I'm using https://github.com/nodejs/http-parser, the callbacks it uses are like this
struct http_parser_settings {
http_cb on_message_begin;
http_data_cb on_url;
http_data_cb on_status;
http_data_cb on_header_field;
http_data_cb on_header_value;
http_cb on_headers_complete;
http_data_cb on_body;
http_cb on_message_complete;
/* When on_chunk_header is called, the current chunk length is stored
* in parser->content_length.
*/
http_cb on_chunk_header;
http_cb on_chunk_complete;
};
The main callback type is defined here
typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
I'm trying to find a way to pass either an Objective-C block or method as the function pointer in the parser_settings. However it lets me use only a C-function, which doesn't suit me because I also need to access the state of an Objective-C object in the callback
At the moment my solution is as follows:
int onHeaderField(http_parser* _, const char* at, size_t length) {
// Need to access state here, so doesn't work for me as a c function
char header[length];
strncpy(header, at, length);
NSLog(#"Header %s", header);
return 0;
}
...
- (void)method {
http_parser_settings settings;
settings.on_header_field = onHeaderField; // rather than func would like to set a block/method to capture and access self
size_t nparsed = http_parser_execute(self.parser, &parserSettings, charData, messageLength)
}
How would I go about accessing self from the callback passed to http_parser_execute?
Technically you can "extract" an Objective-C method implementation in form of a C-pointer with use of class_getMethodImplementation, however these implementations have objc_msgSend-like signature and always require the receiver as an argument, thus not really usable outside of Objective-C world:
NSString *str = #"Hollow World";
SEL sel = #selector(isEqualToString:);
Method meth = class_getInstanceMethod([str class], sel);
typedef BOOL(*IsEqualToStringPtr)(NSString *, SEL, NSString *);
IsEqualToStringPtr impl = (IsEqualToStringPtr)method_getImplementation(meth);
NSLog(#"Is equal? %#", impl(str, sel, #"Hello, World!") ? #"YES" : #"NO"); // prints "NO"
NSLog(#"Is equal? %#", impl(str, sel, #"Hollow World") ? #"YES" : #"NO"); // prints "YES"
Having that said, neither blocks nor Objective-C methods are directly convertible to a C function pointer (they are pointers to structures under the hood), especially when you want to complement it with any kind of context/state.
The simplest thing you can do is to use a global/statically allocated block variable which can be accessed from a C function without altering it's signature:
static int(^StaticBlock)(http_parser *parser, const char *at, size_t length);
static int my_callback(http_parser *parser, const char *at, size_t length) {
return StaticBlock(parser, at, length);
}
...
- (void)someObjectiveCMethod {
__weak typeof(self) weakSelf = self;
StaticBlock = ^(http_parser *parser, const char *at, size_t length) {
if (!weakSelf) {
return -1;
}
__strong typeof(weakSelf) strongSelf = weakSelf;
strongSelf.mprpty += length;
NSLog(#"Hello from Objective-C");
return 8;
};
http_parser_settings settings;
settings.on_header_field = my_callback;
}
The only viable alternative I can think of is using C++ lambdas. However it's still a big challenge when you need to access current state/context, let alone it will require you to switch to Objective-C++. If you are ok with it, first you need to rename your Objective-C file from SomeClass.m into SomeClass.mm. This way you tell Clang that the source code is Objective-C++ now and the compiler should accept a C++ code. Next, if your C library doesn't have C++ guards, you may want to wrap the C includes with extern "C" expression (otherwise linker would not be able to locate C symbols, because C++ mangles them):
extern "C" {
#include <c_header.h>
}
Now the tricky part: lambda expressions return special objects, closures, which can be seamlessly converted to C function pointers only if they don't capture anything from surrounding context. In our scenario it's not the case and it will require extra steps to convert it to a C pointer. Add this code somewhere in your *.mm file:
template<typename L>
struct c_functor_factory : c_functor_factory<decltype(&L::operator())> {};
template<typename R, typename F, typename ...Args>
struct c_functor_factory<R(F::*)(Args...) const> {
using pointer = typename std::add_pointer<R(Args...)>::type;
static pointer make_cptr(F&& func) {
static F instance = std::forward<F>(func);
return [](Args... args) {
return instance(std::forward<Args>(args)...);
};
}
};
template<typename L>
inline static typename c_functor_factory<L>::pointer make_cptr(L&& lambda) {
return c_functor_factory<L>::make_cptr(std::forward<L>(lambda));
}
In fact this solution is not much far from the global C function solution I suggested above. When a closure is passed as an argument here, this template function just perfect-forwards it to a statically allocated variable. As a result the static closure can be called from a capture-less lambda, which in turn is converted to a C function pointer.
Finally, you can make use of C++ lambda expressions and pass them as C function pointers anywhere in your Objective-C code:
- (void)someObjectiveCMethod {
__weak typeof(self) weakSelf = self;
const auto cptr = make_cptr([weakSelf](http_parser *parser, const char *at, size_t length) {
if (!weakSelf) {
return -1;
}
__strong typeof(weakSelf) strongSelf = weakSelf;
strongSelf.num += val;
NSLog(#"Hello from Objective-C++, %s!", at);
return 32;
});
http_parser_settings settings;
settings.on_header_field = my_callback;
}
Unlike the previous one, C++ solution is much more reliable, because each time your code hits the lambda expression, it emits a new closure object. In both cases, however, the function objects have static storage duration, thus make sure you don't pass any strong pointer in the body of it (otherwise it will never be released).
Related
I often find myself creating a "wrapper" block which just serves to execute a number of other blocks, usually with the same type signature.
Say I have 2 blocks with the same type signature:
MyBlockT block1 = ^(NSString *string, id object) {
//1 does some work
};
MyBlockT block2 = ^(NSString *string, id object) {
//2 does some other work
};
Is there some way to implement the magic function Combine() which would take 2 blocks:
MyBlockT combinedBlock = Combine(block1, block2); //hypothetical function
and be equivalent to doing:
MyBlockT combinedBlock = ^(NSString *string, id object) {
block1(string, object);
block2(string, object);
};
I know this only makes sense with blocks that return void, but that's all I'm interested in.
The Combine function needs only take in 2 blocks, if I have more I can just chain them. I'm at wits end on how to go about implementing this or whether it's even possible.
P.S. I wouldn't mind if the solution involved C macros
EDIT
I'd like to be able to use the resulting block as a method argument, e.g.:
[UIView animateWithDuration:1 animations:someCombinedBlock];
Is this what you are looking for?
MyBlockT CombineBlocks(MyBlockT block1, MyBlockT block2)
{
return [^(NSString *string, id object) {
block1(string, object);
block2(string, object);
} copy];
}
The function creates a new block that calls the two given blocks sequentially.
Now up on GitHub, WoolBlockInvocation!
This is a pair of classes, WSSBlockInvocation and WSSBlockSignature, along with some supporting code, that leverage libffi and the ObjC #encode strings which the compiler generates for Blocks to allow you to invoke a whole list of Blocks with the same set of arguments.
Any number of Blocks can be added to an invocation object, provided their signatures -- meaning return type and number and types of arguments -- match. After setting arguments on the invocation object, the Blocks can be invoked in turn, with the return values, if any, stored for later access.
The piece that you're particularly interested in, sewing that list of Blocks up into a single Block, is provided by the invocationBlock method of WSSBlockInvocation.
- (id)invocationBlock
{
return [^void (void * arg1, ...){
[self setRetainsArguments:YES];
va_list args;
va_start(args, arg1);
void * arg = arg1;
NSUInteger numArguments = [blockSignature numberOfArguments];
for( NSUInteger idx = 1; idx < numArguments; idx++ ){
[self setArgument:&arg atIndex:idx];
arg = va_arg(args, void *);
}
va_end(args);
[self invoke];
} copy];
}
This returns a Block that (ab)uses varargs functionality to defer assigning arguments until that encapsulating Block is actually invoked itself. You can thus do the following:
WSSBlockInvocation * invocation = [WSSBlockInvocation invocationWithBlocks:#[animationBlockOne, animationBlockTwo]];
void (^combinedAnimation)(void) = [invocation invocationBlock];
[UIView animateWithDuration:1 animations:combinedAnimation];
Of course, if you're just worried about Blocks for animations, that take no arguments and have no return value, constructing a wrapper Block is trivial:
void (^combinedAnimation)(void) = ^{
animationBlock();
anotherAnimationBlock();
// etc.
};
You only need my code if you need to wrap a set of Blocks and invoke them all with the same set of arguments.
N.B. I have tested this on OS X on x86_64, but not on any other platform. I hope it works on ARM under iOS, but varargs is famously "not portable" and it may not. Caveat compilor, and let me know if something breaks.
Here is a fun abuse of varargs:
id combine(id block, ...)
{
NSMutableArray *blocks = [NSMutableArray array];
//[blocks addObject:block];
va_list objlist;
va_start(objlist, block);
//while((obj = va_arg(ap, id))) { // }
for(id obj = block; obj; obj = va_arg(objlist, id)) {
[blocks addObject:[obj copy]];
}
va_end(objlist);
void (^wrapper)(id,...) = ^(id arg, ...) {
NSMutableArray *args = [NSMutableArray array];
va_list arglist;
va_start(arglist, arg);
for(id x = arg; x; x = va_arg(arglist, id)) {
[args addObject:x];
}
va_end(arglist);
for(void (^blk)() in blocks) {
blk(args);
}
};
return [wrapper copy];
}
int main() {
NSString *fmt = #"-%d-\n%#\n---";
void (^foo)() = combine(^(NSArray *a){ NSLog(fmt, 1, a); },
^(NSArray *a){ NSLog(fmt, 2, a); }, nil);
foo(#"first", #"second", nil);
return 0;
}
You must define each block to accept an NSArray of arguments, and both the combine and resulting block invocation must have at least one argument and end in nil.
If you know the method signature ahead of time, you can work around the NSArray and block arguments restriction by altering the wrapper block appropriately.
Since you don't mind macros
#define combinedBlock(string, object) \
block1((string), (object) ) \
block2((string), (object) )
if you need to perform 2 or more animations simultaneously then RZViewActions is everything you need. Its code looks like almost as animateWithDuration:... calls but with additional features.
If you need to perform ANY blocks simultaneously then you need something like ReactiveCocoa. But I suggest you PromiseKit (simply because it is easier).
I love blocks, and they are very cool.
However, I find that blocks can clutter up my code and make it harder to read without folding all of them up inside Xcode (which I don't like doing).
I like splitting my code into logical methods (selectors) to keep it easier to read, but it appears (on the surface) that this isn't readily possible with frameworks like dispatch, AFNetworking, and several others.
I also don't care for the delegate approach, as that means I cannot name my methods as I would like to, instead relying on what other people think I need.
So, without writing a bunch of glue code like this:
-(void) reloadData {
...
[[EventsManager instance] data:YES async:^(NSArray *events) { [self processEvents:events] }];
...
}
I could instead do something like this:
-(void) reloadData {
...
[[EventsManager instance] data:YES async:createBlock(self, #selector(processEvents:))];
...
}
Which is easier to read (to me).
With the power that we have with objective-c, and it's runtime, this should be possible, no? I haven't seen anything like this out there, though.
I liked your answer from an academic standpoint; +1 and, clearly, you learned something.
From a practical perspective, it seems like an awful lot of added fragility for very little reduction in typing while it also leads to some information loss at the call site.
The advantage of this is that it is exactly explicit:
-(void) reloadData {
...
[[EventsManager instance] data:YES async:^(NSArray *events) { [self processEvents:events] }];
...
}
Reading that, one sees that the asynchronous callback block is required to process the arguments and that the processEvents: method on self will be used to do the actual work.
The expression createBlock(self, #selector(processEvents:)) is a lossy representation of the same; it loses the explicit argumentation of the callback and the mapping between that argumentation and the method being invoked (I often see callback blocks like the above with multiple arguments where there is some lightweight logic and/or argument processing before invoking the method).
Note also that processing a non-varargs call site as a varargs when called is a violation of the C standard and will not work on certain ABIs with certain lists of arguments.
Yes, this is indeed possible, but this solution is ABI-specific (not guaranteed to work on all platforms), and makes extensive use of the information available at run-time about methods.
What we first must do is get information about the method we are wrapping with the block. This is done via NSMethodSignature, which contains information such as:
Number of arguments
Size (in bytes) of each argument
Size of return type
This allows us to wrap (almost) any method with no specific code for that method, thus creating a re-usable function.
Secondly, we need a way to safely dispatch method calls at run-time. We do this via NSInvocation, which grants us the ability to create a dynamic, and safe, method call at run-time.
Thirdly, we need to have a block that can take any number of arguments passed in, and the dispatch that. This is done via C's va_list APIs, and should work for 99% of methods.
Finally, we need to get the return value, and be able to return that from our block. This is the part of the entire operation that is possible to not work, because of weirdness with returning structs and such with the Objective-C runtime.
However, as long as you keep to primitive types and Objective-C objects, this code should work great for you.
A couple of things to note about this implementation:
It is reliant upon undefined behavior with casting of block & function types, however, because of the calling conventions of iOS and Mac, this should not pose any issues (unless your method has a different return type than what the block expects).
It also relies upon undefined behavior with the result of calling va_arg with a type that may not be what is passed - however, since the types are of the same size, this should never be an issue.
Without any further ado, here is an example of the code, followed by the implementation:
#interface MyObj : NSObject
-(void) doSomething;
#end
#implementation MyObj
-(void) doSomething
{
NSLog(#"This is me, doing something! %p", self);
}
-(id) doSomethingWithArgs:(long) arg :(short) arg2{
return [NSString stringWithFormat:#"%ld %d", arg, arg2];
}
#end
int main() {
// try out our selector wrapping
MyObj *obj = [MyObj new];
id (^asBlock)(long, short) = createBlock(obj, #selector(doSomethingWithArgs::));
NSLog(#"%#", asBlock(123456789, 456));
}
/* WARNING, ABI SPECIFIC, BLAH BLAH BLAH NOT PORTABLE! */
static inline void getArgFromListOfSize(va_list *args, void *first, size_t size, size_t align, void *dst, BOOL isFirst) {
// create a map of sizes to types
switch (size) {
// varargs are weird, and are aligned to 32 bit boundaries. We still only copy the size needed, though.
// these cases should cover all 32 bit pointers (iOS), boolean values, and floats too.
case sizeof(uint8_t): {
uint8_t tmp = isFirst ? (uint32_t) first : va_arg(*args, uint32_t);
memcpy(dst, &tmp, size);
break;
}
case sizeof(uint16_t): {
uint16_t tmp = isFirst ? (uint32_t) first : va_arg(*args, uint32_t);
memcpy(dst, &tmp, size);
break;
}
case sizeof(uint32_t): {
uint32_t tmp = isFirst ? (uint32_t) first : va_arg(*args, uint32_t);
memcpy(dst, &tmp, size);
break;
}
// this should cover 64 bit pointers (Mac), and longs, and doubles
case sizeof(uint64_t): {
uint64_t tmp = isFirst ? (uint64_t) first : va_arg(*args, uint64_t);
memcpy(dst, &tmp, size);
break;
}
/* This has to be commented out to work on iOS (as CGSizes are 64 bits)
// common 'other' types (covers CGSize, CGPoint)
case sizeof(CGPoint): {
CGPoint tmp = isFirst ? *(CGPoint *) &first : va_arg(*args, CGPoint);
memcpy(dst, &tmp, size);
break;
}
*/
// CGRects are fairly common on iOS, so we'll include those as well
case sizeof(CGRect): {
CGRect tmp = isFirst ? *(CGRect *) &first : va_arg(*args, CGRect);
memcpy(dst, &tmp, size);
break;
}
default: {
fprintf(stderr, "WARNING! Could not bind parameter of size %zu, unkown type! Going to have problems down the road!", size);
break;
}
}
}
id createBlock(id self, SEL _cmd) {
NSMethodSignature *methodSig = [self methodSignatureForSelector:_cmd];
if (methodSig == nil)
return nil;
return ^(void *arg, ...) {
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSig];
[invocation setTarget:self];
[invocation setSelector:_cmd];
NSUInteger argc = [methodSig numberOfArguments];
va_list args;
va_start(args, arg);
for (int argi = 2; argi < argc; argi++) {
const char *type = [methodSig getArgumentTypeAtIndex:argi];
NSUInteger size;
NSUInteger align;
// get the size
NSGetSizeAndAlignment(type, &size, &align);
// find the right type
void *argument = alloca(size);
getArgFromListOfSize(&args, arg, size, align, argument, argi == 2);
[invocation setArgument:argument atIndex:argi];
}
va_end(args);
[invocation invoke];
// get the return value
if (methodSig.methodReturnLength != 0) {
void *retVal = alloca(methodSig.methodReturnLength);
[invocation getReturnValue:retVal];
return *((void **) retVal);
}
return nil;
};
}
Let me know if you have any issues with this implementation!
This is primarily a curiosity, I'm not really sure what's the practical use of this but here goes.
Since blocks are also Objective-C objects, is it possible to check their type? That is, does it respond to the isKindOfClass: message and how to use that message with respect to blocks?
My naive thought that it's probably like this:
-(void) aMethod {
typedef int (^BlockA)(int x, int y);
id blockVar = ...; // get a block from somewhere
if([blockVar isKindOfClass:BlockA]) {
BlockA blockVarA = blockVar;
int result = blockVarA(1,2);
}
}
The code above probably won't work. But if it is possible to check a block's type, what is the correct way to do it?
Can do, kinda sorta.
But first, let's disambiguate. -[NSObject isKindOfClass:] can tell you it's a block, and that's about it. E.g. I believe this line of code -- ostensibly & unfortunately A BAD IDEA -- will return YES for blocks on present Lion & iOS 5.x:
[myBlock isKindOfClass:NSClassFromString(#"NSBlock")]
That won't help you distinguish the block's function signature.
But it can be done, by snagging the signature from the block's documented internal struct. Code follows for an example OS X command-line app, much of which ripped from Mike Ash's MABlockClosure (great detailed explanation). (UPDATE: Github project CTObjectiveCRuntimeAdditions also apparently provides library code for just this purpose.)
#import <Foundation/Foundation.h>
struct BlockDescriptor {
unsigned long reserved;
unsigned long size;
void *rest[1];
};
struct Block {
void *isa;
int flags;
int reserved;
void *invoke;
struct BlockDescriptor *descriptor;
};
static const char *BlockSig(id blockObj)
{
struct Block *block = (void *)blockObj;
struct BlockDescriptor *descriptor = block->descriptor;
int copyDisposeFlag = 1 << 25;
int signatureFlag = 1 << 30;
assert(block->flags & signatureFlag);
int index = 0;
if(block->flags & copyDisposeFlag)
index += 2;
return descriptor->rest[index];
}
int main(int argc, const char * argv[])
{
#autoreleasepool {
int (^block)(NSNumber *) = ^(NSNumber *num) {
NSLog(#"%# %#", NSStringFromClass([num class]), num);
return [num intValue];
};
NSLog(#"signature %s", BlockSig(block));
NSLog(#"retval %d", (int)block([NSNumber numberWithInt:42]));
}
return 0;
}
Run this and you should get something like:
[58003:403] signature i16#?0#8
[58003:403] __NSCFNumber 42
[58003:403] retval 42
The numbers in the signature (I'm told they are offsets) can be stripped for simpler i#?#.
The signature is in the #encode format, which isn't perfect (e.g. most objects map to same #), but should afford you some ability to distinguish blocks with different signatures at runtime.
While it's not documented in the Apple link, my testing points to #? being the code for a block type, which makes sense of the signature above. I found a clang-developers discussion on this issue which seems to back this up.
The "BlockA" in (^BlockA) is the variable name (in this case a typedef), not its class.
Blocks are objects, but not regular subclasses of NSObject. They only implement a subset of the methods. -isKindOfClass: will probably just crash.
Blocks are of the type NSMallocBlock or NSConcreteGlobalBlock, ... depending on where they were created (heap, stack, ...).
It seems that blocks are of classes like __NSGlobalBlock__, __NSStackBlock__, or __NSMallocBlock__, etc., whose inheritance chain eventually goes to NSBlock and then NSObject. So you could test whether something is a block by doing [... isKindOfClass:NSClassFromString(#"NSBlock")]. However, there doesn't seem to be any way to query a block's signature (return type and argument types) at runtime, so you wouldn't be able to distinguish between blocks of different signatures.
As well as Apple having nothing I can find to say on the matter, poking at a block with class_copyMethodList and method_getName reveals no obvious exposed methods. So I'm going to say that it isn't possible to check their type.
A old question, but anyway:
If you want a simple way of doing this: (Compile it with -fno-objc-arc)
Class __NSGlobalBlock__CLASS () {
static Class result = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dispatch_block_t thisIsAGlobalBlock = ^{// a block with no variables will be a __NSGlobalBlock__
};
result = [[thisIsAGlobalBlock class] retain];
});
return result;
};
Class __NSStackBlock__CLASS () {
static Class result = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
__block dispatch_block_t thisIsAStackBlock = ^{
return ;// we really DON'T want infinate recursion
thisIsAStackBlock();// including a reference to __block var makes this a __NSStackBlock__
};
result = [[thisIsAStackBlock class] retain];
});
return result;
};
Class __NSMallocBlock__CLASS () {
static Class result = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
__block dispatch_block_t thisIsAMallocBlock = Block_copy(// << turns the __NSStackBlock__ Block into a __NSMallocBlock__
^{
return ;// we really DON'T want infinate recursion
thisIsAMallocBlock();// including a reference to __block var makes this a __NSStackBlock__
});
result = [[thisIsAMallocBlock class] retain];
Block_release(thisIsAMallocBlock);
});
return result;
};
Test Code:
#autoreleasepool {
__block dispatch_block_t iAmAGlobalBlock = ^{
};
__block dispatch_block_t iAmAStackBlock = ^{
return;
iAmAStackBlock();
};
dispatch_block_t iAmHeapBlock = Block_copy(iAmAStackBlock);
dispatch_block_t iAmNotAHeapBlock = Block_copy(iAmAGlobalBlock);
if ([iAmAGlobalBlock isKindOfClass:__NSGlobalBlock__CLASS()]) {
NSLog(#"very great success!");
}
if ([iAmAStackBlock isKindOfClass:__NSStackBlock__CLASS()]) {
NSLog(#"another great success!");
}
if ([iAmHeapBlock isKindOfClass:__NSMallocBlock__CLASS()]) {
NSLog(#"also great success!");
}
if ([iAmNotAHeapBlock isKindOfClass:__NSGlobalBlock__CLASS()]) {
NSLog(#"yet another great success!");
}
NSLog (#"Block classes, as reported by NSStringFromClass():\n__NSGlobalBlock__CLASS() = %#\n__NSStackBlock__CLASS() = %#\n__NSMallocBlock__CLASS() = %#\n[iAmAGlobalBlock class] = %#\n[iAmAStackBlock class] = %#\n[iAmHeapBlock class] = %#\n[iAmNotAHeapBlock class] = %#\n",
NSStringFromClass(__NSGlobalBlock__CLASS()),
NSStringFromClass(__NSStackBlock__CLASS()),
NSStringFromClass(__NSMallocBlock__CLASS()),
NSStringFromClass([iAmAGlobalBlock class]),
NSStringFromClass([iAmAStackBlock class]),
NSStringFromClass([iAmHeapBlock class]),
NSStringFromClass([iAmNotAHeapBlock class])
);
Block_release(iAmHeapBlock);
Block_release(iAmNotAHeapBlock);// not really needed, but since we did "Block_copy" it...
}
How to assign and subsequently call a function that returns a function to a local variable in Objective-C?
UPDATE:
I've come up with the following but it's still not right I'm afraid:
(void (^)()) (^loadedCallback) () = (void (^)()) ^(){
#synchronized (synchronizer) {
semaphore++;
}
return Block_copy(^{
#synchronized (synchronizer) {
semaphore--;
if (semaphore == 0) {
onAllLoaded();
}
}
}); };
First, you need to understand the function pointer declaration syntax. It's the same for blocks, except that it's a ^ instead of a *.
Then, you need to create a block and return a copy of it, and assign that to a correctly-declared variable.
typedef NSArray* (^my_block_type_t)(int, float);
my_block_type_t createBlock()
{
my_block_type_t block = ^(int a, float b)
{
return [NSArray array];
};
return Block_copy(block);
}
/* snip */
my_block_type_t theBlock = createBlock();
theBlock();
Block_release(theBlock);
EDIT to address OP's edit: typedefs are typically used to make code easier to read. In the case of blocks and function pointers, it also makes it easier to write. There is a built-in typedef (dispatch_block_t) for blocks that accept no arguments and return void; you should use it. You should also make as many typedefs as you need to avoid having to use the ugly declaration syntax function pointers otherwise force onto your code.
typedef dispatch_block_t (^block_creator_t)();
block_creator_t loadedCallback = ^{
#synchronized (synchronizer)
{
semaphore++;
}
dispatch_block_t result = ^{
#synchronized (synchronizer)
{
semaphore--;
if (semaphore == 0)
onAllLoaded();
}
};
return Block_copy(result);
};
I have an array of pointers to Objective-C objects. These objects have a sort key associated with them. I'm trying to use qsort to sort the array of pointers to these objects. However, the first time my comparator is called, the first argument points to the first element in my array, but the second argument points to garbage, giving me an EXC_BAD_ACCESS when I try to access its sort key.
Here is my code (paraphrased):
- (void)foo:(int)numThingies {
Thingie **array;
array = malloc(sizeof(deck[0])*numThingies);
for(int i = 0; i < numThingies; i++) {
array[i] = [[Thingie alloc] initWithSortKey:(float)random()/RAND_MAX];
}
qsort(array[0], numThingies, sizeof(array[0]), thingieCmp);
}
int thingieCmp(const void *a, const void *b) {
const Thingie *ia = (const Thingie *)a;
const Thingie *ib = (const Thingie *)b;
if (ia.sortKey > ib.sortKey) return 1; //ib point to garbage, so ib.sortKey produces the EXC_BAD_ACCESS
else return -1;
}
Any ideas why this is happening?
The problem is two fold:
the first argument to qsort needs to be a pointer to the beginning of the array
the arguments passed to your sort function are actually pointers to the pointers of your data
Consider this working code:
int thingieCmp(const void *a, const void *b) {
NSObject *aO = *(NSObject **)a;
NSObject *bO = *(NSObject **)b;
if (aO.hash > bO.hash) return 1;
else return -1;
}
int main (int argc, const char * argv[]) {
NSObject **array;
array = malloc(sizeof(NSObject*)*20);
for(int i = 0; i < 20; i++) {
array[i] = [NSObject new];
}
qsort(array, 20, sizeof(NSObject*), thingieCmp);
return 0;
}
Note that the comparison function resolves the data pointers by NSObject *aO = *(NSObject **)a and the qsort function takes array as an argument directly.
All of this, though, begs the question of Why bother?
NSArray is very good at holding arrays of objects and is quite conveniently sortable. Performance is excellent in the general case. If performance analysis indicates that it isn't, you can optimize it away relatively easily.
Note, also, that I have been consistent in use of sizeof() -- same type in both places. Also, the const in your original code is not necessary.
I think, one mistake lies right in the line
qsort(array[0], numThingies, sizeof(array[0]), thingieCmp);
Try
qsort(&array[0], numThingies, sizeof(array[0]), thingieCmp);
or even
qsort(array, numThingies, sizeof(array[0]), thingieCmp);
instead. The compiler won't complain here, as qsort is supposed to take a void* and you pass it a Thingy* which can legally be cast to void* without warning, but you really want qsort to operate on the entire array, which has type Thingy**.
Another thing is: the comparator will be called with pointers to the array slots as arguments, so what you get is actually a Thingy**:
int
thingieCmp(void* a, void* b)
{
Thingie *ia = *((Thingie**)a);
Thingie *ib = *((Thingie**)b);
...
}