我如何比较闭包/块?
Posted
技术标签:
【中文标题】我如何比较闭包/块?【英文标题】:How can I compare closures/blocks? 【发布时间】:2020-05-16 14:23:40 【问题描述】:鉴于应用程序使用的 ObjC 中的这段代码,我想将其转换为 Swift:
typedef void (^VoidBlock)(void);
@interface Worker : NSObject
- (void)add:(VoidBlock)completion;
- (void)remove:(VoidBlock)completion;
- (void)execute;
@end
@implementation Worker
NSMutableArray<VoidBlock> *completions;
- (void)add:(VoidBlock)completion
[completions addObject:completion];
- (void)remove:(VoidBlock)completion
[completions removeObject:completion];
- (void)execute
// ...
[completions enumerateObjectsUsingBlock:^(VoidBlock _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop)
obj();
];
@end
我在实施移除时遇到问题。我尝试了几件事,但没有。基本上,我无法比较 Swift 中的闭包,因为显然闭包不符合 Equatable 协议,因此无法在数组中找到它。或许内存地址可以用来做这个,不知道是不是objc指针和swift引用有问题。理论上,这段代码可以从 objc 或 swift 中使用。我的另一个想法是使用类似的东西:
let firstIndex = hardWorkers.firstIndex(where:
$0 === hardWorkerClosure
)
请注意身份运算符,但这不起作用。一位朋友告诉我,也许我必须使用容器来关闭/阻塞。我记得在 Objc 中,我们有 NSValue 将原始类型包装在一个类中,因此,我们可以将它们保存在 NSMutableArray 中,但我不记得有任何保存块的东西。您对如何解决此问题有任何想法或建议吗?非常感谢。
【问题讨论】:
您能否展示一下您从 Objective-C 成功转换的 Swift 代码部分? 闭包没有可比性,也没有定义的标识,以便给编译器更多的发挥空间,优化和合并闭包实现。如果您需要将身份与闭包相关联,您需要自己执行此操作:***.com/a/45284442/3141234 这能回答你的问题吗? In Swift 3, what is a way to compare two closures? @Ricardo 在 ObjC 中,块通常由它们的地址处理。您将指向它们的指针传递给 ARC(如果您使用手动内存管理)、复制它们等。在 Swift 中,它们有意不将闭包标识暴露给“用户空间”Swift 代码.动机在这里:***.com/a/25694072/3141234 Swift 闭包也不仅仅是一个指针:forums.swift.org/t/… 【参考方案1】:闭包在 Swift 中没有标识,这意味着您不能使用 === 来确定两个闭包是否指向相同的代码。如果你真的需要这个,一种解决方案是在闭包上构建一个抽象:
typealias VoidClosure = () -> Void
class VoidClosureRef
let body: VoidClosure
init(_ body: @escaping VoidClosure)
self.body = body
然后您可以传播VoidClosureRef
的实例:
class Worker
private var completions: [VoidClosureRef] = []
func add(_ completion: VoidClosureRef)
completions.append(completion)
func remove(_ completion: VoidClosureRef)
completions.removeAll $0 === completion
但是,这里更好的设计是add
方法返回一个标识符,该标识符以后可用于移除闭包。
typealias VoidClosure = () -> Void
class Worker
private var completions: [UUID: VoidClosure] = [:]
func add(_ completion: @escaping VoidClosure) -> UUID
let uuid = UUID()
completions[uuid] = completion
return uuid
func remove(_ uuid: UUID)
completions.removeValue(forKey: uuid)
【讨论】:
以上是关于我如何比较闭包/块?的主要内容,如果未能解决你的问题,请参考以下文章