我有一个具有常量ivar的Swift类(它们现在被称为实例常量吗?)。要将值设置为此常量,我需要调用所需对象的初始化程序并传递自身。但是,我不允许我首先初始化所有值,然后调用super.init()
,之后我可以访问self
。那么在这种情况下该怎么办?
class Broadcaster: NSObject, CBPeripheralManagerDelegate {
let broadcastID: NSUUID
let bluetoothManager: CBPeripheralManager
init(broadcastID: NSUUID) {
self.broadcastID = broadcastID
let options: Dictionary<NSString, AnyObject> = [ CBPeripheralManagerOptionShowPowerAlertKey: true ]
self.bluetoothManager = CBPeripheralManager(delegate: self, queue: nil, options: options) // error: 'self' used before super.init call
super.init()
}
}
答案 0 :(得分:34)
不幸的是,将bluetoothManager
作为常量似乎不再可能。从Swift 1.2开始,在初始化程序中,常量属性只能赋值一次。这不允许我们以nil
值开头,将其声明为可选值,并在初始化过程中稍后进行更改。这是更新版本,bluetoothManager
作为变量。
class Broadcaster: NSObject, CBPeripheralManagerDelegate {
let broadcastID: NSUUID
var bluetoothManager: CBPeripheralManager!
init(broadcastID: NSUUID) {
self.broadcastID = broadcastID
super.init()
let options: Dictionary<String, AnyObject> = [ CBPeripheralManagerOptionShowPowerAlertKey: true ]
self.bluetoothManager = CBPeripheralManager(delegate: self, queue: nil, options: options)
}
}
您可以在此处使用隐式展开的可选项(适用于bluetoothManager
)并在super.init()
之后为其指定值:
class Broadcaster: NSObject, CBPeripheralManagerDelegate {
let broadcastID: NSUUID
let bluetoothManager: CBPeripheralManager!
init(broadcastID: NSUUID) {
self.broadcastID = broadcastID
super.init()
let options: Dictionary<NSString, AnyObject> = [ CBPeripheralManagerOptionShowPowerAlertKey: true ]
self.bluetoothManager = CBPeripheralManager(delegate: self, queue: nil, options: options)
}
}
由于bluetoothManager
是可选的,因此在调用super.init()
时,所有属性都会初始化(bluetoothManager
会隐式初始化为nil
)。但是因为我们知道bluetoothManager
在类初始化之后肯定会有值,所以我们声明它是显式解包的,以避免在使用它时进行检查。
更新
属性可以声明为常量,并且仍然可以在初始化程序中更改。在初始化完成时,必须确保它具有确定的值。这在Swift book的“在初始化期间修改常量属性”一章中有记载。
“无主引用和隐式展开的可选属性”一章中描述了一个属性需要通过调用来初始化的情况,其中self必须从尚未完全初始化的对象传递。“
答案 1 :(得分:1)
如何将bluetoothManager设置为@lazy
属性并稍后访问它...到startAdvertising
?
@lazy var bluetoothManager: CBPeripheralManager = CBPeripheralManager(delegate: self, queue: nil)
init() { ... }
func start() {
self.bluetoothManager.startAdvertising([ "foo" : "bar" ])
}