Swift学习之旅
基本语法
- 不要求每一行结束都有分号
- 运算符不能直接跟在变量或常量后面
- 可自动识别属性类别
- 可选属性声明后没有提供初始值,那么默认值是nil
- 使用操作符!去获取值为nil的可选变量会有运行时错误
而可选类型对所有的类型都可用,并且更安全
Swift和Objective-C对比,新出现关键字
deinit
extension
inout
internal
operator
subscript
typealias
类型别名
typealias Feet = Int
var distance:Feet = 13
类型安全,在编译期间就进行类型检查
变量和常量定义
var 表示是变量,可以修改指针指向
let 表示是常量。
0b 二进制
0o八进制
0x十六进制
var age : Int?
表示age变量默认值是nil
switch
- 这里我们需要注意 case 语句中如果没有使用 fallthrough 语句,则在执行当前的 case 语句后,switch 会终止,控制流将跳转到 switch 语句后的下一行。
如果使用了fallthrough 语句,则会继续执行之后的 case 或 default 语句,不论条件是否满足都会执行。
字符串
var test = String("Hello world")
if test.isEmpty { //todo } 判断字符串是否为空
let stringA = String("haha")
stringA += "wawa" // 编译出错,let标识常量,不能修改
- 字符串长度使用 String.characters.count 属性来计算
- Int(String),转换字符串数字为整型
字符Character
- let char: Character = "AB" // 会报错
- let char1: Character = "" // 同样报错
数组
- Array
用var 修饰的数组时可变数组,反之用let声明的则是不可变数组。
var mutableArray : Array<String> = ["xixi", "haha", "hoho"];
var mutableArray1 : [String] = ["xixi", "haha", "hoho"];
var emptyArray = [String]();
let unMutableArray = Array<String> = ["xixi", "haha", "hoho"];
- 初始化数组
var someInts = [Int](repeating: 0, count: 3)
var someInts[Int] = [1,2,3]
- 添加元素,append或+=
- 遍历
for (index, item) in someStrs.enumerated() {
print("在 index = \(index) 位置上的值为 \(item)")
}
- 合并 +
- 数组个数 count
元组
- 返回一个元组类型
func minMax(array:[Int])->(min:Int,max:Int)
- 可选元组类型如(Int, Int)?与元组包含可选类型如(Int?, Int?)是不同的.可选的元组类型,整个元组是可选的,而不只是元组中的每个元素值。
字典
- 定义
var someDict:[String:Int] = ["A":1,"B":2]
var someDict = [String:Int]()
- 更新
someDict.updateValue(3, forKey: "A")
- 删除
someDict.removeValue(forKey: 2)
函数
- 如果为函数的参数指定默认值,则在调用函数时可以不传对应的参数
func makeCoffee(type : String = "卡布奇诺") {
print(type);
}
makeCoffee() // 打印结果 卡布奇诺
makeCoffee(type: "拿铁") // 打印结果 拿铁
- 内部参数
func test(name:String, age:Int)->String {}
- 外部参数,如果你提供了外部参数名,那么函数在被调用时,必须使用外部参数名
func test(myName name:String,myAge age:Int)->String {}
- inout 参数标识 和 c的指针一样
func swap(_ a:inout Int, _ b:inout Int) { }
var x = 1; var y = 5
swap(&x, &y)
- 函数类型(什么?!这是js吗)
func add(a:Int, b:Int)->Int {
return a + b
}
var addition:((Int, Int)->Int) = add
print(addition(1,2))
类
Swift 中的类并不是从一个通用的基类继承而来。如果你不为你定义的类指定一个超类的话,这个类就自动成为基类。
可选链
可以通过连接多个可选链式调用在更深的模型层级中访问属性、方法以及下标。然而,多层可选链式调用不会增加返回值的可选层级。
如果你访问的值不是可选的,可选链式调用将会返回可选值。
如果你访问的值就是可选的,可选链式调用不会让可选返回值变得“更可选”。
因此:
通过可选链式调用访问一个Int值,将会返回Int?,无论使用了多少层可选链式调用。
类似的,通过可选链式调用访问Int?值,依旧会返回Int?值,并不会返回Int??。
扩展
添加计算型属性和计算型类型属性
定义实例方法和类型方法
提供新的构造器
定义下标
定义和使用新的嵌套类型
使一个已有类型符合某个协议
可选的协议要求
协议可以定义可选要求,遵循协议的类型可以选择是否实现这些要求。在协议中使用 optional
关键字作为前缀来定义可选要求。可选要求用在你需要和 Objective-C 打交道的代码中。协议和可选要求都必须带上@objc
属性。标记 @objc
特性的协议只能被继承自 Objective-C 类的类或者 @objc
类遵循,其他类以及结构体和枚举均不能遵循这种协议。
使用可选要求时(例如,可选的方法或者属性),它们的类型会自动变成可选的。比如,一个类型为 (Int) -> String
的方法会变成 ((Int) -> String)?
。需要注意的是整个函数类型是可选的,而不是函数的返回值。
协议中的可选要求可通过可选链式调用来使用,因为遵循协议的类型可能没有实现这些可选要求。类似 someOptionalMethod?(someArgument)
这样,你可以在可选方法名称后加上 ?
来调用可选方法。详细内容可在可选链式调用章节中查看。
下面的例子定义了一个名为 Counter
的用于整数计数的类,它使用外部的数据源来提供每次的增量。数据源由 CounterDataSource
协议定义,包含两个可选要求:
@objc protocol CounterDataSource {
@objc optional func incrementForCount(count: Int) -> Int
@objc optional var fixedIncrement: Int { get }
}
访问控制
模块和源文件
- 在 Swift 中,Xcode 的每个 target(例如框架或应用程序)都被当作独立的模块处理。如果你是为了实现某个通用的功能,或者是为了封装一些常用方法而将代码打包成独立的框架,这个框架就是 Swift 中的一个模块。当它被导入到某个应用程序或者其他框架时,框架内容都将属于这个独立的模块。
- 源文件就是 Swift 中的源代码文件,它通常属于一个模块,即一个应用程序或者框架。尽管我们一般会将不同的类型分别定义在不同的源文件中,但是同一个源文件也可以包含多个类型、函数之类的定义。
- 一个 public 类型的所有成员的访问级别默认为 internal 级别,而不是 public 级别。如果你想将某个成员指定为 public 级别,那么你必须显式指定。这样做的好处是,在你定义公共接口的时候,可以明确地选择哪些接口是需要公开的,哪些是内部使用的,避免不小心将内部使用的接口公开。
- 我们甚至可以在子类中,用子类成员去访问访问级别更低的父类成员,只要这一操作在相应访问级别的限制范围内(也就是说,在同一源文件中访问父类 private 级别的成员,在同一模块内访问父类 internal 级别的成员)
自定义运算符
当使用自定义运算时, 传入的参数至少要有一个当前对象, 否则编译不会通过。定义前缀或后缀运算符时,不要指定优先级。但是,如果将前缀和后缀运算符应用于相同的操作时,则首先进行后缀运算。