結(jié)構(gòu)與枚舉
認(rèn)識(shí)結(jié)構(gòu)(struct)
struct屬于值類(lèi)型,具有拷貝語(yǔ)義(賦值和傳參)
struct不支持面向?qū)ο螅饕糜诙x輕量級(jí)數(shù)值類(lèi)型;class支持面向?qū)ο螅饕糜谠O(shè)計(jì)有豐富關(guān)系的組件系統(tǒng)(有繼承、多態(tài)等復(fù)雜設(shè)計(jì)模式)。
struct有傳參拷貝成本,不要定義尺寸過(guò)大的結(jié)構(gòu);class有ARC內(nèi)存管理成本。
不要再struct內(nèi)定義引用類(lèi)型屬性(會(huì)改變struct的值拷貝語(yǔ)義)。
class RPoint{
var x:Int
var y:Int
init(x:Int, y:Int){ //class的初始化器,必須寫(xiě)。
self.x=x
self.y=y
}
deinit{
print("clean up")
}
}
struct SPoint{
var x:Int
var y:Int
var z:RPoint
}
var rp=RPoint(x:10, y:20)
//struct有默認(rèn)按成員初始化器
var sp1=SPoint(x:10, y:20, z: RPoint(x: 100,y: 200))
var sp2=sp1
print(" \(sp1.x), \(sp1.y), \(sp1.z.x), \(sp1.z.y)") //" 10, 20, 100, 200\n"
print(" \(sp2.x), \(sp2.y), \(sp2.z.x), \(sp2.z.y)") //" 10, 20, 100, 200\n"
sp1.x+=10
sp1.y+=10
sp1.z.x+=10
sp1.z.y+=10
print(" \(sp1.x), \(sp1.y), \(sp1.z.x), \(sp1.z.y)") //" 20, 30, 110, 210\n"
print(" \(sp2.x), \(sp2.y), \(sp2.z.x), \(sp2.z.y)") //" 10, 20, 110, 210\n"

struct VS class
相同點(diǎn):
都可以定義一下成員:屬性、方法、下標(biāo)、初始化器。
都支持類(lèi)型擴(kuò)展、協(xié)議。
不同點(diǎn):
類(lèi)支持繼承和多態(tài),結(jié)構(gòu)不支持。
類(lèi)必須自己定義初始化器,結(jié)構(gòu)會(huì)有默認(rèn)的按成員初始化器
類(lèi)支持析構(gòu)器,結(jié)構(gòu)不支持
類(lèi)的實(shí)例在對(duì)上,由ARC負(fù)責(zé)釋放;結(jié)構(gòu)的實(shí)例在棧上,棧結(jié)束會(huì)自動(dòng)釋放,不參與ARC管理。
類(lèi)支持引用相等比較(===與!==),結(jié)構(gòu)不支持
認(rèn)識(shí)枚舉(enum)
enum用于定義一組相關(guān)的值成員,enum同屬于值類(lèi)型,具有拷貝語(yǔ)義(賦值與傳參)。
//定義枚舉類(lèi)型,換行每一行都要用case
enum Color {
case Red
case Green
case Blue
}
//或者可以不換行,用一個(gè)case就可以
enum ComplexColor {
case Red,Green,Blue,Alpha
}
//枚舉實(shí)例的使用
var c1 = Color.Red
var c2:Color
c2 = .Green //也可以寫(xiě)成 c2 = Color.Green
可以使用switch-case語(yǔ)句處理enum,但case必須包含所有的枚舉值,否則需要用default。
func print (color: Color) {
switch color {
case .Red:
print("Red Color!")
case .Green:
print("Green Color")
}
}
可以為enum指定原始值,即raw value, 類(lèi)型可以是字符、字符串、整數(shù)、或者浮點(diǎn)數(shù)。數(shù)值默認(rèn)從0開(kāi)始,字符串與枚舉值名稱(chēng)相同。
//指定原始類(lèi)型。默認(rèn)從0開(kāi)始,這里設(shè)置Monday = 1那么就從1開(kāi)始了
enum WeekDay: Int {
case Monday = 1, Tuesday, Wednesday, Thursday, Friday, Satutday, Sunday
}
//用原生值來(lái)初始化,rawValue是默認(rèn)值
var day: Weekday?
day = WeekDay(rawValue: 7)
//獲取一個(gè)rawValue
var data = WeekDay.Saturday.rawValue
enum支持關(guān)鍵值,可以設(shè)置不同類(lèi)型的值成員,類(lèi)似聯(lián)合數(shù)據(jù)結(jié)構(gòu)
//枚舉關(guān)聯(lián)值
class Point {
var x=0
var y=0
init(x:Int, y:Int) {
self.x = x
self.y = y
}
}
enum Position {
case Number(Point)
case Name(String)
}
var p1 = Position.Number(Point(x: 123, y: 588))
var p2 = Position.Name("Shanghai People's Square")
//不同類(lèi)型的值成員枚舉類(lèi)型的使用,根據(jù)不同的類(lèi)型做出不同的操作
func print(position: Position) {
switch position {
case .Number (let number):
print("[\(number.x), \(number.y)]")
case .Name (let name):
print(name)
}
}
enum還可以定義以下成員:計(jì)算屬性、方法、初始化器。
//定義計(jì)算屬性、方法、初始化器
enum Sex {
case Male
case Female
//初始化器
init? (symbol: Character) {
switch symbol {
case "M"
self = .Male
case "F"
self = .Female
default:
return nil
}
}
stactic var Default: Sex {
return Sex.Male
}
func show () {
switch self {
case Male:
print("I am Male")
case Female:
print("I am Female")
}
}
}
var sex = Sex.Female
sex.show()
var defaultSex = Sex.Default
var newSex = Sex(symbol: "F")
繼承與多態(tài)
Inheritance
繼承:子類(lèi)自動(dòng)繼承基類(lèi)的屬性、方法、下標(biāo)
只有類(lèi)支持繼承,結(jié)構(gòu)和枚舉不支持繼承
繼承同時(shí)支持實(shí)例成員和類(lèi)型成員
class Shape{
var no=0
func move() {
print("NO: \(no) Shape.move")
}
}
class Rectangle: Shape{
var leftUp=Point()
var width=0
var height=0
}
繼承的兩層含義:
成員復(fù)用:子類(lèi)復(fù)用基類(lèi)成員
var r1=Rectangle()
var c1=Circle()
//成員復(fù)用
r1.no++
r1.move()
c1.no++
c1.move()
類(lèi)型抽象:將子類(lèi)當(dāng)作父類(lèi)來(lái)使用(IS-A關(guān)系準(zhǔn)則)
func process(shape: Shape){
shape.no++
shape.move()
}
var r1=Rectangle()
var c1=Circle()
//類(lèi)型抽象
process(c1)
process(r1)
var s:Shape
s=c1
s=r1
繼承的內(nèi)存模型
class Base{
var x=10
var y=20
static var min=1000
func invoke(){
print("Base.invoke")
}
}
/*
func invoke(self:Base){
print("Base.invoke")
}*/
class Sub: Base{
var z=30
static var max=2000
}
var b=Base()
var s=Sub()
print(Base.min) //1000
print(Sub.min) //1000 這句等于print(Base.min)
Base.min++
print(Base.min) //1001
print(Sub.min) //1001
b.invoke()// invoke(self: b)
s.invoke()// invoke(self: s)

認(rèn)識(shí)多態(tài) Polymorphism
多態(tài):子類(lèi)在同一行為接口下,表現(xiàn)不同的實(shí)現(xiàn)方式。
子類(lèi)使用override關(guān)鍵字來(lái)表達(dá)多態(tài)定義。
可以重寫(xiě)的成員有:方法、屬性、下標(biāo);包括實(shí)例成員和類(lèi)型成員。
在子類(lèi)代碼中,可以使用super來(lái)調(diào)用基類(lèi)的實(shí)現(xiàn)
class Shape{
var no=0
func move() {
print("Shape.move")
}
}
class Rectangle: Shape{
override var no: Int {
get{
print("Rectangle.no.get()")
return super.no
}
set{
print("Rectangle.no.set()")
super.no=newValue
}
}
override func move() {
print("Rectangle.move")
}
}
在成員上使用final阻止子類(lèi)override該成員;在類(lèi)上使用final阻止該類(lèi)被繼承
class Shape{
var no=0
//func show()不能被子類(lèi)重寫(xiě)
final func show(){
print("Shape.show")
}
//0x000640
func move() {
print("Shape.move")
}
}

func process(shape: Shape){
shape.no++
shape.move() //根據(jù)實(shí)際類(lèi)型來(lái)調(diào)用
}
//變量有雙重身份:
//1. 聲明類(lèi)型
//2. 實(shí)際類(lèi)型
var sp: Shape
sp=Shape()
sp.move() // JMP GetVirtualMethod(sp) 二次指針間接運(yùn)算
sp.show() // JMP 0x000340
sp=Rectangle()
sp.move() // JMP GetVirtualMethod(sp) 二次指針間接運(yùn)算
process(sp)
sp=Circle()
sp.move()
process(sp)
繼承中的init和deinit
初始化器 init
如果子類(lèi)沒(méi)有定義初始化器,則將自動(dòng)繼承基類(lèi)的初始化器
如果子類(lèi)定義了初始化器,則不再繼承,此時(shí)子類(lèi)初始化器必須調(diào)用基類(lèi)的一個(gè)初始化器。如果手工不調(diào)用,編譯器將自動(dòng)生成調(diào)用
如果子類(lèi)初始化器與基類(lèi)初始化器原型一致,必須使用override
在子類(lèi)中使用基類(lèi)屬性,必須確保首先調(diào)用基類(lèi)初始化器
析構(gòu)器 deinit
如果子類(lèi)沒(méi)有定義析構(gòu)器,會(huì)自動(dòng)繼承基類(lèi)析構(gòu)器
子類(lèi)析構(gòu)器執(zhí)行完畢后,會(huì)自動(dòng)調(diào)用基類(lèi)析構(gòu)器(無(wú)法手工調(diào)用)
子類(lèi)析構(gòu)器自動(dòng)具有多態(tài)性
class Base{
var data1:Int
init(){
data1=100
print("\(data1)")
print("Base.init")
}
deinit{
print("Base.deinit")
}
}
class Sub: Base{
var data2=200
override init(){
super.init()
print("\(data1), \(data2)")
print("Sub.init")
}
deinit{
print("Sub.deinit")
}
}
func process(){
var b:Base
b=Base()
print("----------")
var s:Base
s=Sub()
print("----------")
}
process()
協(xié)議
認(rèn)識(shí)協(xié)議 Protocol
協(xié)議:類(lèi)型的合同約定,只描述外部接口,不提供具體實(shí)現(xiàn)
協(xié)議可以包含以下成員:屬性、方法、初始化器、下標(biāo)、操作符
一個(gè)類(lèi)型可以實(shí)現(xiàn)多個(gè)協(xié)議,協(xié)議可以應(yīng)用在如下類(lèi)型上。但可以添加class關(guān)鍵字標(biāo)明協(xié)議只能應(yīng)用在類(lèi)上:類(lèi)、結(jié)構(gòu)、枚舉
//定義協(xié)議
protocol Drawable{
var discription: String{
get
}
func draw()
init()
subscript(index: Int) -> Int {
get
}
func ==(lhs: Self, rhs: Self) -> Bool
}
//實(shí)現(xiàn)協(xié)議
class Point: Drawable{
var x:Int
var y:Int
required init(){
x=10
y=10
}
var discription: String{
return "[\(x), \(y)]";
}
func draw(){
print(self.discription)
}
subscript(index: Int) -> Int {
return 0
}
}
使用協(xié)議
協(xié)議本質(zhì)上是一種類(lèi)型,可以作為聲明類(lèi)型,但不能創(chuàng)建實(shí)例
協(xié)議變量的內(nèi)存模型遵從實(shí)際類(lèi)型的內(nèi)存模型
引用類(lèi)型傳參、拷貝采用傳引用方式
值類(lèi)型轉(zhuǎn)參、拷貝采用傳值方式
檢查協(xié)議類(lèi)型
使用is檢查類(lèi)型是否實(shí)現(xiàn)了協(xié)議
使用as?和as!將類(lèi)型下溯轉(zhuǎn)型為協(xié)議
protocol AProtocol{
func display()
}
class Base{
var no=0
}
class Sub:Base,AProtocol{
func display(){
print(no)
}
}
//Compile-time Type 編譯時(shí)類(lèi)型,聲明類(lèi)型
var item1, item2:Base
//Runtime Type 運(yùn)行時(shí)類(lèi)型,實(shí)際類(lèi)型
item1=Base()
item2=Sub()
if(item1 is AProtocol){
print("the runtime type of item1 conforms Shape protocol")
}
if(item2 is AProtocol){
print("the runtime type of item2 conforms Shape protocol")
}
var item3:AProtocol?
var item4=Sub()
item3 = item1 as? AProtocol
item3 = item2 as? AProtocol
item3=item4
協(xié)議中的屬性
協(xié)議中可以定義只讀屬性,也可以定義讀寫(xiě)屬性
協(xié)議中可以定義實(shí)例屬性,也可以定義類(lèi)型屬性
協(xié)議中只能定義變量屬性,不能定義常量屬性
實(shí)現(xiàn)協(xié)議時(shí),并不要求實(shí)現(xiàn)為存儲(chǔ)屬性,還是計(jì)算屬性
協(xié)議中的方法
協(xié)議可以定義實(shí)例方法、也可以定義類(lèi)型方法
協(xié)議中的方法不能定義參數(shù)的默認(rèn)值
針對(duì)值類(lèi)型的mutating協(xié)議方法
值類(lèi)型(struct和enum)實(shí)現(xiàn)的實(shí)例方法如果要更改實(shí)例本身,需要在協(xié)議方法的定義中標(biāo)明mutating關(guān)鍵字,同時(shí)在方法實(shí)現(xiàn)時(shí)也添加mutating關(guān)鍵字
添加了mutating的協(xié)議方法,對(duì)類(lèi)的實(shí)現(xiàn)方法無(wú)影響。在類(lèi)內(nèi)實(shí)現(xiàn)mutating協(xié)議方法時(shí),無(wú)需再添加mutating關(guān)鍵字
協(xié)議中的初始化器
協(xié)議中可以定義初始化器,但不可以定義析構(gòu)器
當(dāng)class中實(shí)現(xiàn)協(xié)議定義的初始化器時(shí),需要添加required關(guān)鍵字
標(biāo)明子類(lèi)也需要提供該初始化器
如果定義為final類(lèi),則不需要required關(guān)鍵字
協(xié)議可以定義可失敗的初始化器init?,具體實(shí)現(xiàn)時(shí)可以失敗,也可以非失敗
更多協(xié)議形式
協(xié)議繼承
一個(gè)協(xié)議可以繼承一個(gè)或多個(gè)協(xié)議
實(shí)現(xiàn)自協(xié)議的類(lèi)型,可必須實(shí)現(xiàn)父協(xié)議中約定的成員
協(xié)議組合
可以使用protocol<A,B,...>來(lái)組合多個(gè)協(xié)議
實(shí)現(xiàn)組合協(xié)議的類(lèi)型,必須實(shí)現(xiàn)組合協(xié)議中的每一個(gè)協(xié)議
組合協(xié)議是一個(gè)臨時(shí)類(lèi)型
可選協(xié)議
協(xié)議的某些成員可以定義為optional,不必實(shí)現(xiàn)
可選協(xié)議只能應(yīng)用于class,不能應(yīng)用于struct和enum
可選協(xié)議必須標(biāo)明@objc特性(即使不需要和Objective-C互操作)
protocol AProtocol{
func display()
}
//協(xié)議繼承
protocol BProtocol: AProtocol{
func invoke()
}
protocol CProtocol{
func excute()
}
class ClassA:BProtocol{
func display(){
print("display")
}
func invoke(){
print("invoke")
}
}
class ClassB:AProtocol,CProtocol{
func display(){
print("display")
}
func excute(){
print("excute")
}
}
//協(xié)議組合
func process( item: protocol<AProtocol,CProtocol>){
item.display()
item.excute()
}
var b=ClassB()
process(b)
//可選協(xié)議
@objc protocol DProtocol {
optional var discription: String { get }
func move()
}
class ClassC: DProtocol{
@objc func move(){
}
}
字符串
認(rèn)識(shí)字符串 String
String是一個(gè)Unicode編碼、16位字符的字符序列
String與NSString支持無(wú)縫互操作
String被定義為struct,值類(lèi)型,拷貝時(shí)具有值語(yǔ)義
String是一個(gè)struct,但內(nèi)部包含一個(gè)指向堆上的“內(nèi)容指針”,其指向的對(duì)象存放真正的字符串內(nèi)容。

使用字符串
使用var和let來(lái)控制字符串的可變性
var str1 = "Hello"
let str2 = ",Swift"
獲取子串中的字符
//枚舉字符
for item in str1.characters{
print(item)
}
for index in str1.characters.indices {
print(str1[index])
}
print(str1[str1.startIndex])
//print(str1[str1.endIndex])
print(str1[str1.startIndex.successor()])
print(str1[str1.endIndex.predecessor()])
let index = str1.startIndex.advancedBy(4)
print(str1[index])
使用append和+鏈接字符串
//連接字符串
str1.appendContentsOf(",World")
var str3=str1+str2
str1+=str2
var char:Character="!"
str1.append(char)
使用字符轉(zhuǎn)義
//字符轉(zhuǎn)義
let heart = "\u{2665}"
print(heart)
let words = "\tHello"
print(words)
字符串插值(String Interpolation)
//字符串插值
var x=100
var y=200.0
var text="[\(x),\(y)]"
copy-on-write 共享技術(shù)
同一個(gè)字符串內(nèi)容拷貝到不同的變量中時(shí),“內(nèi)容指針”不變,即不同變量“共享”同一份堆內(nèi)存。從而實(shí)現(xiàn)“節(jié)省內(nèi)存”。
如果某一個(gè)變量的字符串內(nèi)容改變時(shí),先將原來(lái)堆內(nèi)存拷貝一份,“內(nèi)容指針”指向新的拷貝,然后再更改新的拷貝。從而確?!罢_性”。
copy-on-write的目的是實(shí)現(xiàn)“內(nèi)容相同的字符串共享內(nèi)存,同時(shí)又支持字符串隨時(shí)改變”。
最佳實(shí)踐:盡量不改變字符串,盡量使用常量字符串let


緩存容量與增長(zhǎng)
字符串初始化后,會(huì)分配一個(gè)緩存容量capacity,其長(zhǎng)度一般大于實(shí)際的字符數(shù)量
當(dāng)字符串增長(zhǎng)時(shí),如果實(shí)際需求大于capacity,其capacity會(huì)以二倍的方式指數(shù)增長(zhǎng)。伴隨的代價(jià):
分配新的堆內(nèi)存2*capacity
將原來(lái)堆內(nèi)存上的內(nèi)容拷貝到新內(nèi)存
釋放原來(lái)堆內(nèi)存
最佳實(shí)踐:估計(jì)好capacity,預(yù)先分配好一定容量,避免以后capacity的增長(zhǎng)
str.reserveCapacity(10000) //分配了10000個(gè)字節(jié)給capacity
集合類(lèi)型
集合類(lèi)型有數(shù)組(Array),集合(Set),字典(Dictionary)三種。
認(rèn)識(shí)數(shù)組
Array是一個(gè)有序的元素序列,支持隨機(jī)存取,支持動(dòng)態(tài)更新長(zhǎng)度。
索引從0開(kāi)始,索引訪問(wèn)越界會(huì)拋出運(yùn)行時(shí)異常。
Array被定義為Struct,值類(lèi)型,拷貝時(shí)具有值語(yǔ)義。
Array是一個(gè)Struct,但內(nèi)部包含一個(gè)指向堆上的“元素指針”,其指向的對(duì)象存放真正的數(shù)組元素。
如果數(shù)組元素為值類(lèi)型,拷貝數(shù)組時(shí),元素包含值本身。
如果數(shù)組元素為引用類(lèi)型,拷貝數(shù)組是,元素引用指向相同的對(duì)象。

使用數(shù)組
使var和let來(lái)控制數(shù)組的常量性:數(shù)組長(zhǎng)度和元素內(nèi)容都不能更改。
//變量數(shù)組和常量數(shù)組
var array5=[1,2,3]
let array6=[1,2,3]
數(shù)組遍歷
使用for循環(huán)訪問(wèn)array[index]需要檢查索引越界,具有性能代價(jià)
盡可能使用for-in遍歷數(shù)組元素;或使用Array.enumerate()遍歷索引;二者編譯器會(huì)優(yōu)化掉索引檢查
盡量避免使用insert和remove操作,因?yàn)闀?huì)改變數(shù)組元素序列,涉及到大量的內(nèi)存拷貝操作,代價(jià)較高。
//數(shù)組操作
for item in array5{
print(item)
}
for(index, value) in array5.enumerate(){
print("\(index): \(value)")
}
for index in 0..<array5.count {
print(array5[index])
}
for var index=0;index<array5.count;index++ {
print(array5[index])
}
緩存容量與增長(zhǎng)
數(shù)組初始化后,會(huì)分配一個(gè)緩存容量capacity,其長(zhǎng)度一般大于實(shí)際的元素?cái)?shù)量
當(dāng)數(shù)組長(zhǎng)度增加時(shí),如果實(shí)際需求大于capacity,其capacity會(huì)以近似二倍的方式指數(shù)增長(zhǎng)。伴隨的代價(jià):
分配新的堆內(nèi)存2*capacity
將原來(lái)堆內(nèi)存上的元素拷貝到新內(nèi)存
釋放原來(lái)的堆內(nèi)存
最佳實(shí)踐:估計(jì)好capacity,預(yù)先分配好一定容量,避免以后capacity的增長(zhǎng)
copy-on-write 共享技術(shù):與String的實(shí)現(xiàn)原理一樣,詳情請(qǐng)看String的copy-on-write 共享技術(shù)。
認(rèn)識(shí)集合
Set是一個(gè)無(wú)序的集合,其存儲(chǔ)的值不能重復(fù)
Set中的元素必須有哈希值,即支持Hashable協(xié)議
Set被定義為Struct,值類(lèi)型,拷貝時(shí)具有值語(yǔ)義
Set也是一個(gè)Struct,但內(nèi)部包含一個(gè)指向堆上的“元素指針”,其指向的對(duì)象存放真正的元素。
var words = Set<String>()
words.insert("Hello")
words.insert("Swift")
words.insert("Language")
words.insert("Swift")
認(rèn)知字典
Dictionary是一個(gè)存儲(chǔ)key-value的無(wú)序的集合,key唯一,value可重復(fù)
Dictionary中的key必須有哈希值,即支持Hashable協(xié)議
Dictionary被定義為Struct,值類(lèi)型,拷貝時(shí)具有值語(yǔ)義
Dictionary也是一個(gè)Struct,但內(nèi)部包含一個(gè)指向堆上的“元素指針”,其指向的對(duì)象存放真正的元素。
var dictionary1 = [String:Int]()
var dictionary2 : Dictionary<String,Int>
dictionary2=["Jason":36, "Tom":31, "Marty":44]