【iOS】Swift LAZY 修饰符和 LAZY 方法
延时加载或者说延时初始化是很常用的优化方法,在构建和生成新的对象的时候,内存分配会在运行时耗费不少时间,如果有一些对象的属性和内容非常复杂的话,这个时间更是不可忽略。另外,有些情况下我们并不会立即用到一个对象的所有属性,而默认情况下初始化时,那些在特定环境下不被使用的存储属性,也一样要被初始化和赋值,也是一种浪费。
在其他语言 (包括 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 属性的话,可以看到只有一次输出。
为了简化,我们如果不需要做什么额外工作的话,也可以对这个 lazy 的属性直接写赋值语句:
lazy var str: String = "Hello"
相比起在 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...3
let result = data.map {
(i: Int) -> Int in
print("正在处理 \(i)")
return i * 2
}
print("准备访问结果")
for i in result {
print("操作后结果为 \(i)")
}
print("操作完毕")
这么做的输出为:
// 正在处理 1
// 正在处理 2
// 正在处理 3
// 准备访问结果
// 操作后结果为 2
// 操作后结果为 4
// 操作后结果为 6
// 操作完毕
而如果我们先进行一次 lazy 操作的话,我们就能得到延时运行版本的容器:
let data = 1...3
let 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
// 操作完毕
对于那些不需要完全运行,可能提前退出的情况,使用 lazy 来进行性能优化效果会非常有效。
【iOS】Swift LAZY 修饰符和 LAZY 方法的更多相关文章
- Swift lazy 修饰符和方法
LAZY 修饰符和 LAZY 方法 由 王巍 (@ONEVCAT) 发布于 2015/10/07 延时加载或者说延时初始化是很常用的优化方法,在构建和生成新的对象的时候,内存分配会在运行时耗费不少时间 ...
- 037——VUE中表单控件处理之表单修饰符:lazy/number/trim
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Vue 修饰符once的方法使用
once:只执行一次 代码: <!doctype html> <html lang="en"> <head> <meta charset= ...
- Vue表单修饰符(lazy,number,trim)
lazy:使用了这个修饰符将会从“input事件”变成change事件进行同步 <div id="example"> <input type="text ...
- iOS Swift结构体与类的方法调度
前言 hello,小伙伴们:在忙碌中闲暇之余给大家聊聊swift的知识点,今天给大家带来的是swift中结构体与类的方法调度详细区别,希望对你有所帮助,好了废话不用多说,接下来步入主题! 1.普通方法 ...
- iOS之属性修饰符 retain、strong和copy区别测试
时不时会有点迷惑属性修饰符retain.strong.copy三者之间的区别,还是把测试过程记录下来好一点! 1.属性修饰符结论 2.给retain.strong.copy修饰的字符串属性赋值指针变化 ...
- final修饰符(5)-final方法
final修饰的类的方法不能被重写,例如如果父类不希望子类重写某个方法,则可以使用final修饰符修饰该方法 在java的Object类里面有一个final方法:getClass(),因为Java不希 ...
- iOS 实例变量修饰符
@public 可以在其他类中访问被@public修饰的成员变量 可以在本类中访问被@public修饰的成员变量 可以在子类中访问fl中被@public修饰的成员变量 @private 不可以在其他类 ...
- ios swift 2 新的OptionSetType使用方法
http://www.rockhoppertech.com/blog/swift-2-optionsettype/?utm_source=tuicool 主要使用方法如下 components([NS ...
随机推荐
- numpy使用总结
numpy是Python中常用的数据处理库的基础库,一般通过import numpy as np的方式导进 科学计算库numpy 在numpy中,主要的数据结构是ndarray,在numpy中称为数组 ...
- bzoj2969 矩形粉刷
学习一波用markdown写题解的姿势QAQ 题意 给你一个w*h的矩形网格,每次随机选择两个点,将以这两个点为顶点的矩形内部的所有小正方形染黑,问染了k次之后期望有多少个黑色格子. 分析 一开始看错 ...
- 原根求解算法 && NTT算法
原根求解算法: 获取一个数\(N\)的原根\(root\)的算法 #include<bits/stdc++.h> #define ll long long #define IL inlin ...
- El表达式的判断字符串的长度和截取,日期时间的格式化
<c:if test="${fn:length(each.wii_name) >= 20}"> ${fn:substring(each.wii_name, 0,2 ...
- Java最大公约数和最小公倍数的求法(辗转相除法)
这道题计算了三个数的最小公倍数 import java.util.Scanner; public class D { public static int gcd(int a,int b) { int ...
- 【Unity与23种设计模式】迭代器模式(Iterator)
GoF中定义: "在不知道集合内部细节的情况下,提供一个按序方法存取一个对象集合体的每一个单元." 迭代器模式由于经常使用到 已经被现代程序设计语言纳为标准语句或收录到标准函数库中 ...
- node.js 模块化
模块是编写稍大一点点的程序 一般就会将代码模块化 在node.js中每一个文件就是一个模块,而文件路径就是模块名 怎么使用模块? 在编写某个模块是都有三个预先定义(require,exports,mo ...
- python笔记之函数
函数 >>> def funTest(param1): ... 'this is function document string.' #正文需要有缩进 ... return par ...
- 修改UI及盒子启动及部分后续操作
服务器操作: 1.配置nfs: # vim /etc/exports /home/nfsroot *(insecure,rw,no_root_squash) mkdir -pv /home/nfsro ...
- 自定义TabBar之理解hittest
需求的TabBar是这样的:5个 tabItem, 中间的那个 item 部分超出系统默认TabBar的上边界. 那么实现的关键点就是如何在点击它突出的部分的时候,也可以正常获得响应.我来把问题简化, ...