Swift lazy 修饰符和方法
LAZY 修饰符和 LAZY 方法
由 王巍 (@ONEVCAT) 发布于 2015/10/07
延时加载或者说延时初始化是很常用的优化方法,在构建和生成新的对象的时候,内存分配会在运行时耗费不少时间,如果有一些对象的属性和内容非常复杂的话,这个时间更是不可忽略。另外,有些情况下我们并不会立即用到一个对象的所有属性,而默认情况下初始化时,那些在特定环境下不被使用的存储属性,也一样要被初始化和赋值,也是一种浪费。
在其他语言 (包括 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 来进行性能优化效果会非常有效。
from: http://swifter.tips/
Swift lazy 修饰符和方法的更多相关文章
- 【iOS】Swift LAZY 修饰符和 LAZY 方法
延时加载或者说延时初始化是很常用的优化方法,在构建和生成新的对象的时候,内存分配会在运行时耗费不少时间,如果有一些对象的属性和内容非常复杂的话,这个时间更是不可忽略.另外,有些情况下我们并不会立即用到 ...
- .NET C#基础(2):方法修饰符 - 给方法叠buff
0. 文章目的 本文面向有一定.NET C#基础知识的学习者,介绍C#中的方法修饰符的含义和使用以及注意事项. 1. 阅读基础 理解C#基本语法(如方法声明) 理解OOP基本概念(如多 ...
- java中的类修饰符、成员变量修饰符、方法修饰符。
类修饰符: public(访问控制符),将一个类声明为公共类,他可以被任何对象访问,一个程序的主类必须是公共类. abstract,将一个类声明为抽象类,没有实现的方法,需要子类提供方法实现. fin ...
- java中的类修饰符、成员变量修饰符、方法修饰符
类修饰符: public(访问控制符),将一个类声明为公共类,他可以被任何对象访问,一个程序的主类必须是公共类. abstract,将一个类声明为抽象类,没有实现的方法,需要子类提供方法实现. fi ...
- 037——VUE中表单控件处理之表单修饰符:lazy/number/trim
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Java接口成员变量和方法默认修饰符
Java的interface中,成员变量的默认修饰符为:public static final 所以我们在interface中定义成员变量的时候,可以 1:public static final S ...
- java接口中成员变量和方法的默认修饰符(转)
Java的interface中,成员变量的默认修饰符为:public static final 所以我们在interface中定义成员变量的时候,可以 1:public static final St ...
- C#学习笔记06--类/对象/访问修饰符/方法
编程思想 1.面向过程 面向过程是要把问题解决的过程分成有一定顺序的不同步骤, 然后按照步骤一步步的将问题解决. 2.面向对象 面向对象解决问题的思路是先分析问题中所涉及的对象, 然后 ...
- vue修饰符 .lazy .number .trim
.lazy 在输入框中,v-model 默认是同步数据,使用 .lazy 会转变为在 change 事件中同步 , 也就是在失去焦点 或者 按下回车键时才更新 <template> < ...
随机推荐
- $GLOBALS['HTTP_RAW_POST_DATA'] 和$_POST的区别(转)
---恢复内容开始--- $_POST:通过 HTTP POST 方法传递的变量组成的数组.是自动全局变量. $GLOBALS['HTTP_RAW_POST_DATA'] :总是产生 $HTTP_RA ...
- 编写Qt Designer自定义控件(一)——如何创建并使用Qt自定义控件
在使用Qt Designer设计窗体界面时,我们可以使用Widget Box里的窗体控件非常方便的绘制界面,比如拖进去一个按钮,一个文本编辑器等.虽然Qt Designer里的控件可以满足我们大部分的 ...
- C#数据库读取数据后转换为INT32后计算的小技巧
这有什么难的,不管是什么数据库, 首先分别读出userinfo中usermoney的值 存入s1,card中extramoney的值s2 读出字段数据你应该会吧! 再用userinfo中字段userm ...
- Java编程最差代码
字符串连接误用 错误的写法: String s = ""; for (Person p : persons) { s += ", " + p.getName( ...
- css图片垂直居中
css图片垂直居中一.style代码 .case-pic{ height: 125px; position: relative; text-align: center } .case-pic span ...
- Linux动态查看网络流量iptraf
iptraf工具可以动态查看网络流量 yum install iptraf 查看所有网卡流量 iptraf -g
- Hadoop的伪分布式搭建
我们在搭建伪分布式Hadoop环境,需要将一系列的配置文件配置好. 一.配置文件 1. 配置文件hadoop-env.sh export JAVA_HOME=/opt/modules/jdk1.7.0 ...
- PHP 获取当前日期的上个月的日期
获取当前日期的上个月的日期 <?php /** *参考有: *http://www.oschina.net/code/snippet_96541_4015 *http://stackoverfl ...
- document.all的用法详解
all[] 已经被 Document 接口的标准的 getElementByid() 方法和 getElementsByTagName() 方法以及 Document 对象的 getElementsB ...
- Jquery Table添加行、删除行
html页面代码 <table id="tblUserInfo"> </table> Js代码 function DealUserInfo(qty){ ) ...