需要self来在init中设置swift类的所有常量

时间:2014-06-14 09:38:14

标签: swift self initializer

我有一个具有常量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()
    }
}

2 个答案:

答案 0 :(得分:34)

更新Swift 1.2及更高版本

不幸的是,将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" ])

}