可以使用块来代替代表吗?

时间:2015-10-04 11:47:38

标签: ios iphone delegates objective-c-blocks

我想编写一个自定义委托方法,以从另一个视图控制器接收我的一个视图控制器中的事件。我应该在这里使用块而不是代表。哪个是首选的?

@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

1 个答案:

答案 0 :(得分:6)

在大多数情况下,如果您的委托方法数量非常少(理想情况下只有1),那么块可能是一个很好的替代方法。如果您有多个委托方法,那么块可能会变得很笨拙。

UITableViewUITableViewDelegateUITableViewDataSource之间有几十种委托方法。使用块配置它会很笨拙并且使代码重用非常困难。如果作为代表的特定方式&#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;变得疯狂,块不再是一个好的解决方案。回到代表们,他们做得非常好。