为什么这个闭包没有我期望的论点?

时间:2017-01-10 09:07:37

标签: swift closures

我有SettingsViewController并创建了一个结构来定义每个设置所需的信息。

///Represents a list of the options needed to populate a `SettingsTableViewCell`
public struct Setting {
    ///The image to use for the icon
    var imageName : String

    ///The text to display as the title of the setting
    var title : String

    ///Called when the switch is tapped. If no closure is supplied, the switch is hidden
    var switchCallback: ((_ status: Bool)->())?
}

视图控制器保留这些设置的数组,以便稍后在表视图中使用。下面提供了一个示例:

let options : [Setting] =
[
    Setting(imageName: "notifications", title: "Bump Notifications") {updateNotificationSetting($0)},
    ...
]

然而,当我尝试编译时,我提出了错误:

Cannot convert value of type '(SettingsViewController) -> (Bool) -> ()' to expected argument type '((Bool) -> ())?'

有人可以解释一下(SettingsViewController)的来源吗?如果可以的话,我需要改变什么才能解决它?

对于SSCCE,请参阅以下内容:

import UIKit

///Represents a list of the options needed to populate a `SettingsTableViewCell`
public struct Setting {
    ///The image to use for the icon
    var imageName : String

    ///The text to display as the title of the setting
    var title : String

    ///Called when the switch is tapped. If no closure is supplied, the switch is hidden
    var switchCallback: ((_ status: Bool)->())?
}



@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    let options : [Setting] =
    [
        //Error is on the following line
        Setting(imageName: "notifications", title: "Bump Notifications") {isOn in updateSetting(isOn)},
    ]

    func updateSetting(isOn : Bool) {

    }

}

2 个答案:

答案 0 :(得分:2)

Setting初始化程序中的关闭正在捕获self。但是,只有在初始化对象的所有属性之后,即在self初始化之后,Swift中的let options才可用。

打破圈子的一种方法是使用属性的延迟初始化:

public struct Setting {
    var imageName : String
    var title : String
    var switchCallback: ((_ status: Bool)->())?
}

class MyClass {
    lazy var options: [Setting] = [
        Setting(imageName: "x", title: "X") { [unowned self] in self.updateSetting(isOn: $0)}
    ]

    func updateSetting(isOn : Bool) {}
}

请注意声明当前需要显式类型: [Setting]

请注意,您需要使用[unowned self][weak self]来打破发布周期(感谢@rob的评论)。

答案 1 :(得分:0)

  

但是(a)你必须在闭包中明确引用self(例如self.updateNotificationSetting); (b)为此,只有在lazy var而不是let(允许它现在解决self)时才能这样做。

虽然我无法使用关键字lazy var,但这确实为我提供了解决问题所需的信息。我最终基本上创建了自己的lazy var,只是在我使用数组之前实例化它:

private var options : [Setting]!


...

if options == nil {
        options =  [
            Setting(imageName: "notifications", title: "Bump Notifications") {isOn in self.updateNotificationSetting(isOn: isOn)},
            Setting(imageName: "automatic_check_in", title: "Automatic Check In") {isOn in self.updateAutomaticCheckInSetting(isOn:isOn)},
            Setting(imageName: "logout", title: "Logout", switchCallback:nil)
        ]
    }