Swift学习笔记--高级篇

最近看了两本书, 第一本是Objc.io出的Advanced Swift和王巍大大出的Swifter tips. 后者在作者的博客上有更新, 应该已经更新完了吧.

这里列出一些看过了笔记, 也是比较粗糙, 只是大概都过了一遍, 把一些之前遗漏或者有错漏的地方补全了.

一. Collection
1.值类型的赋值虽然是copy, 但是实际上会是"copy on write”, 只有在真正发生写操作的时候才会进行修改;
2.需要用for循环遍历的时候考虑一下map函数, 它可以使得代码更加简洁, 同时可以让原本不得不为var的变量变为let;3.为了避免不必要的copy, 数组的范围下标访问返回的集合是ArraySlice<T>类型的, 它有与数组一样的方法, 所以可以被当做数组, 如果实在需要转换就用Array(slice)来构造一个;
需要注意的是, 切面可以增加数组元素, 但是不能修改, 如下面的代码:

var array = ["1","2","3"]
var slices = array[1..<array.endIndex]
slices[0] = “a”  // crash
slices.append("4”) // OK
// 存疑:
array[1] = “22”  // 执行后slices并没有响应的变化, 所以, 对内部实现还是有疑问

4.Dictionary的updateValue方法可以返回旧值5.GeneratorType协议由于其只能被访问一次, 因此其实现者最好是class而不是struct6.对集合的访问尽量不要用subscript, 可以用for-in和map, filter等高阶函数实现, 几个”特殊"的情况:1). 对下标的遍历: for idx in collection.indices2). 对下标和元素的遍历: for (idx, element) in collection.enumerate()7.严格说来[1,2,3]这样的值, 它的类型不是Array, 而是ArrayLiteral, 只是因为Array实现了ArrayLiteralConvertible协议, 所以才能通过这样的字面值来构造Array, 同样的还有DictionaryLiteralConvertible, IntegerLiteralConvertible,StringLiteralConvertible等等8.collection的starIndex不一定从0开始的, 所以写C风格循环的时候不要var i = 0, 而应该是var i = collection.startIndex
9.case的模式匹配:

for case let variable? in mayNilCollection{
}

等同于:

for let variable in mayNilCollection where variable != nil {
}

同时

for case nil in mayNilCollection {

}

可以帮你找出集合中有多少个nil

同时case还可以和if一起用:

let j = 5
if case 0..<10 = j {

}
  1. lazy修饰符:
    lazy可以对属性进行修饰, 类似于ObjC里面的手动控制一样. 同时Swift里面的标准库也提供了一套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可以把最后的计算拖到真正需要的时刻再进行. 这种优化非常适合在result遍历的时候, 有需要退出的情况.

二. Optional
1.guard比if好的地方: guard let的变量可以被外部访问, 避免了if金字塔结构; guard的语义更加鲜明, 就是为了检查返回失败条件的

  1. 关于optional chaining的结果也是optional的解释:

let j = Int(“1”)?.successor().successor() // 为什么第二个successor()不需要加?来调用

原因在于结果是optional, 而不是中间状态也是optional, 对于上面的语句来说, optional的状态是已经captured, 所以后续的方法调用只要不是前一个方法本身返回optional, 就不需要写?, 举一个例证:

let j = Int(“1”)?.successor() // 这里把optional传递给了结果, 所以下面的语句需要加?
let k = j?.successor()

  1. 关于??操作符的解释:
    ??操作符的作用基本可以等效为ObjC里面的?:操作符. 但是参考以下情况:
let i: Int? = nil
let j: Int? = nil
let k: Int? = 42
let m = i ?? j ?? k ?? 0
let n = i ?? j ?? k
print(“\(m)”)    // 说明m的类型是Int
print("\(n!)”)   // 说明n的类型是Int?

m和n的区别说明, 对于编译器来说, 不i j k是否为nil, m是可以确定不为nil的, 所以m不会为optional, 但是n则不一定. 这也算是optional的智能之处

另外, 用??来替代||和&&

if let n = i ?? j {
// 类似于 if i != nil || j != nil
}

if let n = i, m = j {
// 类似于 if i != nil && j != nil
}

主要注意的是, ??操作符要和多层optional一起使用的时候要特别注意, 如:

let s1: String?? = nil

(s1 ?? "inner") ?? “outer”     // 返回 “inner"
let s2: String?? = .Some(nil)
(s2 ?? "inner") ?? “outer”     // 返回 “outer"

4.Optional的map与flatMap

let stringNumbers = ["a","1", "2", "3"]
let x = stringNumbers.first.map{Int($0)}      // x的类型为Int??
let y = stringNumbers.first.flatMap{Int($0)}  // y的类型为Int?
  1. Optional类型转换
    在Optional值与非Optional值进行比较的时候, Swift会对非Optional值进行类型转换, 以使两者类型匹配, 再进行比较. 这个特性被广泛使用, 例如下面的代码:
let strArray = [“1”, “2”, “3"]
let result = strArray.first.map{$0}

result的类型会是String?, 但是map中返回的类型是String, 所以是由Swift的编译器为我们进行了类型转换.

6.强制解包
无论出于什么样的目的这么干, 一定要反思一下, 是否已经没有更好的选择了? 这么写之后最好能留下注释解释为什么.

7.隐式Optional
隐式Optional本质上还是Optional, 只是在使用的时候不需要再解包而已, 声明如下:
var s :Int! = nil
print(“(s)”) // 不会报错

一般情况下, 会在那些的确有可能为空, 但是一旦初始化完成之后就不会为空的变量使用此类型. 常见于某些提供了可能失败的构造器的情况.
需要注意的是, 如果隐式Optional为nil, 对它进行的任何操作同样会造成运行时error.

最后提一下Monad和Factor吧. 这个唐巧在自己的博客上更新了很多相关内容, 貌似最新的Qcon讲的也是这个. 这个东西理解起来的确很难, 但其实也就是2个概念, 对于这2个概念的解释, 我觉得唐巧的博客里面讲的很细致, 一起分享给大家我认为最核心的部分:

  1. 主要理解什么叫「封装过的值」, 值被包含在容器中或者被Optional包含, 都可以理解为封装过的值.
  2. flatMap和map都是处理封装过的值, 前者的闭包接受一个「未封装的值」,返回一个「封装后的值」, 后者闭包接受一个「未封装的值」,返回一个「未封装的值」.

理解起来是比较绕, 但是一般来说看看源码, 知道这2个高级函数有什么用就会容易理解很多.

另外, Advanced Swift这本书还是挺值得看的, 很多内容的确比较新颖, 会看到很多国内的大牛都讲了里面的一部分东西, 这里面算是集大成之作. 后续的几章因为暂时团队还没有用Swift开发, 所以还没看, 对类和结构体的那一章也是老生常谈, 如果发现有新大陆会更新出来.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,719评论 0 33
  • SwiftDay011.MySwiftimport UIKitprintln("Hello Swift!")var...
    smile丽语阅读 3,826评论 0 6
  • 1、随机数 不需要随机数种子 arc4random()%N + begin:产生begin~begin+N的随机数...
    我是小胡胡分胡阅读 4,134评论 0 2
  • 基础部分(The Basics) 当推断浮点数的类型时,Swift 总是会选择Double而不是Float。 结合...
    gamper阅读 1,257评论 0 7
  • 湖南人爱吃,在全国都比较有名。每到吃龙虾的季节,大街小巷,到处飘荡着龙虾的香味,引得人口水直流。今天,刘家弟弟亲自...
    刘姐之家阅读 374评论 4 0