死磕The Swift Programming Language——学习笔记1

引言

The Swift Programming Language已经泛泛地看了几遍了,由于看的不上心,花时间研究Swift的时候寥寥无几,再加上平时用Swift写的代码很少,一直还是Swift菜鸟一枚,现在打算和Swift死磕,先从The Swift Programming Language开始。

注:文中引用部分无特殊说明都是The Swift Programming Language里的原文

基础部分

Swift基于cocoa、cocoa touch,兼容OC,能够边写代码边执行(Playground),它是一种语法灵活,编译严格的一门语言。


32位平台上Int与Int32位数相同,64位平台上Int与Int64位数相同


Double是64位的,它至少有16位数字,后面五舍六入,如果是0.xxx形式的小数会显示17位

Float是32位的,只显示7位数字,后面进五舍六入,如果是0.xxx形式的小数会会显示8位

这里与programming Language中说明的不符,我是在playground里测试的

下面是原文表述

注意:
Double精确度很高,至少有15位数字,而Float只有6位数字。选择哪个类型取决于你的代码需要处理的值的范围。


推断浮点数的类型时,Swift总是会选择Double,而不是Float,表达式中整型、浮点同时出现会被推断为Double


不同进制的整数数值字面量的表示:
0b二进制数、0o八进制数、0x十六进制数


1.25e2 = 1.25 x 10^2 = 125.0
1.25e-2 = 1.25 x 10^-2 = 0.0125
0xFp2 = 15 x 2 ^ 2 = 60
0xFp-2 = 15 x 2^ -2 = 3.75


数值字面量可以添加格外格式增加可读性:

let num1 = 000123.456
let num2 = 1_000_000
let num3 = 1_000_000.000_000_1


---

整数转换要向精度大的一方转换

>```
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let twoThousandAndOne = twoThousand + UInt16(one)

这里注意:UInt16(one)不同于OC中的强转,而是调用了UInt16类的构造函数,该类的构造函数可以接受一个UInt8类型的对象罢了


整型和浮点进行运算,统一先转成浮点,字面量本身没有类型之分,3和1.5是可以直接相加的,但是:
let num1 = 3
let num2 = 1.5
num1和num2就不能直接相加,num1和num2是有类型之分的


给类型取别名

typealias AudioSample = UInt16


Bool 类型:
值是true或false,在需要Bool值的时候如果传入非Bool值,swfit会报错,例如if判断的时候必须是Bool值,这个与OC不同。


元组(tuples)形式和用法都很简单,基本看一下就知道怎么用,元组作为函数的返回值很有用

let http404Error = (404, "Not Found")
let (statusCode, statusMessage) = http404Error
print("The status code is (statusCode)")
let (justTheStatusCode, _) = http404Error
print("The status code is (http404Error.0)")
let http200Status = (statusCode: 200, description: "OK")
print("The status code is (http200Status.statusCode)")


---

###可选:Optional

Swift不允许你声明一个变量,而不对其初始化,这一点OC就很宽泛,但是有时候严格的编译会产生一些问题:
例如,我们都知道VC有个view属性,但是也都知道view属性的赋值并不是在VC初始化的时候进行的,而是在loadView函数中进行的,这在Swift中就是个问题,实际上lazy load或者在声明之后再初始化的场景还是很多的。

Swift如何解决这个问题?答案:可选(Optional,用在类型后面加?表示)

public enum Optional<Wrapped> : _Reflectable, NilLiteralConvertible {
case None
case Some(Wrapped)
//系统源码,忽略下面的代码
}


Optional可选有两个值:None或Some(Wrapped)。

OC中的nil表示缺少一个合法对象,仅用于修饰oc对象,非oc对象用NSNotFound表示,这是Swift与OC很不同的地方,这也体现了swift是编译严格的语言。

let a : Int = 1 //a是一个Int对象(swift这里的设计参照了java一切皆对象的思想)
let b : Int? = 1 //b是一个Optional对象,对象值是Some(Wrapped)因为此时b是赋值了的,而这里的Wrapped指的就是Int
let c : Int? = nil //c是一个Optional对象,对象值是None


![](http://upload-images.jianshu.io/upload_images/1490498-cf6c43f22d4274bd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

c是Optional类型的对象,其实是一个enum,是可以用nil初始化的,其实就是enum中的None,d是一个Int对象是不能用nil初始化的。

###强制拆包!:

通过上面的了解我们知道:一个用?修饰的对象再也不是你想象中的那个对象了,**所有用?修饰的类型所产生的对象都是Optional对象**,这对理解?和!很重要的。
例如:上面例子中的b是一个Int?类型,编译器把他当成是一个Optional对象来处理,而不是Int对象来处理。

![注意看右边的输出](http://upload-images.jianshu.io/upload_images/1490498-fad950063a256c9e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

问题来了:
我用b是要把它当一个Int对象来用,它现在是一个Optional对象怎么用?
答案是:用"!"进行强制拆包(forced unwrapping).就可以得到里面的值,要么是None,要么是Some(Wrapped),在这里,Some(Wrapped)就是Int。

![注意看右边的输出和上面的图对比来理解?和!](http://upload-images.jianshu.io/upload_images/1490498-ba7e3e8576a31ed9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

问题又来了:
!有什么用?
答案,!十分有用,一旦你用?声明声明了一个变量,它就不再是你期望的那个类型了,它是Optional类型了(反复强调了N遍,别嫌烦啊),所以它就**不能和其他类型愉快的玩耍了**。

![](http://upload-images.jianshu.io/upload_images/1490498-dd08610731e947ac.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

a和b仅仅是在声明的时候差了一个?就不能在一起玩耍了,这个时候就要用!强制拆包来解决问题了,我们对可选类型进行拆包后的对象就是我们期望的对象,就可以和其它相同对象一起玩耍了。

![](http://upload-images.jianshu.io/upload_images/1490498-f3dc950e7af978de.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

###可选绑定(optional binding):

>使用*可选绑定(optional binding)*来判断可选类型是否包含值,如果包含就把值赋给一个临时常量或者变量。可选绑定可以用在if和while语句中,这条语句不仅可以用来判断可选类型中是否有值,同时可以将可选类型中的值赋给一个常量或者变量。

if let constantName = someOptional {
statements
}


我们可以通过一个很简单的例子把可选绑定理解的更透彻一点:

![](http://upload-images.jianshu.io/upload_images/1490498-57272568fe5adfa4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

通过例子和programming Language中的说明我们可以做如下推断:
1.我们用 if let tempX = x这种表达的时候,x一定是一个可选类型,否则报错(tempA)
2.if let tempX = x 这种表达形式可以理解成:**判断可选x是否包含值,如果包含值,赋值成功,如果不包含值,赋值失败,赋值成功、失败作为if判断的Bool条件,也就是说if判断的是let tempX = x这个整体,与tempX赋值后是什么类型无关**,这里需要理解一下,还有一点是tempX = x赋值成功后其实并不是单纯的赋值,**x是先拆包后赋值给tempX的**,这对于理解可选绑定很重要(tempB,及其输出信息)。
3.可选绑定的变量或常量只能在if中使用,else中是不能用的(tempC)。

有了上面例子对可选绑定的理解,再理解programming Language中出现的这段代码就比较简单了:

>```
if let actualNumber = Int(possibleNumber) {    
    print("\'\(possibleNumber)\' has an integer value of \(actualNumber)")
} else {    
    print("\'\(possibleNumber)\' could not be converted to an integer")
}

Int(possibleNumber)这种情况上面已经介绍过,就是调用Int类的构造函数,这个构造函数返回的是一个Int?对象,因为用possibleNumber并不一定能保证初始化Int成功,如果possibleNumber="haha"初始化就会失败,所以返回的是Int?而不是Int,理解了这一点,再加上上面可选绑定的例子,这个代码就一清二楚了。

你可以包含多个可选绑定在if语句中,并使用where子句做布尔值判断。

if let firstNumber = Int("4"), secondNumber = Int("42") where firstNumber < secondNumber {
    print("\(firstNumber) < \(secondNumber)")
}
// prints "4 < 42"

隐式解析可选类型:

let a :Int? = 1
我们之前介绍的可选有一个问题,我们实际需要的是Int,但是Int?给我的是一个可选Optional对象,里面包了一个Some(Wrapped)是Int,这使得我们每次用a的时候都要对Optional对象拆包才能用,很是麻烦。
如何解决这个问题?
答案:隐式解析可选类型
隐式解析可选类型:在声明常量或变量的时候用"!"代替"?"就是声明了一个隐式解析可选类型,有点晕?看个例子就清楚了。

我们在用普通可选的时候(就是用?修饰的),每次使用都要拆包,才能用,而隐式解析可选类型不需要,直接就可以用,是不是方便了很多,怎么理解隐式解析可选类型?

有时候在程序架构中,第一次被赋值之后,可以确定一个可选类型总会有值。在这种情况下,每次都要判断和解析可选值是非常低效的,因为可以确定它总会有值。

这是隐式解析可选类型存在的意义。

一个隐式解析可选类型其实就是一个普通的可选类型,但是可以被当做非可选类型来使用,并不需要每次都使用解析来获取可选值。

这是隐式解析可选类型的作用

我们可以理解隐式解析可选类型是对普通可选进行自动拆包,省去了我们手动拆包的麻烦,但是如果一个隐式解析可选类型如果没有值的时候,你去尝试取它的值就会发生运行时错误,就像一个普通可选类型强制拆包(!)但是它却没有值的时候也会发生运行时错误。普通可选和隐式解析可选侧重点不同,前者是安全,后者是方便,如何取舍由自己决定。

我们同样可以在if和while里让隐式解析可选类型和nil进行比较(只有可选类型才能和nil进行比较,因为普通类型的值是不可能是nil的),也可以对其进行可选绑定。

还记得我们引入可选Optional的时候引入的VC的view属性的例子吗,它就是一个隐式解析可选类型

//系统源码
publicvar view: UIView! // The getter first invokes [self loadView] if the view hasn't been set yet. Subclasses must call super if they override the setter or getter.

个人理解:可选、隐式解析可选是swift严编译的一个很好的提现,就这一点来说swift对于提高我们编程的严密性还是有一定帮助的。


Swift中断言和OC差不多

assert(age > 0, "A person's age cannot be less than zero")

断言信息可省略

assert(age > 0)

release环境或者基于release复制出来的新的编译环境下,断言是失效的

总结

作为Swift菜鸟,在死磕Swift的道路上希望多与大家沟通讨论,多向大家学习。

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

推荐阅读更多精彩内容