@implementation ThisObject -(void)start { SomeOtherObject *someOtherObject = [SomeOtherObject alloc]; [someOtherObject doSomethingAndCallThisFunctionWhenUrDone:myCallBackFunction :self]; } -(void)myCallBackFunction { // :) }
Basically, how can I make this work?
Function pointers in C can be used to create function calls to which they point. This allows programmers to pass them to functions as arguments. Such functions passed as an argument to other functions are also called callback functions.
Objective-C allows you to have pointer on a pointer and so on. Passing an argument by reference or by address both enable the passed argument to be changed in the calling function by the called function.
Function Pointer Syntaxvoid (*foo)( int ); In this example, foo is a pointer to a function taking one argument, an integer, and that returns void. It's as if you're declaring a function called "*foo", which takes an int and returns void; now, if *foo is a function, then foo must be a pointer to a function.
The call by reference method of passing arguments to a function copies the address of an argument into the formal parameter. Inside the function, the address is used to access the actual argument used in the call.
There are four ways to make a callback:
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]; }
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)]; }
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]; }
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With