为了账号安全,请及时绑定邮箱和手机立即绑定

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

标签:
iOS

引言

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_000let one: UInt8 = 1let 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)")

---###可选:OptionalSwift不允许你声明一个变量,而不对其初始化,这一点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的道路上希望多与大家沟通讨论,多向大家学习。

欢迎大家和我交流沟通,文章中有任何错误和漏洞,恳请指正,谢谢。




点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
移动开发工程师
手记
粉丝
3
获赞与收藏
10

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消