我将函数指定为参数时遇到问题.
我已经定义了这个结构:
struct dispatchItem { let description: String let f: ()->Void init(description: String,f: @escaping ()->()) { self.description = description self.f = f } }
我在一个名为MasterdispatchController的类中使用它,如下所示:
class MasterdispatchController: UITableViewController { let dispatchItems = [ dispatchItem(description: "Static Table",f: testStaticTable),dispatchItem(description: "Editable Table",f: testEditableTable) ] func testEditableTable() { //some code } func testStaticTable() { //some code }
等等
然后我在我的代码中有一个表视图,它发送到任何被点击的函数(不仅仅是我在上面的代码中显示的两个,但这不重要)就像这样
override func tableView(_ tableView: UITableView,didSelectRowAt indexPath: IndexPath) { dispatchItems[indexPath.row].f() }
所以…编译器对此并不满意.它说当我定义dispatchItems let语句时:
Cannot convert value of type ‘(MasterdispatchController) -> () -> ()’ to expected argument type ‘() -> ()’
我想……好吧……我不确定我是否完全理解这一点,但似乎编译器想要知道回调函数将来自哪个类.我明白为什么它可能需要它.所以我有点盲目地遵循编译器给我的模式,并将我的结构更改为:
struct dispatchItem { let description: String let f: (MasterdispatchController)->()->Void init(description: String,f: @escaping (MasterdispatchController)->()->()) { self.description = description self.f = f } }
伟大的编译器很高兴,但现在当我尝试使用dispatchItems [indexPath.row] .f()调用该函数时,它说:
Missing parameter #1 in call
该功能没有参数,所以我感到困惑……
我想也许是问我有问题的对象的实例会有一些意义……在我的例子中,这将是“自我”,所以我尝试了dispatchItems [indexPath.row] .f(self)但是后来我得到一个错误:
Expression resolves to an unused function
所以我有点卡住了.
对不起,如果这是一个愚蠢的问题.谢谢你的帮助.
然后可能有人试图将dispatchItems属性标记为lazy
,以便在self完全初始化时,属性初始化程序在属性的第一次访问时运行.
class MasterdispatchController : UITableViewController { lazy private(set) var dispatchItems: [dispatchItem] = [ dispatchItem(description: "Static Table",f: self.testStaticTable),dispatchItem(description: "Editable Table",f: self.testEditableTable) ] // ... }
(注意,我重命名了你的结构符合Swift命名约定)
现在可以编译,因为你现在可以参考方法的部分应用版本(即type() – > Void),并可以将它们称为:
dispatchItems[indexPath.row].f()
但是,你现在有一个保留周期,因为你在自我上存储了强大捕获自我的闭包.这是因为当用作值时,self.someInstanceMethod解析为部分应用的闭包,强烈捕获self.
您已经接近实现的一个解决方案是使用方法的curried版本 – 它们不会强烈捕获self,而是必须应用给定的实例进行操作.
struct dispatchItem<Target> { let description: String let f: (Target) -> () -> Void init(description: String,f: @escaping (Target) -> () -> Void) { self.description = description self.f = f } } class MasterdispatchController : UITableViewController { let dispatchItems = [ dispatchItem(description: "Static Table",f: testEditableTable) ] override func tableView(_ tableView: UITableView,didSelectRowAt indexPath: IndexPath) { dispatchItems[indexPath.row].f(self)() } func testEditableTable() {} func testStaticTable() {} }
这些函数现在将MasterdispatchController的给定实例作为参数,并返回正确的实例方法以调用该给定实例.因此,您需要首先将它们应用于self,通过说f(self)以获取实例方法来调用,然后使用()调用结果函数.
尽管不断地将这些功能应用于自己可能不方便(或者您甚至可能无法访问自己).更通用的解决方案是将自己存储为dispatchItem的弱属性,以及curried函数 – 然后您可以“按需”应用它:
struct dispatchItem<Target : AnyObject> { let description: String private let _action: (Target) -> () -> Void weak var target: Target? init(description: String,target: Target,action: @escaping (Target) -> () -> Void) { self.description = description self._action = action } func action() { // if we still have a reference to the target (it hasn't been deallocated),// get the reference,and pass it into _action,giving us the instance // method to call,which we then do with (). if let target = target { _action(target)() } } } class MasterdispatchController : UITableViewController { // note that we've made the property lazy again so we can access 'self' when // the property is first accessed,after it has been fully initialised. lazy private(set) var dispatchItems: [dispatchItem<MasterdispatchController>] = [ dispatchItem(description: "Static Table",target: self,action: testStaticTable),action: testEditableTable) ] override func tableView(_ tableView: UITableView,didSelectRowAt indexPath: IndexPath) { dispatchItems[indexPath.row].action() } func testEditableTable() {} func testStaticTable() {} }
这可确保您没有保留周期,因为dispatchItem没有对self的强引用.
当然,您可以使用自己的无主引用,如in this Q&A所示.但是,如果您可以保证您的dispatchItem实例不会超过自我(您希望将dispatchItem设为私有属性),则应该这样做一).
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。