Objective-C Block Property with Xcode code completion

Andrew picture Andrew · Feb 3, 2012 · Viewed 17.6k times · Source

Is it possible to define an Objective-C block property but still have full-code completion in Xcode 4?

If I use a typedef to define the block:

typedef void (^CompletionBlock)(MyObject *myObj);

and then define the property:

@property (nonatomic, copy) CompletionBlock completionBlock;

and then @synthesize the property I don't get full code completion when calling the setter. Xcode will use the typedef and because of this, the code completion doesn't use the full block syntax complete with block parameters, it uses the typedef.

If I define a method prototype in the header that uses the full block syntax instead of the typedef:

@property (nonatomic, copy) void (^completionBlock)(MyObject *myObj);

and then I use @synthesize, the provided setter comes close to using the full code completion syntax but crucially it leaves out the parameter names:

[self setCompletionBlock:(void (^)(MyObject *)) { ... }

Finally, if I try to @synthesize and then override the setter implementation or put the prototype in the header:

- (void)setCompletionBlock:(void (^)(MyObject *myObj))completionBlock {...}

A warning is raised stating that the property type does not match the accessor type. No matter how I try to finagle the syntax, I'm not able to both define a block property and a setter that has the full syntax for code completion. Can I have my cake and eat it too?

Thanks!

Answer

Matt picture Matt · Aug 23, 2012

You can definitely have your cake and eat it too, if you are willing to add one extra line of code to your class interface.

First, define block with a typedef and create a property like you did in your question:

typedef void (^CompletionBlock)(MyObject *myObj);

...

@property (nonatomic, copy) CompletionBlock completionBlock;

Next, as MobileOverload pointed out in his answer, we know that Xcode provides correct code completion for typedef'd blocks if used in a standalone method declaration. So, let's add an explicit declaration for the setter of completionBlock:

- (void)setCompletionBlock:(CompletionBlock)completionBlock;

When called, this method resolves to the setter method declared by the property. However, because we explicitly defined it in the class interface, Xcode sees it and applies full code completion.

So, if you include all three of those lines you should get the desired result. This behavior is clearly a shortcoming of Xcode, as there is no reason why a setter defined in a @property statement should have different code completion than the same method defined on its own.