Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective-C Block Property with Xcode code completion

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!

like image 312
Andrew Avatar asked Feb 02 '12 23:02

Andrew


People also ask

How do you create a completion block in Objective-C?

Define Block Types - (void) performWithCompletion: (void (^)(BOOL finished)) completionBlock; Alternatively you simplify matters by declaring a custom block type in your class header file. Here's an example that defines a type and then uses it in a method signature identical to the example you just saw.

What is completion block?

The block to execute after the operation's main task is completed.

What is a completion block in Swift?

Swift Closures with Completion handler Closures are self-contained blocks of functionality that can be passed around and used in your code. Said differently, a closure is a block of code that you can assign to a variable. You can then pass it around in your code, for instance to another function. …

What is the use of block in Objective-C?

Blocks are a language-level feature added to C, Objective-C and C++, which allow you to create distinct segments of code that can be passed around to methods or functions as if they were values. Blocks are Objective-C objects, which means they can be added to collections like NSArray or NSDictionary .


2 Answers

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.

like image 96
Matt Avatar answered Oct 10 '22 22:10

Matt


You can get some fancy looking code completion when passing your blocks as an argument to a method in your class. In the header file I typedef'd the block like this

typedef void (^MyCompletionBlock)(id obj1, id obj2);

Then I was able to use it as an argument to my method that I have also declared in this class header.

-(void)doThisWithBlock:(MyCompletionBlock)block;

In the m file I declared the method

-(void)doThisWithBlock:(MyCompletionBlock)block {
    NSLog(@"Something");
}

and when I went to call it I got fancy code completion like this. CodeCompletion1

CodeCompletion2

Hopefully this answers your question.

like image 42
MobileOverlord Avatar answered Oct 10 '22 22:10

MobileOverlord