Lazy property initialization in Swift

后端 未结 9 1122
深忆病人
深忆病人 2020-12-18 04:25

How would you implement the following pattern in Swift?

The Container class is initialized with a JSON array that contains dictionaries. These dictionar

相关标签:
9条回答
  • I found this in PageBaseApplication

    var modelController: ModelController {
        // Return the model controller object, creating it if necessary.
        // In more complex implementations, the model controller may be passed to the view controller.
        if !_modelController {
            _modelController = ModelController()
        }
        return _modelController!
    }
    
    var _modelController: ModelController? = nil
    

    similar to what @Brian Tracy mentioned but ussing variables instead of a func

    0 讨论(0)
  • 2020-12-18 04:44

    You indicate a lazy stored property by writing the @lazy attribute before its declaration.”

    @lazy var lazyVariable:String? = ""
    

    Please bear in mind, lazy property must have an initialiser.

    0 讨论(0)
  • 2020-12-18 04:46

    The way lazy works is that the initializer (or init method) runs only when the variable or property is first accessed. I see one main reason why it won't work (at least straight away) in your code, and that is because you packed two lazy instantiation code into one method (loadEntriesIfNeeded).

    To use lazy instantiation, you might need to extend NSMutableArray and NSDictionary and override or create a custom initializer for your lazy instantiation. Then, distribute the code inside loadEntriesIfNeeded into their respective initializers.

    In entries initializer:

    NSMutableArray *entries = [NSMutableArray arrayWithCapacity:[self.entriesDict count]];
    [self.entriesDict enumerateKeysAndObjectsUsingBlock:^(NSString *number, NSDictionary *entryDict, BOOL *stop) {
                Entry *entry = [[Entry alloc] initWithDictionary:entryDict container:self];
                [entries addObject:entry];}];
    _entries = [entries copy];
    

    Then in entriesByNumber initializer:

    NSMutableDictionary *entriesByNumber = [NSMutableDictionary dictionaryWithCapacity:[self.entriesDict count]];
    // Then do fast enumeration accessing self.entries to assign values to entriesByNumber.
    // If self.entries is null, the lazy instantiation should kick in, calling the above code
    // and populating the entries variable.
    _entriesByNumber = [entriesByNumber copy];
    

    Then, you can create your lazy variables by calling on the custom initializers.

    @lazy var entries: CustomArray = custominitforarray()
    @lazy var entriesByNumber: CustomDictionary = custominitfordictionary()
    

    PS: How come you don't have a property for entriesByNumber? I'm guessing it's private? Please test this out and reply about the result as I'm too lazy to do it myself.

    0 讨论(0)
  • 2020-12-18 04:47

    You could use an optional as the instance variable. Then create a function that returns the optional if it exists, and a new object if it does not to simulate lazy loading.

    class Lazy {
        var lazyVariable:String?
    
        func lazilyGetEntries() -> String {
            if let possibleVariable = self.lazyVariable { // optional already exists
                return possibleVariable
            }
            else {                                        // optional does not exist, create it
                self.lazyVariable = String()
                return self.lazyVariable!
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-18 04:51

    There is a @lazy attribute in Swift. I found a small post here and I recommend watching the three Swift video from Apple here (Introduction to Swift, Intermediate Swift, Advanced Swift). These videos show a lot of stuff and the advanced one really is advanced...

    0 讨论(0)
  • 2020-12-18 04:52

    It seems that this question has largely been answered, but to circle back to the original post, here is (IMHO) a relatively succinct translation in Swift. The key is that you can chain lazy properties. Note that I used both a class function and a closure - either is fine.

    import Swift
    
    println("begin")
    
    class ClassWithLazyProperties {
    
        lazy var entries:[String] = ClassWithLazyProperties.loadStuff()
        lazy var entriesByNumber:Dictionary<Int, String> = {
    
            var d = Dictionary<Int, String>()
            for i in 0..<self.entries.count {
                d[i] = self.entries[i]
            }
            return d
        }()
    
        private class func loadStuff() -> [String] {
            return ["Acai", "Apples", "Apricots", "Avocado", "Ackee", "Bananas", "Bilberries"]
        }
    
    }
    
    let c = ClassWithLazyProperties()
    c.entriesByNumber
        // 0: "Acai", 1: "Apples", 2: "Apricots", 3: "Avocado", 4: "Ackee", 5: "Bananas", 6: "Bilberries"]
    
    
    println("end")
    
    0 讨论(0)
提交回复
热议问题