gpt4 book ai didi

objective-c - 如何用 Block 简化回调逻辑?

转载 作者:太空狗 更新时间:2023-10-30 03:08:49 24 4
gpt4 key购买 nike

假设我需要与一个提供协议(protocol)并在操作完成时调用委托(delegate)方法的类进行通信,如下所示:

@protocol SomeObjectDelegate

@required
- (void)stuffDone:(id)anObject;
- (void)stuffFailed;

@end

@interface SomeObject : NSObject
{
}
@end

现在,我决定虽然我可以让另一个类实现 stuffDone: 委托(delegate)方法,但我决定宁愿将该过程封装到一个 block ,写在靠近 SomeObject 被实例化、调用等的地方。我该怎么做?或者换句话说,如果您查看 this关于 block 的著名文章(在替换回调部分);我如何在 SomeObject 中编写一个接受各种 completionHandler: 的方法?

最佳答案

听起来您希望与设计为采用委托(delegate)对象的现有类进行通信。有多种方法,包括:

  1. 使用类别添加适当方法的基于 block 的变体;
  2. 使用派生类添加基于 block 的变体;和
  3. 编写一个实现协议(protocol)并调用您的 block 的类。

这是执行 (3) 的一种方法。首先让我们假设您的 SomeObject 是:

@protocol SomeObjectDelegate
@required
- (void)stuffDone:(id)anObject;
- (void)stuffFailed;

@end

@interface SomeObject : NSObject
{
}

+ (void) testCallback:(id<SomeObjectDelegate>)delegate;

@end

@implementation SomeObject

+ (void) testCallback:(id<SomeObjectDelegate>)delegate
{
[delegate stuffDone:[NSNumber numberWithInt:42]];
[delegate stuffFailed];
}

@end

所以我们有一些测试方法 - 您将拥有一个真正的 SomeObject。

现在定义一个实现协议(protocol)并调用您提供的 block 的类:

#import "SomeObject.h"

typedef void (^StuffDoneBlock)(id anObject);
typedef void (^StuffFailedBlock)();

@interface SomeObjectBlockDelegate : NSObject<SomeObjectDelegate>
{
StuffDoneBlock stuffDoneCallback;
StuffFailedBlock stuffFailedCallback;
}

- (id) initWithOnDone:(StuffDoneBlock)done andOnFail:(StuffFailedBlock)fail;
- (void)dealloc;

+ (SomeObjectBlockDelegate *) someObjectBlockDelegateWithOnDone:(StuffDoneBlock)done andOnFail:(StuffFailedBlock)fail;

// protocol
- (void)stuffDone:(id)anObject;
- (void)stuffFailed;

@end

此类保存您传入的 block 并调用它们以响应协议(protocol)回调。实现很简单:

@implementation SomeObjectBlockDelegate

- (id) initWithOnDone:(StuffDoneBlock)done andOnFail:(StuffFailedBlock)fail
{
if (self = [super init])
{
// copy blocks onto heap
stuffDoneCallback = Block_copy(done);
stuffFailedCallback = Block_copy(fail);
}
return self;
}

- (void)dealloc
{
Block_release(stuffDoneCallback);
Block_release(stuffFailedCallback);
[super dealloc];
}

+ (SomeObjectBlockDelegate *) someObjectBlockDelegateWithOnDone:(StuffDoneBlock)done andOnFail:(StuffFailedBlock)fail
{
return (SomeObjectBlockDelegate *)[[[SomeObjectBlockDelegate alloc] initWithOnDone:done andOnFail:fail] autorelease];
}

// protocol
- (void)stuffDone:(id)anObject
{
stuffDoneCallback(anObject);
}

- (void)stuffFailed
{
stuffFailedCallback();
}

@end

您唯一需要记住的是在初始化时对 block 进行 Block_copy() 并在稍后对它们进行 Block_release() - 这是因为 block 是堆栈分配的,您的对象可能比其创建的堆栈帧更长寿; Block_copy() 在堆中创建一个副本。

现在您可以将所有基于委托(delegate)的方法传递给它 block :

[SomeObject testCallback:[SomeObjectBlockDelegate
someObjectBlockDelegateWithOnDone:^(id anObject) { NSLog(@"Done: %@", anObject); }
andOnFail:^{ NSLog(@"Failed"); }
]
];

您可以使用此技术为任何协议(protocol)包装 block 。

ARC 附录

作为对评论的回应:要使此 ARC 兼容,只需删除对 Block_copy() 的调用,留下直接赋值:

stuffDoneCallback = done;
stuffFailedCallback = fail;

并移除dealloc 方法。您还可以将 Blockcopy 更改为 copy,即 stuffDoneCallback = [done copy];,这就是您可能认为阅读圆弧文档。然而,这并不是因为赋值给强变量导致 ARC 保留赋值 - 并保留堆栈 block 将其复制到堆中。因此,无论有没有 copy,生成的 ARC 代码都会产生相同的结果。

关于objective-c - 如何用 Block 简化回调逻辑?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4824038/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com