0

I am confused about where to use lazy functionality, I mean to say in which type of condition I should use lazy keyword in the collection.

Nirmalsinh Rathod
  • 5,079
  • 4
  • 26
  • 56
Brijesh Shiroya
  • 3,323
  • 1
  • 13
  • 20
  • The accepted answer has nothing to do with `NSMutableDictionary.lazy` ... the `lazy` keyword for properties is completely different. – Alexander Mar 03 '17 at 15:28

3 Answers3

2

Lazy evaluation is when the evaluation of an expression is deferred until the result is needed. This is in contrast to eager evaluation, which is when the evaluation of an expression is done immediately.

Consider this expression:

let input = [1, 2, 3]
let evens = input.map{ $0 * 2 }

Each number of numbers (1, 2, 3) is mapped to a new value by the closure { $0 * 2 }, which multiplies them by 2. This evaluation is done eagerly. That is, the moment this line is being executed is when the evaluation of the map function is performed, and the result of the computation is stored in evens. The input is of type Array<Int>, and the result, evens is also of type Array<Int>.

Now consider this expression:

let input = [1, 2, 3]
let evens = input.lazy.map{ $0 * 2 }

Each number of numbers (1, 2, 3) will be to a new value by the closure { $0 * 2 }, which multiplies them by 2. However, this evaluation is done lazily. That is, at the moment this line is being executed, the multiplication isn't done. Instead, the closure { $0 * 2 } is stored for future reference. The input is of type Array<Int>, and the result, evens is also of type LazyMapRandomAccessCollection<Array<Int>, Int>. The multiplication is deferred until an element is accessed. If an element is never accessed, then it's never processed.

In such a trivial case, the bookkeeping overhead of storing the closure for future evaluation would be larger than just computing the results eagerly. However, you can envision a situation like this:

let input = 1...1000000000
let evens = input.lazy.map{ $0 * 2 }
print(evens[0])

Of all of the 1000000000 in the sequence, only one is ever used. Evaluating the closure 1000000000 times, to produce 1000000000 results, storing them all in memory is really inefficient, if only the first of the elements will ever be needed.

lazy is an instance method of the Sequence protocol. All conforming types, including NSMutableDictionary implement it. They all do the same thing: they defer processing of elements in map and filter statements until the time that their results are needed. This can save memory and processing time in cases where there are many elements, and only a small portion of them are ever needed.

Alexander
  • 59,041
  • 12
  • 98
  • 151
1

From Apple Docs:

A lazy stored property is a property whose initial value is not calculated until the first time it is used. You indicate a lazy stored property by writing the lazy modifier before its declaration.

When use @lazy property then remembers below things:

  • Lazy property must always declare with the var keyword, not with the let constant.
  • Lazy properties must be initialized when it is declared.

How we achieve lazy functionality in Objective-C

@property (nonatomic, strong) NSMutableArray *players;

- (NSMutableArray *)players 
{
    if (!_players) {
        _players = [[NSMutableArray alloc] init];
    }
    return _players;
}

And now in Swift, you can achieve the same functionality by using lazy property. See below example

class Person {

    var name: String

    lazy var personalizedGreeting: String = {

        return "Hello, \(self.name)!"
    }()

    init(name: String) {
        self.name = name
    }
}

Now when you initialize a person, their personal greeting hasn’t been created yet:

let person = Person(name: "John Doe")  // person.personalizedGreeting is nil

But when you attempt to print out the personalized greeting, it’s calculated on-the-fly:

print(person.personalizedGreeting)
// personalizedGreeting is calculated when used
// and now contains the value "Hello, John Doe!"

I hope this will help you to understand the functionality of lazy property.

Hardik Shekhat
  • 1,680
  • 12
  • 21
0

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.

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")
Saumil Shah
  • 2,299
  • 1
  • 22
  • 27
  • the question has nothing to do with `lazy var`s. Also, you should avoid writing things like `for i in 0.. – Alexander Mar 01 '17 at 05:41