您的位置:首页 > 移动开发 > Swift

swift学习日志—— lazy懒加载

2015-12-30 11:26 267 查看
      懒加载或者说延时初始化是很常用的优化方法,在构建和生成新的对象的时候,内存分配会在运行时耗费不少时间,如果有一些对象的属性和内容非常复杂的话,这个时间更是不可忽略。另外,有些情况下我们并不会立即用到一个对象的所有属性,而默认情况下初始化时,那些在特定环境下不被使用的存储属性,也一样要被初始化和赋值,也是一种浪费。

      在其他语言 (包括 Objective-C) 中懒加载的情况是很常见的。我们在第一次访问某个属性时,判断这个属性背后的存储是否已经存在,如果存在则直接返回,如果不存在则说明是首次访问,那么就进行初始化并存储后再返回。这样我们可以把这个属性的初始化时刻推迟,与包含它的对象的初始化时刻分开,以达到提升性能的目的。以 Objective-C 举个例子 (虽然这里既没有费时操作,也不会因为使用懒加载而造成什么性能影响,但是作为一个最简单的例子,可以很好地说明问题):
// ClassA.h
@property (nonatomic, copy) NSString *testString;

// ClassA.m
- (NSString *)testString {
if (!_testString) {
_testString = @"Hello";
NSLog(@"只在首次访问输出");
}
return _testString;
}


      在初始化 
ClassA
 对象后,
_testString
 是 
nil
。只有当首次访问 
testString
 属性时
getter 方法会被调用,并检查如果还没有初始化的话,就进行赋值。为了方便确认,我们还在赋值时打印了一句 log。我们之后再多次访问这个属性的话,因为 
_testString
 已经有值,因此将直接返回。

      在 Swift 中我们使用在变量属性前加 
lazy
 关键字的方式来简单地指定延时加载。比如上面的的代码我们在
Swift 中重写的话,会是这样:

//懒加载
class ClassA {
lazy var str: String = {
let str = "Hello"
print("只在首次访问输出")
return str
}()
}

      我们在使用 
lazy
 作为属性修饰符时,只能声明属性是变量。另外我们需要显式地指定属性类型,并使用一个可以对这个属性进行赋值的语句来在首次访问属性时运行。如果我们多次访问这个实例的 
str
 属性的话,可以看到只有一次输出。

var AA = ClassA()AA.strAA.str

只在首次访问输出

     相比起在 Objective-C 中的实现方法,现在的 lazy 使用起来要方便得多。

     另外一个不太引起注意的是,在 Swift 的标准库中,我们还有一组 
lazy
 方法,它们的定义是这样的:
func lazy<S : SequenceType>(s: S) -> LazySequence<S>

func lazy<S : CollectionType where S.Index : RandomAccessIndexType>(s: S)
-> LazyRandomAccessCollection<S>

func lazy<S : CollectionType where S.Index : BidirectionalIndexType>(s: S)
-> LazyBidirectionalCollection<S>

func lazy<S : CollectionType where S.Index : ForwardIndexType>(s: S)
-> LazyForwardCollection<S>


      这些方法可以配合像 
map
 或是 
filter
 这类接受闭包并进行运行的方法一起,让整个行为变成延时进行的。在某些情况下这么做也对性能会有不小的帮助。例如,直接使用 
map
 时:

let data = 1...5let result = data.map{    (i:Int) -> Int in    print("正在处理:\(i)")    return i*2}print("准备开始访问结果")for i in result{    print("操作后结果为\(i)")}print("操作完毕")

正在处理:1正在处理:2正在处理:3正在处理:4正在处理:5准备开始访问结果操作后结果为2操作后结果为4操作后结果为6操作后结果为8操作后结果为10操作完毕

而如果我们先进行一次 
lazy
 操作的话,我们就能得到延时运行版本的容器:

//map结合lazy懒加载,性能优化let data = 1...5let result = data.lazy.map{    (i:Int) -> Int in    print("正在处理:\(i)")    return i*2}print("准备开始访问结果")for i in result{    print("操作后结果为\(i)")}print("操作完毕")

准备开始访问结果正在处理:1操作后结果为2正在处理:2操作后结果为4正在处理:3操作后结果为6正在处理:4操作后结果为8正在处理:5操作后结果为10操作完毕
对于那些不需要完全运行,可能提前退出的情况,使用 
lazy
 来进行性能优化效果会非常有效。

//map结合lazy懒加载,性能优化let data = 1...5let result = data.lazy.map{    (i:Int) -> Int in    print("正在处理:\(i)")    return i*2}print("准备开始访问结果")for i in result{    if i==8{ //提前退出        break    }    print("操作后结果为\(i)")}print("操作完毕")

准备开始访问结果正在处理:1操作后结果为2正在处理:2操作后结果为4正在处理:3操作后结果为6正在处理:4操作完毕
                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  swift lazy