本文為大地瓜原創(chuàng)筝蚕,歡迎知識(shí)共享媒怯,轉(zhuǎn)載請(qǐng)注明出處赠制。
雖然你不注明出處我也沒(méi)什么精力和你計(jì)較赶袄。
作者微信號(hào):christgreenlaw
大地瓜在學(xué)習(xí)Stanford University的Developing iOS 11 Apps with Swift.
這里記錄了一些小筆記僚碎。這部分是前三節(jié)猴娩。
這篇文章并不是這個(gè)教程的全部?jī)?nèi)容,只是大地瓜自己學(xué)習(xí)過(guò)程中想記錄的一部分內(nèi)容。
swift的optional是為了兼容OC的卷中,optional有兩個(gè)狀態(tài)矛双,set 和 not set。也就是要么有值要么無(wú)值蟆豫。使用感嘆號(hào)表示我們假定其一定有值议忽,但如果你這樣做了,加了感嘆號(hào)十减,但其實(shí)本身無(wú)值栈幸,在訪問(wèn)時(shí)應(yīng)用就會(huì)崩潰掉。問(wèn)號(hào)則表示不保證有值帮辟,只是一個(gè)普通的optional速址。
struct和class在Swift中幾乎是一樣的東西。都有ivar由驹,都有method
主要有以下兩個(gè)區(qū)別:
- struct沒(méi)有繼承關(guān)系壳繁。
- struct是value type,class 是 reference type
數(shù)組荔棉、字典、int蒿赢、string等等都是struct
value type是什么意思润樱?
值類(lèi)型在傳遞時(shí)會(huì)被拷貝。(Swift并不會(huì)無(wú)腦拷貝羡棵,只會(huì)將有修改的部分拷貝壹若,也就是copy-on-write)
引用類(lèi)型傳遞時(shí),傳遞的可以認(rèn)為是指針皂冰,使用的還是同一個(gè)對(duì)象店展。
- struct會(huì)默認(rèn)得到一個(gè)init,其參數(shù)列表列出了所有的ivar秃流。class得到的默認(rèn)init只會(huì)是沒(méi)有參數(shù)列表的init
Swift中的訪問(wèn)控制(Access Control)
internal-- default, it means "usable by any object in my app or framework"
private - this means "only callable from within this object"
private(set) - this means "this property is readable outside this object but not settable"
fileprivate - accessible by any code in this source file
public (for frameworks only) this can be used by objects outside my framework
open (for frameworks only) public and objects outside my framework can subclass this
不做framework開(kāi)發(fā)的話不用在意后兩個(gè)
比較好的做法是將所有的東西都標(biāo)記為private赂蕴,當(dāng)我們發(fā)現(xiàn)這個(gè)東西需要外界調(diào)用時(shí)再取消private
Assertion 斷言
假定某個(gè)條件為真則繼續(xù)運(yùn)行,否則就crash并打印一條error信息舶胀。
這個(gè)東西在自己測(cè)試開(kāi)發(fā)時(shí)會(huì)有效概说,在產(chǎn)品中是無(wú)效的。
用于保護(hù)方法的實(shí)現(xiàn)嚣伐,可以測(cè)試一些錯(cuò)誤糖赔。
assert(一個(gè)bool,一個(gè)string錯(cuò)誤信息)
Extensions
Add vars(properties) and methods to a class/struct/enum, even if you don't have the source code for that class/struct/enum.
注意以下限制:
- 你不能重寫(xiě)已有的method或property轩端。(你只能添加新的)
- 添加的property不能有相關(guān)的storage(computed only)
這個(gè)extension和OC中的類(lèi)擴(kuò)展差別還是挺大的放典,OC里我沒(méi)記錯(cuò)的話可以重寫(xiě)方法覆蓋原來(lái)的方法,屬性也是可以進(jìn)行存儲(chǔ)的。
最好是給某個(gè)類(lèi)型添加相關(guān)的工具或功能奋构,不要添加和這個(gè)類(lèi)沒(méi)關(guān)系的功能壳影。
Optionals
先看enum
enum是class和struct之外的另一種數(shù)據(jù)結(jié)構(gòu)。
enum只能有離散的狀態(tài)(discrete states)
enum FastFoodMenuItem {
case hamburger
case fries
case drink
case cookie
}
enum是值類(lèi)型声怔,所以在傳遞時(shí)會(huì)被拷貝态贤。
enum和struct都是值類(lèi)型,傳遞時(shí)會(huì)進(jìn)行復(fù)制醋火,所以傳遞后你修改的是新的副本悠汽,而不是原來(lái)的那個(gè),而class是引用類(lèi)型芥驳,會(huì)傳遞自身柿冲,你修改一處,那么所有擁有這個(gè)class對(duì)象的兆旬,都會(huì)變化
每個(gè)case都可以有相關(guān)的數(shù)據(jù)(但不是非要有數(shù)據(jù))
enum FastFoodMenuItem {
case hamburger(numberOfPatties: Int)
case fries(size: FryOrderSize)
case drink(String, ounces: Int)
//the unnamed String is the brand, e.g. "coke"
case cookie
}
//note that the drink case has 2 pieces of associated data(one of the "unnamed")
// in the example above, FryOrderSize would also probably be an enum
enum FryOrderSize {
case large
case small
}
使用enum
let menuItem: FastFoodMenuItem = FastFoodMenuItem.hamburger(patties: 2)
let otherItem: FastFoodMenuItem = FastFoodMenuItem.cookie
如果要使用類(lèi)型推斷
let menuItem = FastFoodMenuItem.hamburger(patties: 2)
let otherItem: FastFoodMenuItem = .cookie
//以上都是可以的
//但是不可以像這樣
let otherItem = .cookie
//這個(gè)不難理解吧假抄。。丽猬。宿饱。
也就是說(shuō),只能推斷一側(cè)脚祟。如果你什么都不給的話谬以,那如何推斷呢?
一般使用enum判斷狀態(tài)時(shí)由桌,使用switch
某個(gè)分支你不想做什么就用break
switch
語(yǔ)句必須遍歷所有情況为黎,不能有剩余,如果你不關(guān)心某些狀態(tài)行您,記得使用default
swift中的switch
默認(rèn)是不會(huì)fall through
的铭乾,不會(huì)繼續(xù)執(zhí)行下一個(gè)case
的
enum是可以有method的,以及computed properties娃循,不可以有stored properties
enum FastFoodMenuItem {
case hamburger(numberOfPatties: Int)
case fries(size: FryOrderSize)
case drink(String, ounces: Int)
//the unnamed String is the brand, e.g. "coke"
case cookie
func isIncludedInSpecialOrder(number: Int) -> Bool {}
var calories: Int { //calculate and return caloric value here }
}
enum自己的method中炕檩,可以對(duì)自己的狀態(tài)進(jìn)行判斷(switch self)。但不可以在property的get中進(jìn)行判斷捌斧。
enum FastFoodMenuItem {
···
func isIncludedInSpecialOrder(number: Int) -> Bool {
switch self {
case .hamburger(let pattyCount): return pattyCount == number
case .fries, . cookie: return true//fries and cookie in every special order
case .drink(_, let ounces): return ounces == 16//16oz drink of any kind
}
}
var calories: Int { //calculate and return caloric value here }
}
在enum的method中甚至可以對(duì)自己進(jìn)行修改(更改自己的類(lèi)型)
enum FastFoodMenuItem {
···
mutating func switchToBeingACookie() {
self = .cookie//此時(shí)將自身轉(zhuǎn)換為cookie了捧书,不管你原來(lái)是hamburger還是fries還是什么
}
}
需要注意的是,mutating
是必須要寫(xiě)的骤星,因?yàn)閑num是一個(gè)值類(lèi)型经瓷,copy on write。(struct中也需要寫(xiě)mutating
)
說(shuō)了這么多洞难,Optional其實(shí)就是個(gè)enum舆吮。
大概就是這樣:
enum Optional<T> {
//a generic type, like Array<Element> or Dictionary<Key, Value>
case none
case some(<T>)//the some case has associated data of type T
}
但是它很特殊,有許多特殊的語(yǔ)法。
strong是默認(rèn)的色冀,一般我們不需要寫(xiě)出來(lái)潭袱。
weak:如果別人都不感興趣了,我也就不感興趣了锋恬,把我設(shè)置成nil就好屯换。
那么既然weak是可以設(shè)置為nil的,我們很顯然可以知道只有optional的引用類(lèi)型才可能是weak与学。別的地方是用不到weak的彤悔。
常見(jiàn)的兩個(gè)weak情景,一個(gè)就是outlet索守,另一個(gè)是delegate晕窑。別的地方真的很少用weak了。
weak指針是不會(huì)將對(duì)象保留在heap中的卵佛。unowned:別引用計(jì)數(shù)我杨赤。我指向某個(gè)地方,但是你別計(jì)數(shù)我截汪。我保證沒(méi)有引用計(jì)數(shù)時(shí)(heap中沒(méi)有這個(gè)對(duì)象時(shí)我絕對(duì)不會(huì)訪問(wèn)這里的疾牲,但是你一旦訪問(wèn)的話就會(huì)crash)這個(gè)真的幾乎不用,太危險(xiǎn)了衙解。
一般用unowned來(lái)干嘛呢说敏?解決引用循環(huán)。
closure經(jīng)常產(chǎn)生引用循環(huán)丢郊。