這篇文章是學(xué)習(xí)Swift的筆記與深化熄求。希望這篇文章能夠幫助已經(jīng)有Objective-C經(jīng)驗(yàn)的開(kāi)發(fā)者更快地學(xué)習(xí)Swift渣玲。同時(shí)也品味到Swift的精妙之處。以下是原文地址:
原文地址:http://www.cocoachina.com/ios/20150906/13318.html
結(jié)論放在開(kāi)頭:
我認(rèn)為Swift比Objective-C更優(yōu)雅,更安全同時(shí)也更現(xiàn)代,更性感抡四。
文章組織脈絡(luò):
1.從Objective-C到Swift的語(yǔ)法差異柜蜈。我們熟悉的Objective-C特性在Swift中如何展現(xiàn)仗谆。
2.從Objective-C到Swift的進(jìn)步改進(jìn)指巡。研究對(duì)比Swift在安全性,易用性上的提升,給我們帶來(lái)的新編程范式。
目錄:
1.屬性(property)和實(shí)例變量(instance variable)
2.控制流
3.函數(shù)
4.類與初始化(Initializers)
5.枚舉與結(jié)構(gòu)體
6.協(xié)議(Protocols)
7.Swift與Cocoa
8.總結(jié)
1.屬性(property)和實(shí)例變量(instance variable)
Objective-C property in Swift world
在Cocoa世界開(kāi)發(fā)的過(guò)程中,我們最常打交道的是property.
典型的聲明為:
@property (strong,nonatomic) NSString *string;
而在Swift當(dāng)中,擺脫了C的包袱后,變得更為精煉,我們只需直接在類中聲明即可
class Shape {
var name = "shape"
}
注意到這里,我們不再需要@property指令,而在Objective-C中,我們可以指定property的attribute,例如strong,weak,readonly等隶垮。
而在Swift的世界中,我們通過(guò)其他方式來(lái)聲明這些property的性質(zhì)藻雪。
需要注意的幾點(diǎn):
- strong: 在Swift中是默認(rèn)的
- weak: 通過(guò)weak關(guān)鍵詞申明
- weak var delegate: UITextFieldDelegate?
- readonly,readwrie 直接通過(guò)聲明變量var,聲明常量let的方式來(lái)指明
- copy 通過(guò)@NSCopying指令聲明。
值得注意的是String,Array和Dictionary在Swift是以值類型(value type)而不是引用類型(reference type)出現(xiàn),因此它們?cè)谫x值,初始化,參數(shù)傳遞中都是以拷貝的方式進(jìn)行(簡(jiǎn)單來(lái)說(shuō),String,Array,Dictionary在Swift中是通過(guò)struct實(shí)現(xiàn)的)
延伸閱讀:Value and Reference Types - nonatomic,atomic 所有的Swift properties 都是nonatomic狸吞。但是我們?cè)诰€程安全上已經(jīng)有許多機(jī)制,例如NSLock,GCD相關(guān)API等勉耀。個(gè)人推測(cè)原因是蘋(píng)果想把這一個(gè)本來(lái)就用的很少的特性去掉,線程安全方面交給平時(shí)我們用的更多的機(jī)制去處理指煎。
然后值得注意的是,在Objective-C中,我們可以跨過(guò)property直接與instance variable打交道,而在Swift是不可以的。
例如:我們可以不需要將someString聲明為property,直接使用即可便斥。即使我們將otherString聲明為property,我們也可以直接用_otherString來(lái)使用property背后的實(shí)例變量至壤。
@interface SomeClass : NSObject {
NSString *someString;
}
@property(nonatomic, copy) NSString* otherString;
而在Swift中,我們不能直接與instance variable打交道。也就是我們聲明的方式簡(jiǎn)化為簡(jiǎn)單的一種,簡(jiǎn)單來(lái)說(shuō)在Swift中,我們只與property打交道枢纠。
A Swift property does not have a corresponding instance variable, and the backing store for a property is not accessed directly
小結(jié)
- 因此之前使用OC導(dǎo)致的像巧哥指出的開(kāi)發(fā)爭(zhēng)議就不再需要爭(zhēng)執(zhí)了,在Swift的世界里,我們只與property打交道像街。
- 并且我們?cè)贠C中init和dealloc不能使用屬性self.property = XXX來(lái)進(jìn)行設(shè)置的情況得以解決和統(tǒng)一。
(不知道這一條規(guī)定,在init直接用self.property = value 的同學(xué)請(qǐng)自覺(jué)閱讀iOS夯實(shí):內(nèi)存管理)
個(gè)人覺(jué)得這看似小小一點(diǎn)變動(dòng)使Swift開(kāi)發(fā)變得更加安全以及在代碼的風(fēng)格更為統(tǒng)一與穩(wěn)定晋渺。
Swift property延伸:
- Stored Properties和Computed properties
在Swift中,property被分為兩類:Stored Properties和Computed properties 簡(jiǎn)單來(lái)說(shuō),就是stored properties 能夠保存值,而conmuted properties只提供getter與setter,利用stored properties來(lái)生成自己的值。個(gè)人感覺(jué)Computed properties更像方法,而不是傳統(tǒng)意義的屬性。但是這樣一個(gè)特性存在,使得我們更容易組織我們的代碼香椎。
延伸閱讀:computed property vs function
- Type Properties
Swift提供了語(yǔ)言級(jí)別定義類變量的方法找筝。
In C and Objective-C, you define static constants and variables associated with a type as global static variables.In Swift, however, type properties are written as part of the type’s definition, within the type’s outer curly braces, and each type property is explicitly scoped to the type it supports.
在Objective-C中,我們只能通過(guò)單例,或者static變量加類方法來(lái)自己構(gòu)造類變量:
@interface Model
+ (int) value;
+ (void) setValue:(int)val;
@end
@implementation Model
static int value;
+ (int) value
{ @synchronized(self) { return value; } }
+ (void) setValue:(int)val
{ @synchronized(self) { value = val; } }
@end
// Foo.h
@interface Foo {
}
+(NSDictionary*) dictionary;
// Foo.m
+(NSDictionary*) dictionary
{
static NSDictionary* fooDict = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
// create dict
});
return fooDict;
}
而在Swift中我們通過(guò)清晰的語(yǔ)法便能定義類變量:
通過(guò)static定義的類變量無(wú)法在子類重寫(xiě),通過(guò)class定義的類變量則可在子類重寫(xiě)。
struct SomeStructure {
static var storedTypeProperty = "Some value."
static var computedTypeProperty: Int {
return 1
}
class var overrideableComputedTypeProperty: Int {
return 107
}
}
同時(shí)利用類變量我們也有了更優(yōu)雅的單例模式實(shí)現(xiàn):
class singletonClass {
static let sharedInstance = singletonClass()
private init() {} // 這就阻止其他對(duì)象使用這個(gè)類的默認(rèn)的'()'初始化方法
}
Swift單例模式探索:The Right Way to Write a Singleton
- 延伸:
目前Swift支持的type propertis中的Stored Properties類型不是傳統(tǒng)意義上的類變量(class variable)八千,暫時(shí)不能通過(guò)class 關(guān)鍵詞定義,通過(guò)static定義的類變量類似java中的類變量,是無(wú)法被繼承的,父類與子類的類變量指向的都是同一個(gè)靜態(tài)變量吗讶。
延伸閱讀: Class variables not yet supported
class SomeStructure {
class var storedTypeProperty = "Some value."
}
//Swift 2.0
Error: Class stored properties not yet supported in classes
通過(guò)編譯器拋出的錯(cuò)誤信息,相信在未來(lái)的版本中會(huì)完善Type properties。
2.控制流
Swift與Objective-C在控制流的語(yǔ)法上關(guān)鍵詞基本是一致的,但是擴(kuò)展性和安全性得到了很大的提升叼丑。
主要有三種類型的語(yǔ)句
1.if,switch和新增的guard
2.for,while
3.break,continue
主要差異有:
關(guān)于if
語(yǔ)句里的條件不再需要使用()包裹了关翎。
let number = 23
if number < 10 {
print("The number is small")
}
但是后面判斷執(zhí)行的的代碼必須使用{}包裹住。
為什么呢,在C,C++等語(yǔ)言中,如果后面執(zhí)行的語(yǔ)句只有語(yǔ)句,我們可以寫(xiě)成:
int number = 23
if (number < 10)
NSLog("The number is small")
但是如果有時(shí)要在后面添加新的語(yǔ)句,忘記添加{},災(zāi)難就很可能發(fā)送鸠信。
像蘋(píng)果公司自己就犯過(guò)這樣的錯(cuò)誤纵寝。下面這段代碼就是著名的goto fail錯(cuò)誤,導(dǎo)致了嚴(yán)重的安全性問(wèn)題。
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail; // :)注意 這不是Python的縮減
... other checks ...
fail:
... buffer frees (cleanups) ...
return err;
:
最終在Swift,蘋(píng)果終于在根源上消除了可能導(dǎo)致這種錯(cuò)誤的可能性星立。
if 后面的條件必須為Boolean表達(dá)式
也就是不會(huì)隱式地與0進(jìn)行比較,下面這種寫(xiě)法是錯(cuò)誤的,因?yàn)閚umber并不是一個(gè)boolean表達(dá)式,number != 0才是爽茴。
int number = 0
if number{
}
關(guān)于for
for循環(huán)在Swift中變得更方便,更強(qiáng)大。
得益于Swift新添加的范圍操作符...與...<
我們能夠?qū)⒅胺爆嵉膄or循環(huán):
for (int i = 1; i <= 5; i++)
{
NSLog(@"%d", i);
}
改寫(xiě)為:
for index in 1...5 {
print(index)
}
當(dāng)然,熟悉Python的親們知道Python的range函數(shù)很方便,我們還能自由選擇步長(zhǎng)绰垂。 像這樣:
>>> range(1,5) #代表從1到5(不包含5)
[1, 2, 3, 4]
>>> range(1,5,2) #代表從1到5室奏,間隔2(不包含5)
[1, 3]
雖然在《The Swift Programming Language》里面沒(méi)有提到類似的用法,但是在Swift中我們也有優(yōu)雅的方法辦到。
for index in stride(from: 1, through: 5, by: 2) {
print(index)
}// through是包括5
然后對(duì)字典的遍歷也增強(qiáng)了.在Objective-c的快速枚舉中我們只能對(duì)字典的鍵進(jìn)行枚舉劲装。
NSString *key;
for (key in someDictionary){
NSLog(@"Key: %@, Value %@", key, [someDictionary objectForKey: key]);
}
而在Swift中,通過(guò)tuple我們可以同時(shí)枚舉key與value:
let dictionary = ["firstName":"Mango","lastName":"Fang"]
for (key,value) in dictionary{
print(key+" "+value)
}
關(guān)于Switch
Swich在Swift中也得到了功能的增強(qiáng)與安全性的提高胧沫。
不需要Break來(lái)終止往下一個(gè)Case執(zhí)行
也就是下面這兩種寫(xiě)法是等價(jià)的。
let character = "a"
switch character{
case "a":
print("A")
break
case "b":
print("B")
break
default: print("character")
let character = "a"
switch character{
case "a":
print("A")
case "b":
print("B")
default: print("character")
這種改進(jìn)避免了忘記寫(xiě)break造成的錯(cuò)誤,自己深有體會(huì),曾經(jīng)就是因?yàn)槁?xiě)了break而花了一段時(shí)間去debug占业。
如果我們想不同值統(tǒng)一處理,使用逗號(hào)將值隔開(kāi)即可绒怨。
switch some value to consider {
case value 1,value 2:
statements
}
Switch支持的類型
在OC中,Swtich只支持int類型,char類型作為匹配。
而在Swift中,Switch支持的類型大大的拓寬了谦疾。實(shí)際上,蘋(píng)果是這么說(shuō)的南蹂。
A switch statement supports any kind of data
這意味在開(kāi)發(fā)中我們能夠能夠?qū)ψ址?浮點(diǎn)數(shù)等進(jìn)行匹配了。
之前在OC繁瑣的寫(xiě)法就可以進(jìn)行改進(jìn)了:
if ([cardName isEqualToString:@"Six"]) {
[self setValue:6];
} else if ([cardName isEqualToString:@"Seven"]) {
[self setValue:7];
} else if ([cardName isEqualToString:@"Eight"]) {
[self setValue:8];
} else if ([cardName isEqualToString:@"Nine"]) {
[self setValue:9];
}
switch carName{
case "Six":
self.vaule = 6
case "Seven":
self.vaule = 7
case "Eight":
self.vaule = 8
case "Night":
self.vaule = 9
}
3.函數(shù)
對(duì)于在OC中,方法有兩種類型,類方法與實(shí)例方法念恍。方法的組成由方法名,參數(shù),返回值組成六剥。
在Swift中函數(shù)的定義基本與OC一樣晚顷。
主要區(qū)別為:
1.通過(guò)func關(guān)鍵詞定義函數(shù)
2.返回值在->關(guān)鍵詞后標(biāo)注
各舉一個(gè)類方法與實(shí)例方法例子。
+ (UIColor*)blackColor
- (void)addSubview:(UIView *)view
對(duì)應(yīng)的swift版本
class func blackColor() -> UIColor //類方法, 通過(guò) class func 關(guān)鍵詞聲明
func addSubview(view: UIView) //實(shí)例方法
改進(jìn):
- 在Swift中,函數(shù)的最重要的改進(jìn)就是函數(shù)作為一等公民(first-class),和對(duì)象一樣可以作為參數(shù)進(jìn)行傳遞,可以作為返回值,函數(shù)式編程也成為了Swift支持的編程范式疗疟。
In computer science, a programming language is said to have first-class functions if it treats functions as first-class citizens. Specifically, this means the language supports passing functions as arguments to other functions, returning them as the values from other functions, and assigning them to variables or storing them in data structures
讓我們初略感受一下函數(shù)式編程的魅力:
舉一個(gè)例子,我們要篩選出一個(gè)數(shù)組里大于4的數(shù)字该默。
在OC中我們可能會(huì)用快速枚舉來(lái)進(jìn)行篩選。
NSArray *oldArray = @[@1,@2,@3,@4,@5,@6,@7,@8,@9,@10];
NSMutableArray *newArray;
for (NSNumber* number in oldArray) {
if ([number compare:@4] == NSOrderedDescending ) {
[newArray addObject:number];
}
}
而在Swift中,我們用兩行代碼解決這個(gè)問(wèn)題:
let oldArray = [1,2,3,4,5,6,7,8,9,10]
let newArray = oldArray.filter({$0 > 4})
進(jìn)一步了解Swift的函數(shù)式編程可以通過(guò)這篇優(yōu)秀的博客Functional Reactive Programming in Swift
- 個(gè)人覺(jué)得另外一個(gè)很棒的改進(jìn)是:Default parameter values
在我們的項(xiàng)目中,經(jīng)常會(huì)不斷進(jìn)行功能的增添策彤。為了新增特性,許多方法在開(kāi)發(fā)的過(guò)程中不斷變動(dòng)权均。舉一個(gè)例子:我們開(kāi)始有一個(gè)tableViewCell,它的設(shè)置方法一開(kāi)始簡(jiǎn)單地需要一個(gè)Model參數(shù):
func configureCellWithModel(Model: model)
不久之后,我們想對(duì)部分Cell增添一個(gè)設(shè)置背景顏色的功能。方法需要再接收多一個(gè)參數(shù):
func configureCellWithModel(Model: model,color:UIColor)
這個(gè)時(shí)候方法改變,所以涉及到這些方法的地方都需要修改锅锨。給我們?cè)斐傻睦_
一是:需要做許多重復(fù)修改的工作叽赊。
二是:無(wú)法做得很好的擴(kuò)展和定制,有些地方的cell需要設(shè)置顏色,有些不需要。但是在OC里,我們只能對(duì)所有的cell都賦值必搞。你可能覺(jué)得我們可以寫(xiě)兩個(gè)方法,一個(gè)接收顏色參數(shù),一個(gè)不接受必指。但是我們知道這不是一個(gè)很好的解決方法,會(huì)造成冗余的代碼,維護(hù)起來(lái)也不方便。
而在Swift中,default parameter values的引入讓我們能夠這樣修改我們的代碼:
func configureCellWithModel(Model: model,color:UIColor = UIColor.whiteColor())
這樣的改進(jìn)能讓我們寫(xiě)出的代碼更具向后兼容性,減少了我們的重復(fù)工作量,減少了犯錯(cuò)誤的可能性恕洲。
4.類與初始化(Initializers)
- 文件結(jié)構(gòu)與訪問(wèn)控制
在swift中,一個(gè)類不再分為interface(.h)與implementation(.m)兩個(gè)文件實(shí)現(xiàn),直接在一個(gè).swift文件里進(jìn)行處理塔橡。好處就是我們只需管理一份文件,以往兩頭奔波修改的情況就得到解放了,也減少了頭文件與實(shí)現(xiàn)文件不同步導(dǎo)致的錯(cuò)誤。
這時(shí)我們會(huì)想到,那么我們?nèi)绾蝸?lái)定義私有方法與屬性呢,在OC中我們通過(guò)在class extension中定義私有屬性,在.m文件定義私有方法霜第。
而在Swift中,我們通過(guò)Access Control來(lái)進(jìn)行控制葛家。
"properties, types, functions等能夠進(jìn)行版本控制的統(tǒng)稱為實(shí)體。
- Public:可以訪問(wèn)自己模塊或應(yīng)用中源文件里的任何實(shí)體泌类,別人也可以訪問(wèn)引入該模塊中源文件里的所有實(shí)體癞谒。通常情況下,某個(gè)接口或Framework是可以被任何人使用時(shí)刃榨,你可以將其設(shè)置為public級(jí)別弹砚。
- Internal:可以訪問(wèn)自己模塊或應(yīng)用中源文件里的任何實(shí)體,但是別人不能訪問(wèn)該模塊中源文件里的實(shí)體枢希。通常情況下桌吃,某個(gè)接口或Framework作為內(nèi)部結(jié)構(gòu)使用時(shí),你可以將其設(shè)置為internal級(jí)別苞轿。
- Private:只能在當(dāng)前源文件中使用的實(shí)體茅诱,稱為私有實(shí)體。使用private級(jí)別搬卒,可以用作隱藏某些功能的實(shí)現(xiàn)細(xì)節(jié)"
一個(gè)小技巧,如果我們有一系列的私有方法,我們可以把它們組織起來(lái),放進(jìn)一個(gè)extension里,這樣就不需要每個(gè)方法都標(biāo)記private,同時(shí)也便于管理組織代碼:
// MARK: Private
private extension ViewController {
func privateFunction() {
}
}
- 創(chuàng)建對(duì)象與alloc和init
關(guān)于初始化,在Swift中創(chuàng)建一個(gè)對(duì)象的語(yǔ)法很簡(jiǎn)潔:只需在類名后加一對(duì)圓括號(hào)即可瑟俭。
var shape = Shape()
而在Swift中,initializer也與OC有所區(qū)別,Swift的初始化方法不返回?cái)?shù)據(jù)。而在OC中我們通常返回一個(gè)self指針秀睛。
"Unlike Objective-C initializers, Swift initializers do not return a value. Their primary role is to ensure that new instances of a type are correctly initialized before they are used for the first time."
Swift的初始化方法讓我們只關(guān)注對(duì)象的初始化尔当。之前在OC世界中為什么要self = [super init]莲祸?蹂安。這種問(wèn)題得以避免椭迎。Swift幫助我們處理了alloc的過(guò)程。也讓我們的代碼更簡(jiǎn)潔明確田盈。
而在Swift中,init也有了更嚴(yán)格的規(guī)則畜号。
- 對(duì)于所有Stored Properties,都必須在對(duì)象被創(chuàng)建出來(lái)前設(shè)置好。也就是我們必須在init方法中賦好值,或是直接給屬性提供一個(gè)默認(rèn)值允瞧。
如果有property可以被允許在初始出來(lái)時(shí)沒(méi)有值,也就是需要在創(chuàng)建出來(lái)后再賦值,或是在程序運(yùn)行過(guò)程都可能不會(huì)被賦值简软。那么這個(gè)property必須被聲明為optional類型。該類型的屬性會(huì)在init的時(shí)候初始化為nil. - initializer嚴(yán)格分為Designated Initializer和Convenience Initializer 并且有語(yǔ)法定義述暂。
而在Objective-C中沒(méi)有明確語(yǔ)法標(biāo)記哪個(gè)初始化方式是convenience方法痹升。關(guān)于Designated Initializer可參閱之前的:Objective-C 拾遺:designated initializer
init(parameters) {
statements
}
convenience init(parameters) {
statements
}
5.枚舉與結(jié)構(gòu)體
- 枚舉
在Swift中,枚舉是一等公民。(first-class)畦韭。能夠擁有方法,computed properties等以往只有類支持的特性疼蛾。
在C中,枚舉為每個(gè)成員指定一個(gè)整型值。而在Swift中,枚舉更強(qiáng)大和靈活艺配。我們不必給枚舉成員提供一個(gè)值察郁。如果我們想要為枚舉成員提供一個(gè)值(raw value),我們可以用字符串,字符,整型或浮點(diǎn)數(shù)類型。
enum CompassPoint {
case North
case South
case East
case West
}
var directionToHead = CompassPoint.West
- 結(jié)構(gòu)體
Struct在Swift中和類有許多相同的地方,可以定義屬性,方法,初始化方法,可通過(guò)extension擴(kuò)展等转唉。
不同的地方在于struct是值類型.在傳遞的過(guò)程中都是通過(guò)拷貝進(jìn)行皮钠。
在這里要提到在前面第一節(jié)處提到了String,Array和Dictionary在Swift是以值類型出現(xiàn)的。這背后的原因就是String,Array,Dictionary在Swift中是通過(guò)Struct實(shí)現(xiàn)的赠法。而之前在Objective-C它們都是通過(guò)class實(shí)現(xiàn)的麦轰。
Swift中強(qiáng)大的Struct使得我們能夠更多與值類型打交道。Swift的值類型增強(qiáng)了不可變性(Immutabiliity)砖织。而不可變性提升了我們代碼的穩(wěn)定性,多線程并發(fā)的安全性原朝。
在WWDC2014《Advanced iOS Application Architecture and Patterns》中就有一節(jié)的標(biāo)題是Simplify with immutability。
延伸閱讀:WWDC心得:Advanced iOS Application Architecture and Patterns
6.協(xié)議(Protocols)
- 語(yǔ)法:
在Objective-C中我們這么聲明Protocol:
@protocol SampleProtocol
- (void)someMethod;
@end
而在Swift中:
protocol SampleProtocol
{
func someMethod()
}
在Swift遵循協(xié)議:
class AnotherClass: SomeSuperClass, SampleProtocol
{
func someMethod() {}
}
那么之前Objective-C的protocol中,我們可以標(biāo)志optional镶苞。那在Swift中呢喳坠?
遺憾的是,目前純Swift的protocol還不支持optional。但根據(jù)蘋(píng)果官方論壇的一位員工的回答,未來(lái)Swift是會(huì)支持的茂蚓。
"Optional methods in protocols are limited to @objc protocols only because we haven't implemented them in native protocols yet. This is something we plan to support. We've gotten a number of requests for abstract/pure virtual classes and methods too.
— Joe Groff
Source: https://devforums.apple.com/message/1051431#1051431
protocol和delegate是緊密聯(lián)系的壕鹉。那么我們?cè)赟wift中如何定義Delegate呢?
protocol MyDelegate : class {
}
class MyClass {
weak var delegate : MyDelegate?
}
注意到上面的protocol定義后面跟著的class聋涨。這意味著該protocol只能被class類型所遵守晾浴。
并且只有遵守了class protocol的delegate才能定義為weak。這是因?yàn)樵赟wift中,除了class能夠遵守協(xié)議,枚舉和結(jié)構(gòu)同樣能夠遵守協(xié)議牍白。而枚舉和結(jié)構(gòu)是值類型,不存在內(nèi)存管理的問(wèn)題脊凰。因此只需要class類型的變量聲明為weak即可。
利用Swift的optional chaining,我們能夠很方便的檢查delegate是否為Nil,是否有實(shí)現(xiàn)某個(gè)方法:
以前我們要在Objective-C這樣檢查:
if (self.dataSource && [self.dataSource respondsToSelector:@selector(titleForSegmentAtIndex:)]) {
thisSegmentTitle = [self.dataSource titleForSegmentAtIndex:index];
}
在Swift中,非常的優(yōu)雅簡(jiǎn)潔。
if let thisSementTitle = dataSource?.titleFroSegmentAtIndex?(index){
}
新特性:
在Swift中,protocol變得更加強(qiáng)大,靈活:
class,enum,structure都可以遵守協(xié)議狸涌。
Extension也能遵守協(xié)議切省。利用它,我們不需要繼承,也能夠讓系統(tǒng)的類也遵循我們的協(xié)議。
例如:
protocol myProtocol {
func hello() -> String
}
extension String:myProtocol{
func hello() -> String {
return "hello world!"
}
}
我們還能夠用這個(gè)特性來(lái)組織我們的代碼結(jié)構(gòu),如下面的代碼所示,將UITableViewDataSource的實(shí)現(xiàn)移到了Extension帕胆。使代碼更清晰朝捆。
// MARK: - UITableViewDataSource
extension MyViewcontroller: UITableViewDataSource {
// table view data source methods
}
3 . Protocol Oriented Programming
隨著Swift2.0的發(fā)布,面向協(xié)議編程正式也加入到了Swift的編程范式。Cool.
這種編程方式通過(guò)怎樣的語(yǔ)法特性支撐的呢懒豹?
那就是我們能夠?qū)f(xié)議進(jìn)行擴(kuò)展,也就是我們能夠提供協(xié)議的默認(rèn)實(shí)現(xiàn),能夠?yàn)閰f(xié)議添加新的方法與實(shí)現(xiàn)芙盘。
用前面的myProtocol為例子,我們?cè)赟wift里這樣為它提供默認(rèn)實(shí)現(xiàn)。
extension myProtocol{
func hello() -> String {
return "hello world!"
}
}
我們還能對(duì)系統(tǒng)原有的protocol進(jìn)行擴(kuò)展,大大增強(qiáng)了我們的想象空間脸秽。Swift2.0的實(shí)現(xiàn)也有很多地方用extension protocol的形式進(jìn)行了重構(gòu)儒老。
面向協(xié)議編程能夠展開(kāi)說(shuō)很多,在這里這簡(jiǎn)單地介紹了語(yǔ)法。有興趣的朋友可以參考下面的資料:
Session 408: Protocol-Oriented Programming in Swift
IF YOU'RE SUBCLASSING, YOU'RE DOING IT WRONG.
7.Swift與Cocoa
一門(mén)語(yǔ)言的的強(qiáng)大與否,除了自身優(yōu)秀的特性外,很大一點(diǎn)還得依靠背后的框架记餐。Swift直接采用蘋(píng)果公司經(jīng)營(yíng)了很久的Cocoa框架〈ぃ現(xiàn)在我們來(lái)看看使用Swift和Cocoa交互一些需要注意的地方。
- id與AnyObject
在Swift中,沒(méi)有id類型,Swift用一個(gè)名字叫AnyObject的protocol來(lái)代表任意類型的對(duì)象剥扣。
id myObject = [[UITableViewCell alloc]init];
var myObject: AnyObject = UITableViewCell()
我們知道id的類型直到運(yùn)行時(shí)才能被確定,如果我們向一個(gè)對(duì)象發(fā)送一條不能響應(yīng)的消息,就會(huì)導(dǎo)致crash巩剖。
我們可以利用Swift的語(yǔ)法特性來(lái)防止這樣的錯(cuò)誤:
myObject.method?()
如果myObject沒(méi)有這個(gè)方法,就不會(huì)執(zhí)行,類似檢查delegate是否有實(shí)現(xiàn)代理方法。
在Swift中,在AnyObject上獲取的property都是optional的钠怯。
2 . 閉包
OC中的block在Swift中無(wú)縫地轉(zhuǎn)換為閉包佳魔。函數(shù)實(shí)際上也是一種特殊的閉包。
3 . 錯(cuò)誤處理
之前OC典型的錯(cuò)誤處理步驟:
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *URL = [NSURL fileURLWithPath:@"/path/to/file"];
NSError *error = nil;
BOOL success = [fileManager removeItemAtURL:URL error:&error];
if (!success) {
NSLog(@"Error: %@", error.domain);
}
在Swift中:
let fileManager = NSFileManager.defaultManager()
let URL = NSURL.fileURLWithPath("/path/to/file")
do {
try fileManager.removeItemAtURL(URL)
} catch let error as NSError {
print("Error: \(error.domain)")
}
4 . KVO
Swift支持KVO晦炊。但是KVO在Swift,個(gè)人覺(jué)得是不夠優(yōu)雅的,KVO在Swift只限支持繼承NSObject的類,有其局限性,在這里就不介紹如何使用了鞠鲜。
網(wǎng)上也出現(xiàn)了一些開(kāi)源庫(kù)來(lái)解決這樣的問(wèn)題。有興趣可以參考一下:
KVO 在OS X中有Binding的能力,也就是我們能夠?qū)蓚€(gè)屬性綁定在一起,一個(gè)屬性變化,另外一個(gè)屬性也會(huì)變化断国。對(duì)與UI和數(shù)據(jù)的同步更新很有幫助,也是MVVM架構(gòu)的需求之一贤姆。之前已經(jīng)眼饞這個(gè)特性很久了,雖然Swift沒(méi)有原生帶來(lái)支持,Swift支持的泛型編程給開(kāi)源界帶來(lái)許多新的想法。下面這個(gè)庫(kù)就是實(shí)現(xiàn)binding的效果稳衬。
8.總結(jié)
到這里就基本介紹完Swift當(dāng)中最基本的語(yǔ)法和與Objective-C的對(duì)比和改進(jìn)霞捡。
事實(shí)上Swift的世界相比OC的世界還有很多新鮮的東西等待我們?nèi)グl(fā)現(xiàn)和總結(jié),Swift帶來(lái)的多范式編程也將給我們編程的架構(gòu)和代碼的組織帶來(lái)更來(lái)的思考。而Swift也是一個(gè)不斷變化,不斷革新的語(yǔ)言薄疚。相信未來(lái)的發(fā)展和穩(wěn)定性會(huì)更讓我們驚喜碧信。這篇文章也將隨著Swift的更新而不斷更新,同時(shí)限制篇幅,突出重點(diǎn)。
希望這篇文章能夠給各位同行的小伙伴們快速了解和學(xué)習(xí)Swift提供一點(diǎn)幫助街夭。有疏漏錯(cuò)誤的地方歡迎直接提出砰碴。感謝。
參考:
1.《The Swift Programming Language》
2.Apple Swift Blog
3.Using Swift with Cocoa and Objective-C