在Swift中重新初始化一个懒惰的初始化variables
我有一个variables,初始化为:
lazy var aClient:Clinet = { var _aClient = Clinet(ClinetSession.shared()) _aClient.delegate = self return _aClient }()
问题是,在某些时候,我需要重置这个aClient
variables,以便它可以在ClinetSession.shared()
更改时再次初始化。 但是,如果我把课程设置为可选的Clinet?
,当我尝试将它设置nil
时,LLVM会给我一个错误。 如果我使用aClient = Clinet(ClinetSession.shared())
在代码中的某处重置它,它将以EXEC_BAD_ACCESS
结束。
有没有办法可以使用lazy
和被允许重置自己?
谢谢!
懒惰是明确的一次性只有初始化。 您要采用的模型可能只是一个按需初始化模型:
var aClient:Client { get { if(_aClient == nil) { _aClient = Client(ClientSession.shared()) } return _aClient! } } var _aClient:Client?
现在每当_aClient
nil
,它将被初始化并返回。 可以通过设置_aClient = nil
来重新初始化
这个解决scheme不再适用于Swift 4!
相反,我build议你使用@ PBosman的解决scheme
下面的行为是一个错误,在Swift bug SR-5172 (已经在2017-07-14已经被parsing, PR#10,911已经被parsing)中描述,并且很明显,这种行为从来没有故意。
Swift 3的解决scheme出于历史原因,但由于这是一个漏洞利用, 我build议你不要这样做:
我不确定这是什么时候添加的,但是从Swift 3开始 ,您可以简单地将属性设置为nil-able:
lazy var aClient:Client! = { var _aClient = Client(ClinetSession.shared()) _aClient.delegate = self return _aClient }() // ... aClient = nil
现在,下一次将它设置为nil
之后调用aClient,它将被重新初始化。
请注意,尽pipe现在在技术上是可选的,但是每次尝试读取它时,都会保证具有运行时值。 这就是我使用的原因!
在这里,因为它总是一个安全的调用,永远不会被读 nil
,但它可以设置 nil
。
编辑:根据Ben Leggiero的回答,懒惰的变数可以在Swift 3中无效。
晚会很晚,甚至不知道这是否与Swift 3相关,但是这里有。 David的回答是好的,但是如果你想创造许多懒惰的可变的variables,你将不得不编写一个相当庞大的代码块。 我正在尝试创build一个封装了这个行为的ADT。 这是迄今为止我所得到的:
struct ClearableLazy<T> { struct ClearableLazy<T> { private var t: T! private var constructor: () -> T init(_ constructor: () -> T) { self.constructor = constructor } mutating func get() -> T { if t == nil { t = constructor() } return t } mutating func clear() { t = nil } }
然后你会声明和使用这样的属性:
var aClient = ClearableLazy(Client.init) aClient.get().delegate = self aClient.clear()
有些事情我不喜欢,但是不知道如何改进:
- 你必须传递一个构造函数给初始化器,这看起来很丑。 不过,它的优势在于,您可以精确指定如何创build新对象。
- 每当你想使用它时,调用
get()
属性是非常糟糕的。 如果这是一个计算的属性,而不是一个函数,但是计算的属性不能改变,那会更好一些。 - 为了消除调用
get()
的需要,你必须扩展每个你想使用的types和ClearableLazy
初始值。
如果有人觉得从这里捡起来,那真是太棒了。
这允许将属性设置nil
来强制重新初始化:
private var _recordedFileURL: NSURL! /// Location of the recorded file private var recordedFileURL: NSURL! { get { if _recordedFileURL == nil { let file = "recording\(arc4random()).caf" let url = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent(file) NSLog("FDSoundActivatedRecorder opened recording file: %@", url) _recordedFileURL = url } return _recordedFileURL } }