Re-initialize a lazy initialized variable in Swift

前端 未结 7 833
没有蜡笔的小新
没有蜡笔的小新 2020-12-04 11:08

I have a variable that initialized as:

lazy var aClient:Clinet = {
    var _aClient = Clinet(ClinetSession.shared())
    _aClient.delegate = self
    return          


        
7条回答
  •  情话喂你
    2020-12-04 11:35

    Because the behavior of lazy changed in Swift 4, I wrote a few structs that give very specific behavior, which should never change between language versions. I put these on GitHub, under the BH-1-PD license: https://github.com/RougeWare/Swift-Lazy-Patterns

    ResettableLazy

    Here is the one relevant to this question, which gives you a way to lazily-initialize a value, cache that value, and destroy it so it can be lazily-reinitialized later.

    Note that this requires Swift 5.1! For the Swift 4 version, see version 1.1.1 of that repo.

    The simple usage of this is very straightforward:

    @ResettableLazy
    var myLazyString = "Hello, lazy!"
    
    print(myLazyString) // Initializes, caches, and returns the value "Hello, lazy!"
    print(myLazyString) // Just returns the value "Hello, lazy!"
    
    _myLazyString.clear()
    print(myLazyString) // Initializes, caches, and returns the value "Hello, lazy!"
    print(myLazyString) // Just returns the value "Hello, lazy!"
    
    myLazyString = "Overwritten"
    print(myLazyString) // Just returns the value "Overwritten"
    _myLazyString.clear()
    print(myLazyString.wrappedValue) // Initializes, caches, and returns the value  "Hello, lazy!"
    

    This will print:

    Hello, lazy!
    Hello, lazy!
    Hello, lazy!
    Hello, lazy!
    Overwritten
    Hello, lazy!
    

    If you have complex initializer logic, you can pass that to the property wrapper:

    func makeLazyString() -> String {
        print("Initializer side-effect")
        return "Hello, lazy!"
    }
    
    @ResettableLazy(initializer: makeLazyString)
    var myLazyString: String
    
    print(myLazyString) // Initializes, caches, and returns the value "Hello, lazy!"
    print(myLazyString) // Just returns the value "Hello, lazy!"
    
    _myLazyString.clear()
    print(myLazyString) // Initializes, caches, and returns the value "Hello, lazy!"
    print(myLazyString) // Just returns the value "Hello, lazy!"
    
    myLazyString = "Overwritten"
    print(myLazyString) // Just returns the value "Overwritten"
    _myLazyString.clear()
    print(myLazyString.wrappedValue) // Initializes, caches, and returns the value  "Hello, lazy!"
    

    You can also use it directly (instaed of as a property wrapper):

    var myLazyString = ResettableLazy() {
        print("Initializer side-effect")
        return "Hello, lazy!"
    }
    
    print(myLazyString.wrappedValue) // Initializes, caches, and returns the value "Hello, lazy!"
    print(myLazyString.wrappedValue) // Just returns the value "Hello, lazy!"
    
    myLazyString.clear()
    print(myLazyString.wrappedValue) // Initializes, caches, and returns the value "Hello, lazy!"
    print(myLazyString.wrappedValue) // Just returns the value "Hello, lazy!"
    
    myLazyString.wrappedValue = "Overwritten"
    print(myLazyString.wrappedValue) // Just returns the value "Overwritten"
    _myLazyString.clear()
    print(myLazyString.wrappedValue) // Initializes, caches, and returns the value  "Hello, lazy!"
    

    These will both print:

    Initializer side-effect
    Hello, lazy!
    Hello, lazy!
    Initializer side-effect
    Hello, lazy!
    Hello, lazy!
    Overwritten
    Initializer side-effect
    Hello, lazy!
    

    This answer has been updated; its original solution no longer works in Swift 4 and newer.

    Instead, I recommend you use one of the solutions listed above, or @PBosman's solution

    Previously, this answer hinged on behavior which was a bug. Both that old version of this answer, its behavior, and why it's a bug are described in the text and comments of Swift bug SR-5172 (which has been resolved as of 2017-07-14 with PR #10,911), and it's clear that this behavior was never intentional.

    That solution is in that Swift bug's text, and also in the history of this answer, but because it's a bug exploit that doesn't work in Swift 3.2+ I recommend you do not do that.

提交回复
热议问题