Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective-C type-check a block?

This is different from other "can I check the type of a block" posts on SO, as far as I can tell anyway.

I want to know if, given a block object of unknown signature, I can learn what arguments it accepts prior to invoking?

I have a situation where I have a number of callbacks associated with objects in a dictionary. I want some of those callbacks to expect a different set of arguments. The example here is extremely simplified, but I think it gets the point across.

How can I find out if a block is of a type I previously typedef'd?

//MyClass.m

// I start by declare two block types
typedef void (^callbackWithOneParam)(NSString*);
typedef void (^callbackWithTwoParams)(NSString*, NSObject*);

........

// I create a dictionary mapping objects to callback blocks

self.dict = @{
  @"name": "Foo",
  @"callback": ^(NSString *aString) {
    // do stuff with string
  }
}, {
  @"name": "Bar",
  @"callback": ^(NSString *aString, NSObject *anObject) {
    // do stuff with string AND object
  }
} 

.....

// Later, this method is called.  
// It looks up the "name" parameter in our dictionary, 
// and invokes the associated callback accordingly.

-(void) invokeCallbackForName:(NSString*)name {
   // What is the type of the result of this expression?
   [self.dict objectForKey: name]

   // I want to say: (pseudocode)
   thecallback = [self.dict objectForKey: name];
   if (thecallback is of type "callbackWithOneParam") {
      thecallback(@"some param")
   }
   else if (thecallback is of type "callbackWithTwoParams") {
      thecallback(@"some param", [[NSObject alloc] init]);
   }
}
like image 706
Matt H. Avatar asked Nov 22 '12 11:11

Matt H.


People also ask

What is __ block Objective-C?

__block is a storage qualifier that can be used in two ways: Marks that a variable lives in a storage that is shared between the lexical scope of the original variable and any blocks declared within that scope. And clang will generate a struct to represent this variable, and use this struct by reference(not by value).

What is @property in Objective-C?

The goal of the @property directive is to configure how an object can be exposed. If you intend to use a variable inside the class and do not need to expose it to outside classes, then you do not need to define a property for it. Properties are basically the accessor methods.

What is ID in Obj C?

id is the generic object pointer, an Objective-C type representing "any object". An instance of any Objective-C class can be stored in an id variable.

Why do you generally create a weak reference when using self in a block?

For many of us, it's best practice to always use weak combined with self inside closures to avoid retain cycles. However, this is only needed if self also retains the closure. By adding weak by default you probably end up working with optionals in a lot of cases while it's actually not needed.


2 Answers

Frankly, if the callbacks have different types, they should be under different keys. Why not use the keys @"callbackWithOneParam" and @"callbackWithTwoParams"? To me, that's superior to having a generic "callback" key plus a separate "type" key to tell you how to interpret the callback.

But what this really calls for is to use objects of custom classes instead of dictionaries. You've crossed the boundary where generic objects stop being convenient and start to cause more problems than they solve.

like image 83
Ken Thomases Avatar answered Oct 13 '22 01:10

Ken Thomases


Personally, I use the ingenious CTBlockDescription...

CTBlockDescription lets you inspect blocks including arguments and compile time features at runtime.

BOOL(^bk)(BOOL,id) = ^BOOL(BOOL ani, id obj) { return YES; };

[CTBlockDescription.alloc initWithBlock:bk].blockSignature.description;

<NSMethodSignature: 0x253f080>
    number of arguments = 3
    frame size = 12
    is special struct return? NO
    return value: -------- -------- -------- --------
        type encoding (c) 'c'
        flags {isSigned}
        modifiers {}
        frame {offset = 0, offset adjust = 0, size = 4, size adjust = -3}
        memory {offset = 0, size = 1}
    argument 0: -------- -------- -------- --------
        type encoding (@) '@?'
        flags {isObject, isBlock}
        modifiers {}
        frame {offset = 0, offset adjust = 0, size = 4, size adjust = 0}
        memory {offset = 0, size = 4}
    argument 1: -------- -------- -------- --------
        type encoding (c) 'c'
        flags {isSigned}
        modifiers {}
        frame {offset = 4, offset adjust = 0, size = 4, size adjust = -3}
        memory {offset = 0, size = 1}
    argument 2: -------- -------- -------- --------
        type encoding (@) '@'
        flags {isObject}
        modifiers {}
        frame {offset = 8, offset adjust = 0, size = 4, size adjust = 0}
        memory {offset = 0, size = 4}

Gorgeous...

like image 23
Alex Gray Avatar answered Oct 12 '22 23:10

Alex Gray