前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Swift学习总结

Swift学习总结

原创
作者头像
SheltonWan
修改2019-08-04 11:07:35
2.9K0
修改2019-08-04 11:07:35
举报

1、var 声明变量,let 声明常量,变量会根据上下文识别类型。

2、溢出操作符——&+,&-,&*,Swift的哲学是触发陷阱比潜在安全漏洞要好

3、字符串支持插值\(var)占位符,支持复合赋值操作符+=连接字符串

4、swift必须手动转换类型,不会自动类型转换,譬如int8+int16会报错

5、switch语法与objc差别很大,执行一个分支马上停止,不需要break语句跳出,反而想要穿透到下面分支还要用fallthrough语句。

switch语句每一个分支不能空操作。

Switch既支持一个值与给定值比较,也支持多个值与给定值比较,还支持区间值与给定值比较,多个值用逗号分隔,区间则用三个点…来界定。

switch支持值绑定,在case语句中声明变量或常量,其值绑定为状态码的值。switch绑定值可以配合where语句使用,能额外检查一些条件,这个特性可以创建动态筛选条件。

譬如:

case let boy as Boy://Boy is class

Case let name where name.contain(“wan”)

6、元组——具有逻辑关联的两个或多个值的有限组合,支持索引访问,也可以命名访问,如:

var statusCode

var errorString

let error = (code:statusCode, description:errorString)

元组可以在switch的区间匹配中应用,下划线_可用作通配符,匹配任何值。

7、if-case 语法 为只有一个分支的switch语句提供优雅的替代品。

8、区间既可在switch语句中匹配使用,也可以在for-in循环中使用。

9、通配符_既可以在switch语句使用,也可以在for-in语句中替代迭代器,这样就可以忽略迭代器。

10、for-in循环支持where子句,如 for i in 1…100 where I%3==0 { }

Where子句是用来替代for-in中的if条件判断,使代码看起来更优雅,是可替代的。

11、类型推断——根据上下文推断出实例的类型,不需要显式声明。有些情况下需要明确声明类型,但一般来说,建议尽量利用类型推断。

12、repeat-while替代了do-while

13、导入framework方式如: import Cocoa

不需要#符号,也不需要双引号“”或者尖括号<>

14、字符串双引号前不需要@符号

15、每个字符串都是一个String对象,虽然其本身不是一个集合,但是其底层内容确实以集合的形式存在,字符串的characters属性表示组成这个字符串字符集合。

组成字符串的每个字符也是一个Character对象。

16、\u{}表示Unicode标量,十六进制数放在花括号里。每个字符都有一个或多个Unicode标量构成。一个Unicode标量对应一个基本字符。

多个 Unicode标量构成的字符为组合标量,通常也有有单个标量表示形式,而且其等价。

对于两个字符或者两个字符串,如果它们具有相同的语言学含义和外观,无论是否用相同的Unicode标量创建,都认为两者相等。

标准等价意味着无论用组合标量还是预组合标量,结果都会被当做单个字符。

17、swift不允许直接用索引下标[]来访问字符串中的指定字符,因为swift无法在不遍历前面每个字符的情况下知道指定的索引对应于哪个Unicode标量,该索引必须要先获取到start索引,再通过编译计算到指定索引。

18、swift任何类型都可以用可空类型来说明一个实例可能是nil,而objc-c只允许对象是nil

19、声明实例变量时,在类型后跟随问号?,则表示该变量是可空类型,可以为nil,也可以赋了值。

20、实例变量后跟随感叹号!,其作用是强制展开,无论实例变量是否有值,都会访问封装的值。感叹号!假设有这样一个值,如果没有,这样展开会产生运行时错误。

string实例变量和string!实例变量不是相同的类型——如果你有一个String变量,就无法在不展开可空实例的情况下将String?的值赋予给这个变量。

21、可空实例绑定——如果有值,就将其值赋予一个临时常量或变量,并且使这个常量或变量在条件语句第一个分支代码中可用。其语法与在条件语句中创建常量或变量一致,只是不需要再强制展开可空实例了,这个操作自动完成。

If let Instance = nilInstance, let Instance = nilInstance {}

22、声明实例变量时,在类型后跟随感叹号!,则表示该变量是隐藏式展开可空类型。隐式展开可空类型与普通可空类型重要区别就是不需要展开,使用上不需要if条件语句了。如果这种隐式展开可空类型没有值的话,访问其值会直接导致运行时错误。建议如果某个实例可能为nil,就不要使用隐式展开可空类型。

23、实例后面跟问号?——可空链式调用,与可空实例绑定类似,两者重要区别是,可空链式调用允许把多个查询串联为一个可空实例的值。

24 、感叹号跟在实例后面,其作用就是断言实例不为空,若真为空就崩溃,相当断言效果。

25、nil合并运算符??类似三目操作符?:

26、guard语句和if语句有点类似,都是根据其关键字之后的表达式的布尔值决定下一步执行什么。但与if语句不同的是,guard语句只会有一个代码块,不像if语句可以if else多个代码块。

那么guard语句的作用到底是什么呢?顾名思义,就是守护。guard语句判断其后的表达式布尔值为false时,才会执行之后代码块里的代码,如果为true,则跳过整个guard语句。guard语句中声明的实例可以在整个方法作用域中使用。

其语法:

guard 布尔表达式 case{ 执行代码 }

——————————————————————————————————————————————————————————

1、swift的Array类型可以持有任何类型的值——对象和非对象都可以。

2、声明数组主要有两种语法,数组实例也支持类型推断

var bucketList:[String]

var friends:Array<String>

var weeks = ["Monday","Tuesday"] ——字面量语法

var array = Array<String>()

var array = [Int]()

集合Set语法与数组一致

3、声明字典语法,支持类型推断

var dict1:Dictionary<String,Double> = [:]

var dict2 = Dictionary<String,Double>()

var dict3:[String:Double] = [:]

var dict4 = [String:Double]()

var dict5 = [“name”:”shelton”,”age”:]

Swift与obj-c的字典区别,就是简化赋值objc用大括号{},swift用中括号[]

4、集合Set是无序,储存元素唯一,数组有序,储存元素可以重复,字典无序,但键值唯一。

5、Swift函数支持嵌套,用元组语法来支持返回多个值,支持变长参数,支持参数带默认值。函数还允许有外部名与内部名。元组也可以作为函数参数

6、闭包就是objc中的Block

闭包语法:

{(参数)->返回类型 in

//代码

}

闭包可以利用swift的类型推断系统去除参数和返回值的类型信息来简化闭包。

如果闭包代码只有一行表达式,return关键字也可以省略。

闭包甚至可以利用快捷参数名来替代显式声明的参数,做到剔除参数声明来简化闭包。$0表示第一个参数,$1表示第二个参数。

尾部闭包语法甚至可以省略掉方法的圆括号。

闭包和函数能记录在其闭合作用域中定义的变量所封装的内部信息。

闭包是引用类型。

func greeting(_ greeting:String) -> (String)->String {

return { (name:String) -> String in

return "\(greeting) \(name)"

}

}

上面函数,有一个String参数,结果返回一个函数,不需要通过嵌入函数来实现,用闭包可以简化之。

7、枚举Enum语法上多了case关键字,支持一系列类型,包括所有的内建数值类型和字符串。在swift中,方法可以和枚举关联,即在枚举中添加方法。

在swift中,枚举是值类型,而值类型的方法不能对self进行修改,如果希望值类型方法能修改self,需要标记这个方法为mutating。

Swift的枚举,除了像其它语言那样定义一些静态的成员值来枚举可能的状态,还提供了一种强大的特性,可以定义带关联值的成员。关联值能让你把数据附在枚举实例上,不同的成员可以有不同类型的关联值。

在枚举中,如果带有递归关联值成员,需要关键字indirect,否则报错。

枚举语法:

enumname.enumvalue. 或者 .enumvalue

8、创建项目中,入口文件main.swift没有main函数

在main.swift 创建其它文件的结构或类,不需要import对应文件

9、结构体Struct也是可以声明自己的方法,但是若方法要修改结构体的属性,需要用关键字mutating标志,因为结构体和枚举都是值类型。

10、类与结构体的区别之一,支持继承,在重载父类方法的时候要添加override关键字

Swift的类有个新特性,可以禁止子类重载某个函数,在该函数增加final关键字。如果我们在声明一个类时,在class前加上final修饰符,则表示禁止类被继承。

11、结构体和类都支持类方法(c++的静态方法),但是结构体需要在方法前用static标记,而类则用class标记该方法。用class标记的类方法可以由子类重载,想要子类不能重载,则需要用static标记。也就是类和结构体都支持static关键字标记类方法,但该方法不支持重载。当然也可以用final class来标记类方法。

12、属性分存储属性和计算属性。

存储属性用来存储数据,可以是只读属性,也可以是读写属性,只读属性用let声明。

swift增加一个惰性存储属性概念,用lazy关键字修饰,惰性储存属性的值只在第一次访问的时候才会出现,因为它依赖类型的外部因素,必须要满足某些前提条件才能计算得到。注意,标记为lazy的属性只会被计算一次。

只读的计算属性用var来定义,与只读得存储属性不同。计算属性的类型必须显式声明

针对objc的kvo,swift提供一种特性——属性观察,但计算属性不能用。

13、与类方法类似,有类属性,用class标记的属性子类可以重载自定义,用static标记的子类不可以重载修改。枚举,结构体和类都支持类属性。

类计算属性与类方法很类似,区别是一个用关键字var,另一个用func,类计算属性没有圆括号。

计算属性如果没有写入方法,可以省略定义中的get。

子类要重载类计算属性,同样要标记override。

14、swift提供了 open、public、internal、fileprivate、private五层访问控制。objc没有这些访问限制。

private:访问级别所修饰的属性或者方法只能在当前类里访问.(注意:Swift4 中,extension 里也可以访问 private 的属性。)

fileprivate:访问级别所修饰的属性或者方法在当前的 Swift 源文件里可以访问。

internal 访问级别所修饰的属性或方法在源代码所在的整个模块都可以访问。如果是框架或者库代码,则在整个框架内部都可以访问,框架由外部代码所引用时,则不可以访问。如果是 App 代码,也是在整个 App 代码,也是在整个 App 内部可以访问。

public: 可以被任何人访问。但其他 module 中不可以被 override 和继承,而在 module 内可以被 override 和继承。

open: 可以被任何人使用,包括 override 和继承。

15、swift中的初始化方法意义和c++的构造函数类似。与普通方法类似,但是没有func关键字标记,也没有返回值,用init关键字做方法名,参数个数可变。

结构体提供了一种默认的初始化方法,会将所有属性都作为参数。与结构体不同,类没有默认的成员初始化方法。

在方法实现中,属性如果遇到同名参数才需要指定self,不然则不需要。

在初始化方法中允许给常量赋值,其它方法则不允许。

16、初始化增加了两个概念:指定初始化和便捷初始化,便捷初始化需要在init前加上关键字convenience。还有一个required关键字不能忽略,表示子类必须重载该指定初始化方法,只是不用override关键字,而是用required关键字。便捷初始化参数可以灵活不需包含所有属性,且内部必须要调用到一个指定初始化方法。

在创建Swift对象,可以类似:var obj = classname.init(), 也可以类似:var obj = classname(),括号里的参数与init实现一致。

17、反初始化就是c++中的析构函数思想,也相当于objc的dealloc,在实例被清除出内存钱会调用到。

18、初始化还有个概念可失败初始化,其实就是可空实例关联的东西,其语法需要再init后跟随一个问号,也可以跟随一个感叹号。感叹号表示返回隐式展开可空类型实例,其使用起来方便(不需要写可空类型展开的语法),但不如跟随问号安全。

19、在被赋给另一个实例或是作为参数传递给函数时,值类型总是被复制。

String,Int, Array, Dictionary等是Struct,是值类型。

Class是引用类型。

声明为常量的值类型不能改变属性,即使属性在类型实现中是用var声明也一样。但是声明为常量的引用类型实例的属性却可以被修改。

建议不要在值类型内使用引用类型,确实需要再结构体内使用引用类型,最好使用不可变的实例。

我们预期,当把值类型实例赋给新变量、常量或传递给函数时,实例会被复制。但是,若值类型内有引用类型,副本实例和原来实例中引用类型实例还是指向同一个实例,改变这个引用实例,副本实例中的引用实例也会被影响。

值类型内的引用类型属性在复制时只是浅拷贝,并不会创建新的实例,而是指向同一个实例。

20、理解相等与同一的概念,相等通常是指俩实例的内容相等,同一是指俩实例指向内存中同一个实例。基本数据类型String、Int、Double、Float、Array、Dictionary都可以检查相等性。新增语法===来检测俩实例的同一性,但值类型不能用同一性检查。类实例若要判断相等性==,则需要实现协议Equatable。

21、关于值类型的复制行为,swift语言提供了一种写时复制的特性。在某个实例需要修改或写入存储时,该实例才会产生一份自己的副本,在这之前,它们会维护自己对同一份存储的引用。

因此我们在赋值或将实例作为参数传递时,在它们没被修改或写入存储时,它们还是对同一份存储进行引用。这样值类型就可以避免创建多余的数据副本。

——————————————————————————————————————————————————————————

1、协议关键字protocol

与objc的协议区别,多了计算属性支持,不过计算属性也可以理解成方法。

某个类型符合协议,或者说遵循某个协议,其语法与继承一样,都是类型名称后 +冒号+协议名称。

当我们添加协议后,会有错误警告,通过Fix修复错误会自动把协议需要实现的方法自动列出来,不需要我们一一写。

所有类型都支持协议,枚举,结构,类都可以符合协议

与objc一样,可以符合多个协议

与objc不一样的地方是,swift的协议支持继承,还可有多继承。

如果协议中声明的方法在值类型实现中需要修改self,注意要方法前标记mutating。

这里的多继承协议,有点类似c++的抽象类了

你可以在协议的继承列表中,通过添加 class 关键字来限制协议只能被类类型遵循,而结构体或枚举不能遵循该协议。class 关键字必须第一个出现在协议的继承列表中,在其他继承的协议之前 。

2、assert与precondition的区别是,assert在release版本被编译器优化删除,而precondition在debug版本和release版本效果一致

3、Swift在可能抛出异常的函数声明中加上关键字throws,该关键字在函数参数与->之间。

遇到可能会抛出异常的方法,必须要用do catch语法来捕获异常。

do {

try//用try关键字标记存在异常的方法

} catch {

//在这里我们可以

}

Swift允许二次抛出异常,在调用可能存在异常的方法时,用try标记,但是可以不用do catch,而是让当前方法声明上标记throws达到可以支持二次抛出异常。

总结如下:必须用try标记每次调用可能抛出异常的函数,而任何try标记的调用必须要么在do catch语句块内,要么在一个本身被标记为throws的函数内。

不过也有个例外,可以在try后面跟随感叹号。与强制展开可空实例一样,一旦出现错误程序就会崩溃。该用法谨慎使用,少用。

还有第三种情况,可以用try? 调用一个可能抛出异常的函数,得到函数原本的返回值对应的可空类型返回值。发生错误的时候忽略错误而不触发陷阱。常用于有后备函数可用,且配合guard关键字使用。

4、swift对应objc中的category的语法关键字是extension,枚举、结构体、类都支持extension。其用法基本跟objc的category类似,都不支持存储属性,但是支持计算属性,支持protocol,支持增加方法,支持添加嵌套类型,支持新初始化方法。

5、swift把c++中的模板特性引入,称为泛型。其语法如下

type TypeName <Element> { //type可以是struct,也可以是class或者enum等

}

用法:

var a = TypeName <Element>()

枚举、结构体、类和函数都支持泛型。

在实现泛型的时候,对于一些无法预知的类型,其某些功能不知道是否支持的情况下,通过增加泛型约束来实现。有两种类型约束:一种是类型必须是给定类的子类,还有一种是类型必须符合一个协议或者协议组合,具体语法:尖括号里的类型+冒号+协议。

协议是不可以直接支持泛型的,不过协议支持一个相关特性:关联类型,参考如下:

protocol IteratorProtocol {

associatedtype Element

mutating func next() -> Element?

}

protocol Sequence {

associatedtype Iterator: IteratorProtocol

func makeIterator() -> Iterator

}

在实现泛型的时候,有可能一个泛型约束不够,还需要where子句来进行更多的约束。代码参考:

mutating func pushAll <S:Sequence> (_ seq:S) where S.Element==Element {

for item in seq {

self.push(item)

}

}

关于多态的特性,用继承,或协议,或泛型都可以支持。

6、swift新特性,除了枚举、结构、类支持extension扩展,协议也可以进行扩展,可以添加有实现的计算属性和方法,只是不能添加存储属性。

之前提过协议是支持继承,且多继承,在实践过程中,我们给一个协议A补充从另外一个协议B继承,这个时候我们发现我们已经有多个实现是从符合A协议的,正常情况,需要我们在每个实现中补充B协议的实现。但是有了协议扩展extension的特性,我们不需要这么做,仅仅通过extension A来补充B的方法实现则可。当然,如果我们硬是要在单个实现中补充B协议的实现是可以的,且其优先级会高于协议的扩展,会覆盖协议的扩展方法。

有个地方要小心了,如果我们单纯扩展协议增加一个计算属性或方法,又在具体类型实现了同名的计算属性和方法,这些方法和计算属性因为不是协议必须的,所以会有预期不到的结果,编译器并不会检测实际的类型,而是遵循我们我们提供的类型信息。

7、swift内存管理采用ARC(自动引用计数)

默认情况下创建的类实例是强引用,可用关键字week声明为弱引用。弱引用必须是var声明,且可空。

在实际应用中,注意避免循环引用。在使用闭包的时候也要注意循环引用。闭包增加分逃逸闭包和非逃逸闭包两个概念,通常闭包作为参数传给函数时,是非逃逸闭包,这种闭包编译器可以确定不会造成循环引用,而作为类型的属性这种闭包是逃逸闭包,这种闭包就容易引起循环引用。在使用的时候要使用捕获列表来避免循环引用。捕获列表语法如下:[weak self]:

注意,混合使用逃逸闭包和非逃逸闭包是会编译错误的,如果要避免错误,可以用

@escaping属性来修复这个错误。

Swift是不可以访问实例的引用计数,但是有个函数(isKnownUniquelyReferenced)可以判断一个实例是否是对某个实例的唯一引用。

————————————————————————————————————————————————————————————————————

1、Object C中 @selector语法换成#selector

2、Swift中类型转换用关键字as,as?, as!三种语法

3、ObjC中的 #pragma mark 用 #MARK替代

4、ObjeC中有id表示任意对象,Swift中AnyObject 可以代表任何 class 类型的实例,Any 可以表示任意类型,甚至包括方法(func)类型

5、.self 用在类型后面取得类型本身,用在实例后面取得实例本身

其中第2个用法,获取实例本身一般直接通过init方法创建即可,所以这种用法不推荐使用。

此外,这里的 .self 和协议、类方法中的 Self 完全不同。注意区分

6、通过 AnyObject.Type 这种方式得到的就是一个元类型,也就是 AnyClass。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档