Swift函数作为类中的参数
我是一个快速的初学者,所以要温柔……
我将函数指定为参数时遇到问题. 我已经定义了这个结构: 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语句时:
我想……好吧……我不确定我是否完全理解这一点,但似乎编译器想要知道回调函数将来自哪个类.我明白为什么它可能需要它.所以我有点盲目地遵循编译器给我的模式,并将我的结构更改为: 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()调用该函数时,它说:
该功能没有参数,所以我感到困惑…… 我想也许是问我有问题的对象的实例会有一些意义……在我的例子中,这将是“自我”,所以我尝试了dispatchItems [indexPath.row] .f(self)但是后来我得到一个错误:
所以我有点卡住了. 对不起,如果这是一个愚蠢的问题.谢谢你的帮助.
问题是,在self完全初始化之前,您尝试在实例属性的初始化器中引用实例方法testStaticTable和testEditableTable.因此,编译器不能将self作为隐式参数部分地应用于这些方法,而是只能将
offer you the curried versions – 类型(MasterDispatchController) – > () – > ().
然后可能有人试图将dispatchItems属性标记为 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设为私有属性),则应该这样做一). (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |