Gonzalo Larralde
Gonzalo Larralde

Reputation: 3541

Closures definition and usage in Objective-C

I'm trying to write a generic function to start and end events into my Obj-C (iOS) application. I'm defining - (void)startEvent:(void (^)())completion. In the body of this function I take an action that launches an animation. What I need is call to completion when an specific time interval pass.

So, I make a copy of completion and assign it to a global variable (in class scope).

This is how I do this:

void (^startEventCompletionClosure)();

- (void)startEvent:(void (^)())completion {
    // side note: I have NO access to "complete" closure of - [UIView animateWithDuration:...]
    ...
    [self performSelector:@selector(startEventCompleted) withObject:nil afterDelay:kDealy];
    startEventCompletionClosure = [completion copy];
}

- (void)startEventCompleted {
    startEventCompletionClosure();
    [startEventCompletionClosure release];
}

But, I have a few questions:

Upvotes: 0

Views: 2067

Answers (3)

Khrob
Khrob

Reputation: 1269

UIView also has nice block based animation methods now...

animateWithDuration:animations: animateWithDuration:animations:completion: animateWithDuration:delay:options:animations:completion:

[UIView animateWithDuration:kAnimationDurationTime animations:^{
    // animate some animatable properties
    // do some other stuff
  } completion:^(BOOL finished) {
    // code that you want to run
    //  when the animation has finished
}];

I've found this a very useful way to animate things.

Upvotes: 0

NSResponder
NSResponder

Reputation: 16861

First, we call them "blocks", not "closures" in Objective-C. Secondly, -performSelector:withObject:afterDelay: is something we used before we had blocks. These days, you should probably use dispatch_after(). Finally, blocks are objects, and they conform to the NSObject protocol.

Upvotes: 1

mipadi
mipadi

Reputation: 410932

Is this the better way to handle this?

Depending on your usage, you may want to store this as an instance variable (unless you really want the block to be shared between classes, and thus changed for all classes anytime startEvent: is called).

Is a __block an NSObject? a C declaration?

It's a C storage qualifier.

Why do I have to copy it? Is it not possible just to retain it?

You can retain it, but it probably won't do what you want it to do. In C and Objective-C, blocks are created on the stack. When you copy it, it (and any variables it closed over) are copied to the heap. If you retain it, it and its variables are not copied to the heap.

If it's not an Obj-C Object, why I can call to [... copy] and [... retain] as it were?

Magic. :) More seriously, in Objective-C, blocks are designed to act as Objective-C objects. (It's similar to the reason you can seamlessly cast between NSString and CFStringRef -- the objects are designed to make this possible.)

Upvotes: 2

Related Questions