我想编写一个自定义委托方法,以从另一个视图控制器接收我的一个视图控制器中的事件。我应该在这里使用块而不是代表。哪个是首选的?
@protocol MyClassDelegate
-(void)doSomethingInDelegate;
@end
@interface MyClass : NSObject
@property id<MyClassDelegate> delegate;
-(void)doSomething
@end
@implementation MyClass
-(void)doSomething
{
[self.delegate doSomethingInDelegate];
}
@end
@interface MyOtherClass<MyClassDelegate> : NSObject
...
@end
@implementation MyOtherClass
-(void)doSomethingInDelegate
{
NSLog(@"Doing something in delegate");
}
@end
答案 0 :(得分:6)
在大多数情况下,如果您的委托方法数量非常少(理想情况下只有1),那么块可能是一个很好的替代方法。如果您有多个委托方法,那么块可能会变得很笨拙。
UITableView
在UITableViewDelegate
和UITableViewDataSource
之间有几十种委托方法。使用块配置它会很笨拙并且使代码重用非常困难。如果作为代表的特定方式&#34;可能是高度可重用的(如在UITableViewController
中),然后委托是一个更强大的模式。
另一方面,如果你的代表最终只有一个&#34; thisActionFinished:`方法,那么一个委托可能有点过分,而且最好只传递一个块。在许多情况下这是真的,我们过去需要创建许多单方法委托协议,这有点痛苦。块使这种常见模式更容易。
但它并不是授权的通用替代品,而且块有许多与回调无关的其他目的。因此,学习这两种技术非常重要。
根据您的具体示例,有几个错误。让我们以委托和阻止形式进行。
// Since the protocol needs to know about the class, you need to warn the
// compiler that this class exists.
@class MyClass;
// Declare the delegate protocol. Delegate method names should follow this
// pattern with "did", "should", or "will" in their names. Delegate methods
// should always pass the delegating object as the first parameter. A given
// delegate may be delegating for several instances.
@protocol MyClassDelegate
-(void)myClass:(MyClass *)class didSomething:(id)something;
@end
// Declare the class that has a delegate. Notice that `delegate` should be `weak`
// here. In your example, it's `strong`, and that will almost always lead to a
// retain loop. With rare exceptions, delegates are not retained.
@interface MyClass : NSObject
@property (nonatomic, readwrite, weak) id<MyClassDelegate> delegate;
-(void)doSomething;
@end
// Do the thing
@implementation MyClass
-(void)doSomething {
[self.delegate myClass:self didSomething:@"SOMETHING"];
}
@end
// The delegate object almost always has a strong pointer to the thing it delegates
// for. That's why you want the `delegate` property to be weak.
// Note that your syntax was wrong. "MyOtherClass <MyClassDelegate>". That's
// the new generic syntax, not the protocol syntax. Protocols go at the end.
@interface MyOtherClass : NSObject <MyClassDelegate>
@property (nonatomic, readwrite, strong) MyClass *c;
@end
// And the obvious impl
@implementation MyOtherClass
- (instancetype)init {
self = [super init];
if (self) {
self.c = [MyClass new];
self.c.delegate = self;
}
return self;
}
-(void)myClass:(MyClass *)class didSomething:(id)something {
NSLog(@"Doing something in delegate");
}
@end
如果这是一个基于块的API,那就让它们做同样的事情。
// If your callback takes no arguments and returns nothing, then you can
// use dispatch_block_t here. But often you need parameters or return
// something, and for that you should usually make a typealias. Welcome to the
// spiral world of block syntax.
typedef void(^MyClassCallback)(id something);
// Instead of a delegate, we have a callback. We might have several. We might
// have a block that returns the row height. But if you're doing a lot of
// that, just use a delegate. Note that blocks should always be `copy`.
@interface MyClass : NSObject
@property (nonatomic, readwrite, copy) MyClassCallback callback;
-(void)doSomething;
@end
// And here's how you use the block. It's just like a function.
@implementation MyClass
-(void)doSomething {
if (self.callback != nil) {
self.callback(@"SOMETHING");
}
}
@end
// And the delegate.
@interface MyOtherClass : NSObject
@property (nonatomic, readwrite, strong) MyClass *c;
@end
@implementation MyOtherClass
- (instancetype)init {
self = [super init];
if (self) {
self.c = [MyClass new];
// And here's the syntax for creating the block.
self.c.callback = ^(id something) {
NSLog(@"Doing something in delegate");
};
}
return self;
}
@end
请注意,我们在代理中不需要额外的方法来保存一行代码,我们也不需要定义协议。这是转移到轻量级授权块的重要原因。它使相关代码保持紧密。但是当代码变得复杂时,&#34;在一起&#34;变得疯狂,块不再是一个好的解决方案。回到代表们,他们做得非常好。