J'ai une classe Swift qui a un ivar constant (sont-ils appelés des constantes d'instance maintenant?). Pour définir la valeur de cette constante, j'ai besoin d'appeler un initialiseur de l'objet souhaité et de se passer . Cependant, je ne suis pas autorisé à le faire car je dois d'abord initialiser toutes les valeurs, puis appeler super.init()
et ensuite je suis autorisé à accéder à self
. Alors, que faire dans ce cas?
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()
}
}
Malheureusement, il ne semble plus possible d’avoir bluetoothManager
comme constante. À partir de Swift 1.2, dans un initialiseur, les propriétés constantes ne peuvent affecter une valeur qu'une seule fois. Cela ne nous permet pas de commencer par une valeur nil
en la déclarant comme facultative et le modifier plus tard dans le processus d'initialisation. Voici la version mise à jour avec bluetoothManager
comme variable.
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)
}
}
Vous pouvez utiliser ici l'option implicitement déballée (pour bluetoothManager
) et lui affecter la valeur après 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)
}
}
Étant donné que bluetoothManager
est facultatif, au moment où super.init()
est appelée, toutes les propriétés sont initialisées (bluetoothManager
est implicitement initialisée avec nil
). Mais comme nous savons que bluetoothManager
aura définitivement la valeur après l'initialisation de la classe, nous la déclarons comme explicitement dépliée pour éviter les vérifications lors de son utilisation.
METTRE À JOUR
Une propriété peut être déclarée comme constante et toujours être modifiée dans l'initialiseur. Il suffit de s'assurer qu'il a une valeur définie au moment où l'initialisation se termine. Ceci est documenté dans le chapitre "Modification des propriétés constantes pendant l'initialisation" du livre Swift.
La situation où une propriété doit être initialisée avec un appel où self doit être passé à partir d'un objet non encore complètement initialisé est décrite dans le chapitre "Références sans propriétaire et propriétés facultatives implicitement non enveloppées".
Que diriez-vous de configurer votre bluetoothManager en tant que @lazy
propriété et y accéder plus tard, par exemple à startAdvertising
?
@lazy var bluetoothManager: CBPeripheralManager = CBPeripheralManager(delegate: self, queue: nil)
init() { ... }
func start() {
self.bluetoothManager.startAdvertising([ "foo" : "bar" ])
}