加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

Swift函数作为类中的参数

发布时间:2020-12-14 02:24:23 所属栏目:百科 来源:网络整理
导读:我是一个快速的初学者,所以要温柔…… 我将函数指定为参数时遇到问题. 我已经定义了这个结构: struct dispatchItem { let description: String let f: ()-Void init(description: String,f: @escaping ()-()) { self.description = description self.f = f
我是一个快速的初学者,所以要温柔……

我将函数指定为参数时遇到问题.

我已经定义了这个结构:

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

所以我有点卡住了.

对不起,如果这是一个愚蠢的问题.谢谢你的帮助.

问题是,在self完全初始化之前,您尝试在实例属性的初始化器中引用实例方法testStaticTable和testEditableTable.因此,编译器不能将self作为隐式参数部分地应用于这些方法,而是只能将 offer you the curried versions – 类型(MasterDispatchController) – > () – > ().

然后可能有人试图将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设为私有属性),则应该这样做一).

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读