Swift中最优传递实例方法作为参数的方案(批量调用场景)
问题描述
假设我有一个实现了FooObserver协议的对象数组,协议定义如下:
protocol FooObserver{ func didDoIt(description: String) func didNotDoIt(description: String) } class Item: FooObserver{ func didDoIt(description: String){ print(description) } func didNotDoIt(description: String){ print("uh oh") } } let myArray = [Item(), Item(), Item(), Item()]
我想让数组中每个对象调用didDoIt或didNotDoIt方法,不想逐个遍历重复编写代码,希望遵循DRY原则,写一个接收实例方法标识的函数来批量调用。我知道可以用Selector实现,但不确定具体操作,也不想给实例方法加@objc标记,同时想了解有没有其他方案。
注:我关注的是实例方法引用的函数式处理,而非一对多委托或Swift内置的发布订阅机制。
方案1:方法引用函数式实现(推荐)
Swift支持直接将协议的实例方法作为闭包传递,我们可以定义一个接收(FooObserver, String) -> Void类型参数的函数,直接传入协议方法即可批量调用:
func callInstanceMethodForAllItems(_ method: (FooObserver, String) -> Void, with argument: String) { myArray.forEach { observer in method(observer, argument) } }
调用方式简洁直观,完全类型安全且无需@objc标记:
// 调用didDoIt方法 callInstanceMethodForAllItems(FooObserver.didDoIt, with: "we did it") // 调用didNotDoIt方法 callInstanceMethodForAllItems(FooObserver.didNotDoIt, with: "something went wrong")
方案2:扩展Array优化调用体验
如果想让调用更自然,可以给Array写一个限定元素类型的扩展:
extension Array where Element: FooObserver { func invoke(_ method: (Element, String) -> Void, with argument: String) { forEach { method($0, argument) } } }
调用时直接通过数组对象调用方法:
myArray.invoke(FooObserver.didDoIt, with: "we did it") myArray.invoke(FooObserver.didNotDoIt, with: "oops")
方案3:Selector实现(不推荐,仅作参考)
如果一定要用Selector,必须给协议和方法添加@objc标记,同时要处理类型转换:
@objc protocol FooObserver{ @objc func didDoIt(description: String) @objc func didNotDoIt(description: String) } class Item: FooObserver{ func didDoIt(description: String){ print(description) } func didNotDoIt(description: String){ print("uh oh") } } func callInstanceMethodForAllItems(selector: Selector, arg: String){ for o in myArray{ (o as NSObject).perform(selector, with: arg) } } // 注意方法名拼写,原代码中didDoit是错误写法 callInstanceMethodForAllItems(selector: #selector(FooObserver.didDoIt(description:)), arg: "we did it")
这种方式依赖Objective-C运行时,失去Swift类型安全性,不符合你的核心需求,仅作场景补充。
内容的提问来源于stack exchange,提问作者samfr
相关产品推荐
相关产品推荐

