在Objective C中,什么相当于在C中传递函数指针?

Joe*_*Joe 29 function-pointers objective-c

@implementation ThisObject

-(void)start {

       SomeOtherObject *someOtherObject = [SomeOtherObject alloc];

       [someOtherObject doSomethingAndCallThisFunctionWhenUrDone:myCallBackFunction :self];

}

-(void)myCallBackFunction {

       // :)

}
Run Code Online (Sandbox Code Playgroud)

基本上,我怎样才能做到这一点?

rbr*_*own 60

有四种方法可以进行回调:

  1. 函数指针你可以做一个函数指针,如果你真的想要的,但并不推荐.它的完成方式与在C中执行的方式相同.问题是您不能使用指向Objective-C方法的函数指针.它看起来像这样:

    void callback(/* Some args */) {
        // Some callback.
    }
    
    - (void)doSomethingAndCallThisFunctionWhenDone:(void(*)(/* Some args */))func {
    
        // Do something.
    
        if (func)
            func(/* Some args */);
    }
    
    - (void)start {
        [self doSomethingAndCallThisFunctionWhenDone:&callback];
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 选择器您可以使用-performSelector:.它看起来像这样:

    - (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)];
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 代表使用代表.这类似于UITableViewDelegate/UITableViewDataSource.请在此处查看Apple文档.你可以这样做:

    - (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];
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 回调的首选方法是使用块.它们仅适用于iOS 4.0+或Mac OS X 10.6+.它看起来像这样:

    - (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
        }];
    }
    
    Run Code Online (Sandbox Code Playgroud)

正如您在块中看到的那样,它更容易阅读,并且您的回调与您的代码内联.这特别好,所以你不必追捕它.块有许多好处,但我不可能在这里全部覆盖它们.

最后一件事,如果你使用一个块,你会想要使用一个,typedef所以你不必像往常一样输入模糊的块类型void(^)(/* Some args */).本typedef看起来是这样的:

typdef void(^MyCallback)(/* Some args */);
Run Code Online (Sandbox Code Playgroud)

然后,您可以像这样声明您的方法:

- (void)doSomethingAndCallThisBlockWhenDone:(MyCallback)block;
Run Code Online (Sandbox Code Playgroud)

更新:

我已经展示了如何实现不同技术的更多细节(见上文).

  • +1 很好的综合答案。请记住,如果您需要将块持久化在不同的线程上或超出当前运行循环的轮次,则需要将其复制到堆中(或者您使用 ARC 进行编译并且它执行正确的事情™) (2认同)

MBy*_*ByD 3

你在说这个吗?

-(void)callSomePassedSelector:(SEL)callbackSelector {
    [someObjectThatRespondesToThisSelector performSelector:callbackSelector];
}
Run Code Online (Sandbox Code Playgroud)

我假设您想存储它并稍后调用它,但这应该为您提供有关如何传递和调用它的所有所需信息。还有其他方法可以调用选择器,请参阅此处