最近項目使用的是OC酱塔,后頭看之前用Swift開發(fā)的一個項目時,發(fā)現(xiàn)很多細(xì)節(jié)都忘記了????危虱。
為了回憶和以后方便查看羊娃,現(xiàn)在根據(jù)官方文檔swift編程語言,做下筆記埃跷。
1蕊玷、 值類型和引用類型
-
值類型被賦予給一個變量邮利、常量或者被傳遞給一個函數(shù)的時候,其值會被拷貝垃帅。
在 Swift 中延届,所有的基本類型:整數(shù)、浮點數(shù)贸诚、布爾值方庭、字符串、數(shù)組和字典酱固,都是值類型械念,并且在底層都是以結(jié)構(gòu)體的形式所實現(xiàn)。
所有的結(jié)構(gòu)體和枚舉類型都是值類型运悲。這意味著它們的實例龄减,以及實例中所包含的任何值類型屬性,在代碼中傳遞的時候都會被復(fù)制班眯。
-
引用類型在被賦予到一個變量欺殿、常量或者被傳遞到一個函數(shù)時,其值不會被拷貝鳖敷,引用的是已存在的實例本身而不是其拷貝脖苏。
類是引用類型,因此引用的是已存在的實例本身而不是其拷貝定踱。
2棍潘、OC與Swift中的字符串、數(shù)組崖媚、和字典類型
Swift 中亦歉,String,Array和Dictionary類型均以結(jié)構(gòu)體的形式實現(xiàn)畅哑。這意味著被賦值給新的常量或變量肴楷,或者被傳入函數(shù)或方法中時,它們的值會被拷貝荠呐。
Objective-C 中NSString赛蔫,NSArray和NSDictionary類型均以類的形式實現(xiàn),而并非結(jié)構(gòu)體泥张。它們在被賦值或者被傳入函數(shù)或方法時呵恢,不會發(fā)生值拷貝,而是傳遞現(xiàn)有實例的引用媚创。
3渗钉、類和結(jié)構(gòu)體的選擇
按照通用的準(zhǔn)則,當(dāng)符合一條或多條以下條件時钞钙,考慮構(gòu)建結(jié)構(gòu)體:
- 該數(shù)據(jù)結(jié)構(gòu)的主要目的是用來封裝少量相關(guān)簡單數(shù)據(jù)值鳄橘。
- 有理由預(yù)計該數(shù)據(jù)結(jié)構(gòu)的實例在被賦值或傳遞時声离,封裝的數(shù)據(jù)將會被拷貝而不是被引用。
- 該數(shù)據(jù)結(jié)構(gòu)中儲存的值類型屬性瘫怜,也應(yīng)該被拷貝术徊,而不是被引用。
- 該數(shù)據(jù)結(jié)構(gòu)不需要去繼承另一個既有類型的屬性或者行為宝磨。
以下情境中適合使用結(jié)構(gòu)體:
- 幾何形狀的大小弧关,封裝一個width屬性和height屬性盅安,兩者均為Double類型唤锉。
- 一定范圍內(nèi)的路徑,封裝一個start屬性和length屬性别瞭,兩者均為Int類型窿祥。
- 三維坐標(biāo)系內(nèi)一點,封裝x蝙寨,y和z屬性晒衩,三者均為Double類型。
在所有其它案例中墙歪,定義一個類听系,生成一個它的實例,并通過引用來管理和傳遞虹菲。實際中靠胜,這意味著絕大部分的自定義數(shù)據(jù)構(gòu)造都應(yīng)該是類,而非結(jié)構(gòu)體毕源。
4浪漠、類和結(jié)構(gòu)體
-
類和結(jié)構(gòu)體有著類似的定義方式。我們通過關(guān)鍵字class和struct來分別表示類和結(jié)構(gòu)體霎褐,并在一對大括號中定義它們的具體內(nèi)容:
class SomeClass {
// 在這里定義類
}
struct SomeStructure {
// 在這里定義結(jié)構(gòu)體
}
以下是定義結(jié)構(gòu)體和定義類的示例:
其中name為可選類型址愿,值為可選String,默認(rèn)值為nil冻璃,意為沒有name值
struct Resolution {
var width = 0
var height = 0
}
class VideoMode {
var resolution = Resolution()
var interlaced = false
var frameRate = 0.0
var name: String?
}
-
類和結(jié)構(gòu)體實例
let someResolution = Resolution()
let someVideoMode = VideoMode()
-
結(jié)構(gòu)體類型的成員逐一構(gòu)造器
所有結(jié)構(gòu)體都有一個自動生成的成員逐一構(gòu)造器响谓,用于初始化新結(jié)構(gòu)體實例中成員的屬性。
let vga = Resolution(width:640, height: 480)
類實例沒有默認(rèn)的成員逐一構(gòu)造器
-
結(jié)構(gòu)體是值類型
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
cinema.width = 2048
print("cinema is now \(cinema.width) pixels wide")
// 打印 "cinema is now 2048 pixels wide"
print("hd is still \(hd.width) pixels wide")
// 打印 "hd is still 1920 pixels wide"
-
類是引用類型
let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
print("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
// 打印 "The frameRate property of theEighty is now 30.0"
需要注意的是tenEighty和alsoTenEighty被聲明為常量而不是變量省艳。然而你依然可以改變tenEighty.frameRate和alsoTenEighty.frameRate歌粥,因為tenEighty和alsoTenEighty這兩個常量的值并未改變。它們并不“存儲”這個VideoMode實例拍埠,而僅僅是對VideoMode實例的引用失驶。所以,改變的是被引用的VideoMode的frameRate屬性枣购,而不是引用VideoMode的常量的值嬉探。
5擦耀、屬性
屬性將值跟特定的類、結(jié)構(gòu)或枚舉關(guān)聯(lián)涩堤。存儲屬性存儲常量或變量作為實例的一部分眷蜓,而計算屬性計算(不是存儲)一個值。
注意
計算屬性可以用于類胎围、結(jié)構(gòu)體和枚舉吁系,存儲屬性只能用于類和結(jié)構(gòu)體。Swift 中的屬性沒有對應(yīng)的實例變量
-
存儲屬性
存儲屬性就是存儲在特定類或結(jié)構(gòu)體實例里的常量或變量白魂。
例如:FixedLengthRange 的實例包含一個名為 firstValue 的變量存儲屬性和一個名為 length 的常量存儲屬性汽纤。
struct FixedLengthRange {
var firstValue: Int
let length: Int
}
var rangeOfThreeItems = FixedLengthRange(firstValue: 0, length: 3)
// 該區(qū)間表示整數(shù)0,1福荸,2
rangeOfThreeItems.firstValue = 6
// 該區(qū)間現(xiàn)在表示整數(shù)6蕴坪,7,8
注意
如果創(chuàng)建了一個結(jié)構(gòu)體的實例并將其賦值給一個常量敬锐,則無法修改該實例的任何屬性背传,即使有屬性被聲明為變量也不行:
let rangeOfFourItems = FixedLengthRange(firstValue: 0, length: 4)
// 該區(qū)間表示整數(shù)0,1台夺,2径玖,3
rangeOfFourItems.firstValue = 6
// 盡管 firstValue 是個變量屬性,這里還是會報錯
原因:結(jié)構(gòu)體屬于值類型颤介,當(dāng)值類型的實例被聲明為常量的時候梳星,它的所有屬性也就成了常量。
-
Lazy Stored Properties
延遲存儲屬性是指當(dāng)?shù)谝淮伪徽{(diào)用的時候才會計算其初始值的屬性买窟。在屬性聲明前使用 lazy 來標(biāo)示一個延遲存儲屬性丰泊。
必須將延遲存儲屬性聲明成變量(使用 var 關(guān)鍵字),因為屬性的初始值可能在實例構(gòu)造完成之后才會得到始绍。而常量屬性在構(gòu)造過程完成之前必須要有初始值瞳购,因此無法聲明成延遲屬性。
注意
如果一個被標(biāo)記為 lazy 的屬性在沒有初始化時就同時被多個線程訪問亏推,則無法保證該屬性只會被初始化一次学赛。
-
計算屬性
計算屬性不直接存儲值,而是提供一個 getter 和一個可選的 setter吞杭,來間接獲取和設(shè)置其他屬性或變量的值盏浇。
注意
必須使用 var 關(guān)鍵字定義計算屬性,包括只讀計算屬性芽狗,因為它們的值不是固定的绢掰。let 關(guān)鍵字只用來聲明常量屬性,表示初始化后再也無法修改的值。
例如:Rect提供了一個名為center 的計算屬性滴劲。
struct Point {
var x = 0.0, y = 0.0
}
struct Size {
var width = 0.0, height = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set(newCenter) {
origin.x = newCenter.x - (size.width / 2)
origin.y = newCenter.y - (size.height / 2)
}
}
}
var square = Rect(origin: Point(x: 0.0, y: 0.0),
size: Size(width: 10.0, height: 10.0))
let initialSquareCenter = square.center
square.center = Point(x: 15.0, y: 15.0)
print("square.origin is now at (\(square.origin.x), \(square.origin.y))")
// 打印 "square.origin is now at (10.0, 10.0)”
-
簡化 setter 聲明
如果計算屬性的 setter 沒有定義表示新值的參數(shù)名攻晒,則可以使用默認(rèn)名稱 newValue。
var center: Point {
get {
let centerX = origin.x + (size.width / 2)
let centerY = origin.y + (size.height / 2)
return Point(x: centerX, y: centerY)
}
set {
origin.x = newValue.x - (size.width / 2)
origin.y = newValue.y - (size.height / 2)
}
}
-
只讀計算屬性
只有 getter 沒有 setter 的計算屬性就是只讀計算屬性班挖。
只讀計算屬性的聲明可以去掉 get 關(guān)鍵字和花括號:
struct Cuboid {
var width = 0.0, height = 0.0, depth = 0.0
var volume: Double {
return width * height * depth
}
}
let fourByFiveByTwo = Cuboid(width: 4.0, height: 5.0, depth: 2.0)
print("the volume of fourByFiveByTwo is \(fourByFiveByTwo.volume)")
// 打印 "the volume of fourByFiveByTwo is 40.0"
-
屬性觀察
屬性觀察器監(jiān)控和響應(yīng)屬性值的變化鲁捏,每次屬性被設(shè)置值的時候都會調(diào)用屬性觀察器,即使新值和當(dāng)前值相同的時候也不例外萧芙。
可以為除了延遲存儲屬性之外的其他存儲屬性添加屬性觀察器给梅,也可以通過重寫屬性的方式為繼承的屬性(包括存儲屬性和計算屬性)添加屬性觀察器。
willSet 在新的值被設(shè)置之前調(diào)用
didSet 在新的值被設(shè)置之后調(diào)用
class StepCounter {
var totalSteps: Int = 0 {
willSet(newTotalSteps) {
print("About to set totalSteps to \(newTotalSteps)")
}
didSet {
if totalSteps > oldValue {
print("Added \(totalSteps - oldValue) steps")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 200
// About to set totalSteps to 200
// Added 200 steps
stepCounter.totalSteps = 360
// About to set totalSteps to 360
// Added 160 steps
-
類型屬性(Type Properties)
存儲型類型屬性可以是變量或常量
双揪,計算型類型屬性跟實例的計算型屬性一樣只能定義成變量
屬性动羽。
跟實例的存儲型屬性不同,必須給存儲型類型屬性指定默認(rèn)值盟榴,因為類型本身沒有構(gòu)造器曹质,也就無法在初始化過程中使用構(gòu)造器給類型屬性賦值婴噩。
1擎场、類型屬性語法
Swift 中,類型屬性是作為類型定義的一部分寫在類型最外層的花括號內(nèi)几莽,因此它的作用范圍也就在類型支持的范圍內(nèi)迅办。
使用關(guān)鍵字 static 來定義類型屬性。在為類定義計算型類型屬性時章蚣,可以改用關(guān)鍵字 class 來支持子類對父類的實現(xiàn)進(jìn)行重寫站欺。
struct SomeStructure {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 1
}
}
enum SomeEnumeration {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 6
}
}
class SomeClass {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 27
}
class var overrideableComputedTypeProperty: Int {
return 107
}
}
2、類型屬性是通過類型本身來訪問纤垂,而不是通過實例矾策。
print(SomeStructure.storedTypeProperty)
// 打印 "Some value."
SomeStructure.storedTypeProperty = "Another value."
print(SomeStructure.storedTypeProperty)
// 打印 "Another value.”
6、方法
-
實例方法 (Instance Methods)
在 Objective-C 中峭沦,類是唯一能定義方法的類型贾虽。但在 Swift 中,類/結(jié)構(gòu)體/枚舉上均可以定義方法吼鱼。
1蓬豁、定義一個很簡單的Counter類:
class Counter {
var count = 0
func increment() {
count += 1
}
}
let counter = Counter()
// 初始計數(shù)值是0
counter.increment()
// 計數(shù)值現(xiàn)在是1
2、在實例方法中修改值類型
結(jié)構(gòu)體和枚舉是值類型菇肃。默認(rèn)情況下地粪,值類型的屬性不能在它的實例方法中被修改。
但是:
你可以為這個方法選擇可變(mutating)行為琐谤,然后就可以從其方法內(nèi)部改變它的屬性蟆技;
struct Point {
var x = 0.0, y = 0.0
mutating func moveByX(deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveByX(2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
// 打印 "The point is now at (3.0, 4.0)"
注意
不能在結(jié)構(gòu)體類型的常量(a constant of structure type)上調(diào)用可變方法。
let fixedPoint = Point(x: 3.0, y: 3.0)
fixedPoint.moveByX(2.0, y: 3.0)
// 這里將會報告一個錯誤
3、在可變方法中給 self 賦值
可變方法能夠賦給隱含屬性self一個全新的實例质礼。上面Point的例子可以用下面的方式改寫:
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
self = Point(x: x + deltaX, y: y + deltaY)
}
}
新版的可變方法moveBy(x:y:)創(chuàng)建了一個新的結(jié)構(gòu)體實例聊品,它的 x 和 y 的值都被設(shè)定為目標(biāo)值。調(diào)用這個版本的方法和調(diào)用上個版本的最終結(jié)果是一樣的几苍。
-
self 屬性
類型的每一個實例都有一個隱含屬性叫做self翻屈,self完全等同于該實例本身。你可以在一個實例的實例方法中使用這個隱含的self屬性來引用當(dāng)前實例妻坝。
上面例子中的increment方法還可以這樣寫:
func increment() {
self.count += 1
}
注意
實例方法的某個參數(shù)名稱與實例的某個屬性名稱相同的時候伸眶,參數(shù)名稱享有優(yōu)先權(quán)。這時你可以使用self屬性來區(qū)分參數(shù)名稱和屬性名稱刽宪。
-
類方法
定義在類型本身上調(diào)用的方法厘贼。
在方法的func關(guān)鍵字之前加上關(guān)鍵字static,來指定類型方法圣拄。類還可以用關(guān)鍵字class來允許子類重寫父類的方法實現(xiàn)嘴秸。
在 Objective-C 中,你只能為 Objective-C 的類類型(classes)定義類型方法(type-level methods)庇谆。
在 Swift 中岳掐,你可以為所有的類、結(jié)構(gòu)體和枚舉定義類型方法饭耳。