30
@implementation ThisObject

-(void)start {

       SomeOtherObject *someOtherObject = [SomeOtherObject alloc];

       [someOtherObject doSomethingAndCallThisFunctionWhenUrDone:myCallBackFunction :self];

}

-(void)myCallBackFunction {

       // :)

}

Basically, how can I make this work?

Matthew Scharley
  • 127,823
  • 52
  • 194
  • 222
Joe
  • 301
  • 1
  • 4
  • 5
  • But what is the SomeOtherObject's side of this? What needs to be declared in SomeOtherObject and what does it need to do? It has to have a doSomethingAndCallThisFunctionWhenUrDone. But what does it actually have to do to call said method for object ThisObject? BTW thx a million so far. – Joe Aug 07 '11 at 12:29
  • I expanded my answer to show some more implementation details. For function pointers and blocks you don't need an object to call them, but you can pass objects in as arguments. – rbrown Aug 08 '11 at 17:39

3 Answers3

64

There are four ways to make a callback:

  1. Function Pointer You can do a function pointer if you really want, but it's not recommended. It's done the same way you would do it in C. The problem is you can't use a function pointer to an Objective-C method. It looks something like this:

    void callback(/* Some args */) {
        // Some callback.
    }
    
    - (void)doSomethingAndCallThisFunctionWhenDone:(void(*)(/* Some args */))func {
    
        // Do something.
    
        if (func)
            func(/* Some args */);
    }
    
    - (void)start {
        [self doSomethingAndCallThisFunctionWhenDone:&callback];
    }
    
  2. Selectors You can use -performSelector:. It looks like this:

    - (void)doSomethingAndCallTarget:(id)target withSelector:(SEL)sel {
    
        // Do something.
    
        [target performSelector:sel];
    }
    
    - (void)start {
    
        SomeOtherObject * someOtherObject = [[SomeOtherObject alloc] init];
    
        [self doSomethingAndCallTarget:someOtherObject withSelector:@selector(MyCallback)];
    }
    
  3. Delegates Use a delegate. This is similar to UITableViewDelegate/UITableViewDataSource. See the Apple docs here. You might do it like this:

    - (void)doSomethingDelegate:(id<MyCallbackObject>)delegate {
    
        [delegate retain];
    
        // Do something.
    
        [delegate performMyCallback];  // -performMyCallback must be declared in the MyCallbackObject protocol and implemented by SomeOtherObject.
    
        [delegate release];
    }
    
    - (void)start {
    
        id<MyCallbackObject> someOtherObject = [[SomeOtherObject alloc] init];
    
        [self doSomethingDelegate:someOtherObject];
    
        [someOtherObject release];
    }
    
  4. Blocks The preferred way for callbacks is to use blocks. They are only available for iOS 4.0+ or Mac OS X 10.6+. It looks something like this:

    - (void)doSomethingAndCallThisBlockWhenDone:(void(^)(/* Some args */))block {
    
        [block copy];
    
        // Do something.
    
        if (block)
            block(/* Some args */);
    
        [block release];
    }
    
    - (void)start {
        [self doSomethingAndCallThisBlockWhenDone:^void(/* Some args */){   // Return type and arguments may be omitted if you don't have any.
            // Your callback
        }];
    }
    

As you can see with the block, it's easier to read and your callback is inline with your code. This is especially nice so you don't have to hunt it down. There are many more benefits of blocks, but I couldn't possibly cover them all here.

One last thing, if you use a block, you will want to use a typedef so you don't have to type obscure block types like void(^)(/* Some args */) all the time. The typedef could look like this:

typdef void(^MyCallback)(/* Some args */);

Then, you can declare your method like this:

- (void)doSomethingAndCallThisBlockWhenDone:(MyCallback)block;

Update:

I have shown more detail of how to implement the different techniques (see above).

rbrown
  • 2,635
  • 2
  • 24
  • 24
  • 2
    +1 nice comprehensive answer. Remember that if you need the block to persist on a different thread or beyond the current turn of the runloop, it needs to be copied to the heap (or you compile with ARC and it does The Right Thing™) – Dave DeLong Aug 08 '11 at 18:04
3

Are you talking about this?

-(void)callSomePassedSelector:(SEL)callbackSelector {
    [someObjectThatRespondesToThisSelector performSelector:callbackSelector];
}

I assume you want to store it and call it later, but this should give you all the needed information about how to pass and call it. There are other methods to invoke the selector, see more here

MByD
  • 135,866
  • 28
  • 264
  • 277
0

im a bit confused about what you talking about but is this it?

[self performSelector:@selector(myCallFunction)];
Jacob
  • 1,459
  • 2
  • 19
  • 32