You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 08:27:12