【问题标题】:What is meaning of NSMutableDictionary.lazy in swift?NSMutableDictionary.lazy 在swift中的含义是什么?
【发布时间】:2017-03-01 05:27:54
【问题描述】:

我对在哪里使用 lazy 功能感到困惑,我的意思是说我应该在集合中使用 lazy 关键字的哪种类型的条件。

【问题讨论】:

  • 接受的答案与NSMutableDictionary.lazy无关……属性的lazy关键字完全不同。

标签: objective-c swift nsmutabledictionary lazy-sequences


【解决方案1】:

来自 Apple 文档:

惰性存储属性是在第一次使用时才计算初始值的属性。您可以通过在声明之前编写惰性修饰符来指示惰性存储属性。

使用@lazy属性时会记住以下内容:

  • 惰性属性必须始终使用var 关键字声明,而不是使用let 常量。
  • 惰性属性必须在声明时进行初始化。

我们如何在 Objective-C 中实现惰性功能

@property (nonatomic, strong) NSMutableArray *players;

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

现在在 Swift 中,您可以使用 lazy 属性实现相同的功能。见下例

class Person {

    var name: String

    lazy var personalizedGreeting: String = {

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

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

现在,当您初始化一个人时,他们的个人问候语尚未创建:

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

但是,当您尝试打印个性化问候语时,它是即时计算的:

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

我希望这能帮助你理解惰性属性的功能。

【讨论】:

  • 这与NSMutableDictionary.lazy无关。
【解决方案2】:

惰性求值是将表达式的求值推迟到需要结果时。这与 eager 评估 不同,后者是立即完成表达式的评估。

考虑这个表达式:

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

每个数字 (1, 2, 3) 通过闭包{ $0 * 2 } 映射到一个新值,闭包将它们乘以 2。这个评估是急切地完成的。也就是说,执行此行的时刻是在执行map 函数的评估时,计算结果存储在evens 中。 inputArray<Int> 类型,结果 evens 也是 Array<Int> 类型。

现在考虑这个表达式:

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

每个数字 (1, 2, 3) 通过闭包 { $0 * 2 } 将它们乘以 2 为一个新值。但是,此评估是延迟完成的。也就是说,在执行这条线的那一刻,乘法还没有完成。相反,闭包{ $0 * 2 } 被存储以供将来参考。 inputArray<Int> 类型,结果 evens 也是 LazyMapRandomAccessCollection<Array<Int>, Int> 类型。乘法被推迟到元素被访问。如果一个元素从未被访问过,那么它就永远不会被处理。

在这种微不足道的情况下,存储闭包以供将来评估的簿记开销将比仅仅急切地计算结果要大。但是,您可以设想这样的情况:

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

在序列中的所有1000000000 中,只有一个被使用过。评估闭包 1000000000 次,以产生 1000000000 结果,将它们全部存储在内存中确实效率低下,如果只需要第一个元素的话。

lazySequence 协议的实例方法。所有符合要求的类型,包括NSMutableDictionary 都实现了它。他们都做同样的事情:他们推迟处理mapfilter 语句中的元素,直到需要他们的结果。在元素很多且只需要其中一小部分的情况下,这可以节省内存和处理时间。

【讨论】:

    【解决方案3】:

    lazy 的工作方式是初始化程序(或 init 方法)仅在第一次访问变量或属性时运行。我看到它在您的代码中不起作用(至少立即)的一个主要原因,那是因为您将两个惰性实例化代码打包到一个方法中(loadEntriesIfNeeded)。

    要使用惰性实例化,您可能需要扩展 NSMutableArray 和 NSDictionary 并为您的惰性实例化覆盖或创建自定义初始化程序。然后,将 loadEntriesIfNeeded 中的代码分发到各自的初始化程序中。

    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")
    

    【讨论】:

    • 问题与lazy vars无关。此外,您应该避免写 for i in 0..&lt;self.entries.count 之类的东西来支持 for i in self.entries.indices。此外,如果您需要数组的索引和元素,则应使用for (index, element) in self.entries.enumerated()
    猜你喜欢
    • 2018-12-27
    • 2018-05-05
    • 1970-01-01
    • 2014-07-02
    • 1970-01-01
    • 2019-07-02
    • 1970-01-01
    • 2011-06-01
    • 1970-01-01
    相关资源
    最近更新 更多