1.property初始化的不同
對(duì)于
class
而言,定義class時(shí)候置媳,屬性必須賦值,否則編譯不通過(guò)公条,有三種
方式
- 直接賦值
class CPet {
var name:String = "小花"
var kind:String = "泰迪"
}
- 可選型
class CPet {
var name:String 拇囊?
var kind:String ?
}
- 構(gòu)造器
class CPet {
var name:String
var kind:String
init(name:String,kind:String) {
self.name = name
self.kind = kind
}
}
對(duì)于
struct
而言靶橱,并沒(méi)有這種限制
struct SPet {
var name:String
var kind:String
}
沒(méi)有賦值寥袭,編譯也是可以通過(guò)的
注意:
class直接
對(duì)屬性賦值路捧,也就是沒(méi)有通過(guò)構(gòu)造器賦值
的,在創(chuàng)建對(duì)象對(duì)屬性賦值只能是如下方式:
class CPet {
var name:String?
var kind:String?
}
struct SPet {
var name:String?
var kind:String?
}
let cpet = CPet() // class不可直接在構(gòu)造函數(shù)中初始化property
cpet.name = "老三"
print(cpet.name)
let spet = SPet(name: "老七", kind: "法斗")// struct可直接在構(gòu)造函數(shù)中初始化property
print(spet.name)
//Optional("老三")
//Optional("老七")
這是為什么呢传黄?
原因:
class
在初始化時(shí)不能直接把 property 放在默認(rèn)
的constructor 的參數(shù)里杰扫,而是需要自己創(chuàng)建
一個(gè)帶參數(shù)的constructor,也就是上面的第三種
情況:通過(guò)構(gòu)造器初始化屬性
class CPet {
var name:String?
var kind:String?
init(name:String,kind:String) {
self.name = name
self.kind = kind
}
}
let cpet = CPet(name: "老三", kind: "法牛")
print(cpet.name)
let spet = SPet(name: "老七", kind: "法斗")
print(spet.name)
//Optional("老三")
//Optional("老七")
2. struct是值類型(Value Type),class是引用類型(Reference Type)
概念:
值類型
的變量直接包含他們的數(shù)據(jù)膘掰,對(duì)于值類型都有他們自己的數(shù)據(jù)副本章姓,因此對(duì)一個(gè)變量操作不可能
影響另一個(gè)變量;
引用類型
的變量存儲(chǔ)對(duì)他們的數(shù)據(jù)引用识埋,因此后者稱為對(duì)象凡伊,因此對(duì)一個(gè)變量操作可能
影響另一個(gè)變量所引用的對(duì)象。
這就是深拷貝
與淺拷貝
窒舟,深拷貝就是內(nèi)容
拷貝系忙,淺拷貝就是指針
拷貝。兩者的區(qū)別為:
1. 是否開(kāi)啟新的內(nèi)存地址
2. 是否影響內(nèi)存地址的引用計(jì)數(shù)
代碼如下:
class CPet {
var name:String?
var kind:String?
init(name:String,kind:String) {
self.name = name
self.kind = kind
}
}
struct SPet {
var name:String?
var kind:String?
}
let cpet = CPet(name: "老三", kind: "法牛")
let secondCPet = cpet
secondCPet.name = "老四"
print(cpet.name)
//Optional("老四")
let spet = SPet(name: "老七", kind: "法斗")
var secondSpet = spet
secondSpet.name = "老八"
print(spet.name)
//Optional("老七")
3.在struct
的成員函數(shù)中修改自己本身
的值惠豺,應(yīng)該在函數(shù)簽名上加上mutating
關(guān)鍵字,而class
則沒(méi)有此限制
struct SPet {
var name:String
var kind:String
mutating func changeName(){
self.name = self.name + "changeName"
}
}
class CPet {
var name:String
var kind:String
init(name:String,kind:String) {
self.name = name
self.kind = kind
}
func changeName(){
self.name = self.name + "changeName"
}
}
let cpet = CPet(name: "老三", kind: "法牛")
print(cpet.name)
//老三
cpet .changeName();
print(cpet.name)
//老三changeName
var spet = SPet(name: "老七", kind: "法斗")
print(spet.name)
//老七
spet .changeName()
print(spet.name)
//老七changeName
4.immutable 變量
struct
初始化為let
的對(duì)象無(wú)法修改
银还,修改會(huì)編譯報(bào)錯(cuò),而class
沒(méi)有此限制
class CPet {
var name:String?
var kind:String?
init(name:String,kind:String) {
self.name = name
self.kind = kind
}
}
struct SPet {
var name:String?
var kind:String?
}
錯(cuò)誤寫(xiě)法:
正確寫(xiě)法:
此外洁墙,struct和class還有一些其他方面的不同
- class可以繼承蛹疯,而struct不可以
- 從內(nèi)存分配角度,
struct
分配在棧
上,而class
分配在堆
上扫俺。 - 從安全角度苍苞,
struct
值類型是自動(dòng)線程安全
的,無(wú)引用計(jì)數(shù) - 從速度角度狼纬,值類型通常來(lái)說(shuō)是以
棧
的形式分配的,而不是用堆
骂际。
”堆”和“椓屏穑”并不是
數(shù)據(jù)結(jié)構(gòu)
上的Heap跟Stack,而是程序運(yùn)行中的不同內(nèi)存空間歉铝。棧是程序啟動(dòng)
的時(shí)候盈简,系統(tǒng)事先分配的,使用過(guò)程中太示,系統(tǒng)不干預(yù)柠贤;堆是用的時(shí)候才向系統(tǒng)申請(qǐng)的,用完了需要交還类缤,這個(gè)申請(qǐng)和交還的過(guò)程開(kāi)銷相對(duì)就比較大了臼勉。棧是編譯
時(shí)分配空間,而堆是動(dòng)態(tài)分配(運(yùn)行時(shí)分配空間)餐弱,所以棧
的速度快宴霸。
- 從內(nèi)存泄漏的角度看囱晴,
struct
沒(méi)有引用計(jì)數(shù)
,不會(huì)引起內(nèi)存泄漏
Struct使用場(chǎng)景:模型較小瓢谢,并且無(wú)需繼承畸写、無(wú)需儲(chǔ)存到
NSUserDefault
(Struct
不能被序列化
成NSData
對(duì)象。
) 或者無(wú)需 Objective-C (Objective-C 的代碼里無(wú)法調(diào)用 Swift 的 Struct氓扛。因?yàn)橐?Objective-C 里調(diào)用 Swift 代碼的話枯芬,對(duì)象需要繼承于 NSObject。)使用時(shí)采郎。