Answers:
通常,目标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 responsesToSelector:@selector(myClassWillDoSomething :)){”之类的东西来保护它们。在我的示例中,委托必须实现两种方法。
除了非正式协议,您还可以使用通过@protocol定义的正式协议。如果这样做,则可以将委托设置器的类型和实例变量更改为“ id <MyClassDelegate>
”,而不仅仅是“id
”。
此外,您会注意到未保留该委托。通常这样做是因为“拥有”“ MyClass”实例的对象通常也是委托。如果MyClass保留了其委托,则将存在一个保留周期。在具有MyClass实例并且是其委托以清除该委托引用的类的dealloc方法中,这是一个好主意,因为它是一个弱返回指针。否则,如果使MyClass实例保持活动状态,则将有一个悬空指针。
为了完整起见,由于StackOverflow 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);
}];
这是一个示例,它使委托的概念保持不变,并且仅进行原始回叫。
@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:]将是异步的,这将使回调比此处有用。
为了使这个问题保持最新,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语法。
+ (void)sayHi:(void(^)(NSString *reply))callback;
不是+ (void)sayHi:(void(^)(NSString *))callback;
- (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName;
(注意parameterTypes
不是parameters
)
回调:目标C中有4种回调类型
选择器类型:您可以看到NSTimer,UIPangesture是选择器回调的示例。用于非常有限的代码执行。
代表类型:常见,在Apple框架中最常用。UITableViewDelegate,NSNURLConnectionDelegate。它们通常用于显示从服务器异步下载许多图像等。
如果有其他答案,请让我。我会很感激的。