如何在 Objective-C 中执行回调

Posted

技术标签:

【中文标题】如何在 Objective-C 中执行回调【英文标题】:How to perform Callbacks in Objective-C 【发布时间】:2010-11-04 04:13:29 【问题描述】:

函数?

我只是想看看一些完整的例子,我应该理解它。

【问题讨论】:

【参考方案1】:

为了完整起见,由于 *** RSS 只是随机地为我复活了这个问题,另一个(较新的)选项是使用块:

@interface MyClass: NSObject

    void (^_completionHandler)(int someParameter);


- (void) doSomethingWithCompletionHandler:(void(^)(int))handler;
@end


@implementation MyClass

- (void) doSomethingWithCompletionHandler:(void(^)(int))handler

    // NOTE: copying is very important if you'll call the callback asynchronously,
    // even with garbage collection!
    _completionHandler = [handler copy];

    // Do stuff, possibly asynchronously...
    int result = 5 + 3;

    // Call completion handler.
    _completionHandler(result);

    // Clean up.
    [_completionHandler release];
    _completionHandler = nil;


@end

...

MyClass *foo = [[MyClass alloc] init];
int x = 2;
[foo doSomethingWithCompletionHandler:^(int result)
    // Prints 10
    NSLog(@"%i", x + result);
];

【讨论】:

@Ahruman:“void (^_completionHandler)(int someParameter);”中的“^”字符是什么意思?意思是?你能解释一下那条线的作用吗? 您能否解释一下为什么需要复制回调处理程序?【参考方案2】:

通常,目标 C 中的回调是通过委托完成的。这是一个自定义委托实现的示例;


头文件:

@interface MyClass : NSObject 
    id delegate;

- (void)setDelegate:(id)delegate;
- (void)doSomething;
@end

@interface NSObject(MyDelegateMethods)
- (void)myClassWillDoSomething:(MyClass *)myClass;
- (void)myClassDidDoSomething:(MyClass *)myClass;
@end

实施 (.m) 文件

@implementation MyClass
- (void)setDelegate:(id)aDelegate 
    delegate = aDelegate; /// Not retained


- (void)doSomething 
    [delegate myClassWillDoSomething:self];
    /* DO SOMETHING */
    [delegate myClassDidDoSomething:self];

@end

这说明了一般方法。您在 NSObject 上创建一个类别,声明您的回调方法的名称。 NSObject 实际上并没有实现这些方法。这种类型的类别称为非正式协议,您只是说许多对象可能实现这些方法。它们是一种转发声明选择器类型签名的方法。

接下来,您有一些对象是“MyClass”的委托,MyClass 会根据需要调用委托上的委托方法。如果您的委托回调是可选的,您通常会在调度站点使用“if ([delegate respondsToSelector:@selector(myClassWillDoSomething:)) ”之类的东西来保护它们。在我的示例中,委托需要实现这两种方法。

您也可以使用通过@protocol 定义的正式协议来代替非正式协议。如果这样做,您需要将委托设置器的类型和实例变量更改为“id <MyClassDelegate>”,而不仅仅是“id”。

此外,您会注意到委托未保留。这通常是因为“拥有”“MyClass”实例的对象通常也是委托。如果 MyClass 保留了它的委托,那么就会有一个保留周期。在具有 MyClass 实例并且是清除该委托引用的委托的类的 dealloc 方法中这是一个好主意,因为它是一个弱反向指针。否则,如果某些东西使 MyClass 实例保持活动状态,您将有一个悬空指针。

【讨论】:

+1 好彻底的答案。锦上添花将是指向更深入的 Apple 代表文档的链接。 :-) 乔恩,非常感谢您的帮助。我真的很感谢你的帮助。对此我很抱歉,但我对答案不太清楚。 Message .m 是一个在 doSomething 函数调用期间将自己设置为委托的类。 doSomething 是用户调用的回调函数吗?因为我的印象是用户调用 doSomething,而您的回调函数是 myClassWillDoSomethingg 和 myClassDidDoSomething。另外,你能告诉我如何创建一个调用回调函数的更高类吗?我是一名 C 程序员,所以我对 Obj-C 环境还不太熟悉。 "Message .m" 只是意味着,在你的 .m 文件中。你会有一个单独的类,我们称之为“Foo”。 Foo 会有一个“MyClass *myClass”变量,在某些时候 Foo 会说“[myClass setDelegate:self]”。在此之后的任何时候,如果包括 foo 在内的任何人在 MyClass 的该实例上调用 doSomethingMethod,则 foo 将调用其 myClassWillDoSomething 和 myClassDidDoSomething 方法。实际上,我还将发布第二个不使用委托的不同示例。 我不认为 .m 代表“消息”。 ***.com/questions/652186/…【参考方案3】:

这里有一个例子,它把委托的概念排除在外,只做一个原始的回调。

@interface Foo : NSObject 

- (void)doSomethingAndNotifyObject:(id)object withSelector:(SEL)selector;
@end

@interface Bar : NSObject 

@end

@implementation Foo
- (void)doSomethingAndNotifyObject:(id)object withSelector:(SEL)selector 
    /* do lots of stuff */
    [object performSelector:selector withObject:self];

@end

@implementation Bar
- (void)aMethod 
    Foo *foo = [[[Foo alloc] init] autorelease];
    [foo doSomethingAndNotifyObject:self withSelector:@selector(fooIsDone:)];


- (void)fooIsDone:(id)sender 
    NSLog(@"Foo Is Done!");

@end

通常,方法 -[Foo doSomethingAndNotifyObject:withSelector:] 将是异步的,这将使回调比这里更有用。

【讨论】:

非常感谢约翰。我了解您在 cmets 之后的第一个回调实现。同样,您的第二个回调实现更简单。两者都很好。 感谢您发布此 Jon,它非常有帮助。我不得不改变 [object performSelectorwithObject:self];到 [object performSelector:selector withObject:self];为了让它正常工作。【参考方案4】:

为了让这个问题保持最新,ios 5.0 引入了ARC 意味着这可以更简洁地使用Blocks 来实现:

@interface Robot: NSObject
+ (void)sayHi:(void(^)(NSString *))callback;
@end

@implementation Robot
+ (void)sayHi:(void(^)(NSString *))callback 
    // Return a message to the callback
    callback(@"Hello to you too!");

@end

[Robot sayHi:^(NSString *reply)
  NSLog(@"%@", reply);
];

如果你忘记了 Objective-C 的 Block 语法,总会有F****ng Block Syntax。

【讨论】:

在@interface 中应该是+ (void)sayHi:(void(^)(NSString *reply))callback; 而不是+ (void)sayHi:(void(^)(NSString *))callback; 不符合上述F****ng Block Syntax:- (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName;(注意parameterTypes不是parameters【参考方案5】:

CallBack:Objective C 中有 4 种类型的回调

    Selector type:可以看到NSTimer、UIPangesture是Selector回调的例子。用于非常有限的代码执行。

    委托类型:在 Apple 框架中常见且最常用。 UITableViewDelegate,NSNURLConnectionDelegate。它们通常用于显示从服务器异步下载许多图像等。

    NSNotifications:NotificationCenter 是 Objective C 的功能之一,用于在事件发生时通知许多接收者。 :块在 Objective C 编程中更常用。这是一个很棒的功能,用于执行代码块。也可以参考教程了解:Blocks tutorial

如果有其他答案,请告诉我。我会很感激的。

【讨论】:

以上是关于如何在 Objective-C 中执行回调的主要内容,如果未能解决你的问题,请参考以下文章

AudioUnit Render 回调中的 Objective-C/Swift 用法

Objective-C 回调处理程序 [关闭]

快速调用objective-c类方法

如何在 Playground 中运行异步回调

如何在Playground中运行异步回调

细数Objective-C中的回调机制