Swift 基础小结
-
在 Swift 中使用
var
和let
分别声明变量和常量,至于类型,则可以通过后面的初始值信息进行推断,或者直接在变量名后进行指定。var str = "string" let num: Int = 0 var isOpen: Bool
这种不同于 OC 的声明书写格式,是否会觉得有点不习惯呢,但是鉴于其自动推断类型的强大功能,通常我们是可以省略类型说明的,书写起来会更加便捷。
使用反引号可以将关键字指定为变量名称,但是不提倡这样做。
let `var` = "var" print(`var`)
-
在 Swift 中值的类型转换必须是显示的,如下面将字符串转换为整型:
let str = "2" let num = 3 let result = Int(str)! + num
如果
Int(str)
强制转换失败,那么可选值结果为nil
,此时进行强制解包则会报错。 -
数组和字典的声明更佳便捷,同样可以省略类型说明。
let array = [String]() let dic = [String:Int]() let array = ["str1","str2"] let dic = ["1":1,"2":2]
数组和字典的声明如此相似,是否可以将字典看作是元素是键值对的无序数组呢,并且元素的类型可以是诸如
Int
的基本类型,相对于 OC 是不是帮了大忙了! -
在 Swift 中不再支持 C 语言中的
for
语句循环,如打印 0 到 9 ,使用如下写法是无法编译通过的:for(int i = 0;i<10;i++) { print(i) }
但是这里引入了范围表达式:
..<
和...
,分别表示不包括上界限和包括上界限的范围,所以有如下写法:for i in 0..<10 { print(i) }
-
另外,
do-while
循环则修改为了repeat-while
循环,当然,while
循环还可以使用。 -
for-in
循环进行了强化,临时变量无需声明类型且可以是元组类型。for (key,value) in ["2":2] { print(key,":",value) }
-
对于条件语句而言,判断条件必须是布尔表达式,不会在隐式的将数值同 0 进行比较或判断可选类型是否为 nil ,并且包裹判断条件的圆括号可以省略。
let num = 3 if num > 0 { print(num) }
不过,对于可选类型,这里提供了一种书写方式,将判断其是否是 nil ,然后再去进行解包合为一步,也称为可选绑定。
let str: String? = "5" if let temp = str,let num = Int(temp),num == 5 { print(num) }else if let num = Int("5") { print(num) }
如果可选值有值,则将值赋给临时变量,而后执行下面的语句,如果为 nil ,那么则跳过下面的语句。
需要注意的是,这种写法必须要省略圆括号。
-
在 Swift 中使用
switch
选择分支时,如果将所有的情况都列出了,则可以省略default
选项。如果无法列出所有的可能项,则需要使用default
默认项。let str = "Test Str" switch str { case "Test": print("content : \(str)") case "Test Str1": print("content : \(str)") case let x where str.hasPrefix("Test"): print("x : \(x)") default: print("default") }
switch 中可以比较的值不在限于整型值,其他类型也可以,而且还可以使用
where
关键字来添加限定条件。 -
使用
struct
关键字定义结构体,其和类一样,可以声明变量、方法和构造器,但是其同类有个重要区别,就是类实例传递时,传递的是引用,而结构体传递的是值。protocol Named { var name: String { get } } protocol Aged { var age: Int { get } } struct Person: Named, Aged { var name: String var age: Int }
结构体可以遵循协议,但是不能继承结构体。
-
使用
enum
关键字定义枚举类型,除了使用case
定义枚举值外,还可以定义方法,但是不能定义存储属性。而且,枚举值除了其原始值外,还可以有不同的关联值,相同原始值的枚举实例变量如果关联值不同,那么这两个枚举变量是不相等的。enum EnumTest { case tt1(str: String,num: NSNumber) case tt2(str: String,num: NSNumber) case tt3(str: String,num: NSNumber) func test() { switch self { case .tt1(str: "str1", num: NSNumber.init(value: 1)): print(self) case .tt1(str: "str1", num: NSNumber.init(value: 2)): print(self) case .tt1(let str, let num): print(str,num) case .tt2(str: "str2", num: nil): print(self) case .tt3(str: "str3", num: nil): print(self) default: print(self) } } } let enumT1 = EnumTest.tt1(str: "str1", num: NSNumber.init(value: 1)) enumT1.test()
如果需要通过
:
指定枚举的原始值,那么该原始值类型需要遵循RawRepresentable
协议。枚举同样不能继承枚举,但同样可以遵循协议。 -
使用
protocol
关键字来定义协议,类、枚举、结构体都可以遵循协议,并且如果协议会被结构体实现,且其中定义的函数需要修改结构体中的属性,那么需要使用mutating
关键字来修饰该函数,来表明这是一个可以修改结构体属性的函数,而类函数本身就可以修改属性,则不需要额外标记。 -
可以使用
extension
关键字来扩展某个类型,声明其遵循某个协议。 -
类如果继承其他类,那么其遵循的协议要写在继承的类之后。
-
声明函数时,可以指定参数类型为遵循某一协议的任意类型,遵循多个协议的类型使用
&
进行连接。func test(para: Named&Aged){ }
-
闭包是自包含的函数代码块,可以在代码中被传递和使用,全局函数和嵌套函数实际上是特殊的闭包。
-
使用
@escaping
来声明一个闭包是逃逸闭包,即作为参数传递给函数的闭包,可以在该函数执行结束之后进行调用,常用于异步操作。在逃逸闭包中,是不可以隐式引用self
的,必须显示地引用。var completionHandlers: [() -> Void] = [] func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) { completionHandlers.append(completionHandler) } someFunctionWithEscapingClosure { print(self.completionHandlers.count) } completionHandlers[0]()
-
自动闭包不接受参数,但是可以有返回值。如果一个函数的参数是一个闭包,那么使用
@autoclosure
进行修饰后,调用该函数时,其必须接收一个非闭包参数并自动将其转换为闭包。var customersInLine = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] func serve(customer customerProvider: @autoclosure () -> String) { print("Now serving \(customerProvider())!") } serve(customer: customersInLine.remove(at: 0))
并且此时,如果传递闭包参数
serve(customer: {customersInLine.remove(at: 0)})
是会报错的。 -
在 Swift 中可以使用泛型来表示函数的参数为任意类型,而且需要使用
inout
修饰参数,来表示参数是可以被修改的。public func swap<T>(_ a: inout T, _ b: inout T)
-
函数、方法、类、枚举、结构体都可以使用泛型。使用泛型时,还可以限定其必须是某个类的子类或必须实现某个协议,还可以使用
where
子句来添加额外的约束条件。func allItemsMatch<C1: Container, C2: Container> (_ someContainer: C1, _ anotherContainer: C2) -> Bool where C1.ItemType == C2.ItemType, C1.ItemType: Equatable protocol Container { associatedtype ItemType mutating func append(_ item: ItemType) var count:Int { get } subscript(_ index:Int)->ItemType { get } }
对于
allItemsMatch
函数而言,其接收的两个参数必须都遵循了Container
协议,而且关联的类型ItemType
必须遵循Equatable
协议。 -
在定义类的实例变量或方法时,可以使用关键字
static
或class
,但是在协议、结构体或扩展中,只能使用static
关键字。如此,当类遵循的某个协议中使用static
定义了一个变量,那么该类在实现该协议时,使用static
或class
声明该变量都可以。 -
在 Swift 中,使用
typealias
关键字取代typedef
关键字,定义类型别名。typealias Int_16 = Int16