Reputation: 32066
I have a SettingsViewController
and have created a struct to define the information required for each setting.
///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)->())?
}
The view controller keeps an array of these settings to later be used in a table view. An example of one is provided below:
let options : [Setting] =
[
Setting(imageName: "notifications", title: "Bump Notifications") {updateNotificationSetting($0)},
...
]
However, when I try to compile, I'm presented with the error:
Cannot convert value of type '(SettingsViewController) -> (Bool) -> ()' to expected argument type '((Bool) -> ())?'
Can somebody explain where the (SettingsViewController)
is coming from, please? And if you can, what I need to change to fix it, please?
For an SSCCE, see below:
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) {
}
}
Upvotes: 0
Views: 71
Reputation: 130082
The closure in your Setting
initializer is capturing self
. However, self
in Swift is available only after all the properties of an object are initialized, that is, after let options
is initialized.
One method to break the circle is to use lazy initialization of properties:
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) {}
}
Note the explicit type : [Setting]
is currently required for the declaration.
Note you need to use [unowned self]
or [weak self]
to break the release cycle (thanks @rob for the comment).
Upvotes: 2
Reputation: 32066
But (a) you have to have an explicit reference to
self
in the closure (e.g.self.updateNotificationSetting
); and (b) to do that, you can only do that if you make itlazy var
rather thanlet
(allowing it to now resolveself
).
Although I wasn't able to get this working with the keyword lazy var
, this did give me the information I needed to solve the problem. I ended up essentially making my own lazy var, only instantiating it just before I use the array:
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)
]
}
Upvotes: 0