偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

從Objective-C到Swift:幾點(diǎn)想法和意見(jiàn)

移動(dòng)開發(fā) iOS
在這篇文章里我想跟大家談?wù)動(dòng)嘘P(guān)我近來(lái)從Objective-C過(guò)渡到Swift的一些感受。我會(huì)盡可能的給大家一些意見(jiàn),提示一些誤區(qū)并比較一下在兩種語(yǔ)言之間的差異。話不多說(shuō),讓我們開門見(jiàn)山。

在這篇文章里我想跟大家談?wù)動(dòng)嘘P(guān)我近來(lái)從Objective-C過(guò)渡到Swift的一些感受。我會(huì)盡可能的給大家一些意見(jiàn),提示一些誤區(qū)并比較一下在兩種語(yǔ)言之間的差異。話不多說(shuō),讓我們開門見(jiàn)山。

注意:本文討論的開發(fā)環(huán)境為Xcode 6 beta 2版本。

單一文件結(jié)構(gòu) VS 接口-實(shí)現(xiàn)

最值得一提的一大改動(dòng)便是在Objective-C中“[接口].h/[實(shí)現(xiàn)].m”這種文件結(jié)構(gòu)被取締了。

其實(shí)我本人是很支持這種文件結(jié)構(gòu)的,因?yàn)橥ㄟ^(guò)接口文件來(lái)獲取及共享類特性的方式相當(dāng)安全而且簡(jiǎn)單,不過(guò)現(xiàn)在不得不面對(duì)它不復(fù)存在的現(xiàn)實(shí)了。

在Swift中并不存在接口與實(shí)現(xiàn)分割成兩個(gè)文件的現(xiàn)象,我們僅需要依靠實(shí)現(xiàn)來(lái)構(gòu)建一個(gè)類就行了(并且在寫的時(shí)候甚至不可能添加關(guān)于可訪問(wèn)性的修改)。

如果對(duì)于這一改動(dòng)感到無(wú)法忍受的話應(yīng)注意以下事項(xiàng):

最為明顯的:靠直覺(jué)。

我們可以借助漂亮的文檔來(lái)提高類的可讀性。舉個(gè)例子,我們可以把所有想作為public的要素全部挪到文件開頭去,也可以采用擴(kuò)展來(lái)區(qū)分public和private。

另一個(gè)很實(shí)用的辦法就是在private的方法和變量命名前加一個(gè)下劃線'_'作為前綴。

下面是混合了以上兩種方案的示例:

  1. // Public 
  2. extension DataReader { 
  3.        
  4.     var data { } 
  5.     func readData(){ 
  6.         var data = _webserviceInteraction() 
  7.     } 
  8.    
  9. // Private implementation 
  10. class DataReader: NSObject { 
  11.       
  12.     let _wsURL = NSURL(string: "http://theurl.com"
  13.        
  14.     func _webserviceInteraction()->String{ 
  15.         // ... 
  16.     } 

雖然我們沒(méi)辦法修改類中各元素的可見(jiàn)性,不過(guò)我們可以試著讓某些訪問(wèn)變得“困難一些”。

一個(gè)特殊的方法就是使用嵌套類來(lái)把private部分隱藏起來(lái)(至少是自動(dòng)的隱藏),下面是例子:

  1. import UIKit 
  2.    
  3. class DataReader: NSObject { 
  4.        
  5.     // Public *********************** 
  6.     var data:String?{ 
  7.         get{return private.internalData} 
  8.     } 
  9.        
  10.     init(){ 
  11.         private = DataReaderPrivate() 
  12.     } 
  13.    
  14.     func publicFunction(){ 
  15.         private.privateFunc() 
  16.     } 
  17.    
  18.        
  19.     // Private ********************** 
  20.     var private:DataReaderPrivate 
  21.        
  22.     class DataReaderPrivate { 
  23.         var internalData:String? 
  24.            
  25.         init(){ 
  26.             internalData = "Private data!" 
  27.         } 
  28.            
  29.         func privateFunc (){} 
  30.     } 

我們將private的實(shí)現(xiàn)放入一個(gè)private常量的實(shí)例中,然后用“正常”的類的實(shí)現(xiàn)來(lái)充當(dāng)接口。不過(guò)private部分并非會(huì)真正的隱藏起來(lái),只不過(guò)在訪問(wèn)的時(shí)候需要加上一個(gè)private關(guān)鍵字了:

  1. let reader = DataReader() 
  2. reader.private.privateFunc() 

問(wèn)題來(lái)了:僅是為了***要將這些private的部分隱藏起來(lái)要把代碼寫得這樣怪異值得嗎?

我的建議是在可見(jiàn)性的修改出來(lái)之前(蘋果正在忙這個(gè)事),我們還是采用詳細(xì)的文檔或者多少用一點(diǎn)擴(kuò)展來(lái)完成這個(gè)事。

常量和變量

在 寫Objective-C的時(shí)候我會(huì)很少的使用到const關(guān)鍵字,甚至于我知道有的數(shù)據(jù)時(shí)不會(huì)變的(好吧不要吐槽我)。然而在Swift中蘋果建議開發(fā) 者們多花點(diǎn)心思在使用常量(let)而不是變量(var)上。所以請(qǐng)注意要弄明白你的變量的具體要做什么。你會(huì)使用常量的頻繁度將是你從未想象過(guò)的。

更加簡(jiǎn)化的寫法

來(lái)看一下下面的兩行代碼并比較有何不同:

  1. let wsURL:NSURL = NSURL(string:"http://wsurl.com"); 
  2. vs 
  3. let wsURL = NSURL(string:"http://wsurl.com"

在我最開始接觸Swift的前兩個(gè)星期我強(qiáng)迫自己不要在每一行代碼***都添加分號(hào),現(xiàn)在我感到人生圓滿(不過(guò)現(xiàn)在寫Objective-C的時(shí)候我不會(huì)加分號(hào)了)。

類型推斷可以直接根據(jù)變量的定義為其指派類型,相比較Objective-C這類冗雜的語(yǔ)言來(lái)說(shuō),在這里倒是可圈可點(diǎn)。

我們應(yīng)該使用一致的命名方式,否則其他的開發(fā)者(包括你自己)就很難通過(guò)極其糟糕的命名來(lái)推測(cè)其類型:

  1.  
  2.    

     

  3. let a = something() 

更加合理的命名是這樣的:

 

 

  1. let a = anInt() 

還有一個(gè)改動(dòng)就是關(guān)于括弧號(hào),他們不再需要配對(duì)了:

  1. if (a > b){} 
  2.      vs    
  3. if a > b {} 

不過(guò)請(qǐng)記住,我們?cè)诶ㄌ?hào)中間寫入的部分會(huì)被認(rèn)為是一個(gè)表達(dá)式,在這里不總是代表這樣寫是對(duì)的。在變量綁定時(shí)我們不能像下面這樣使用括號(hào):

  1. if (let x = data){} // Error!  
  2. if let x = data {} // OK! 

使用類型判斷和刪除分號(hào)及括號(hào)并不完全必要,不過(guò)我們可以考慮一下用以上建議的方式來(lái)寫Swift代碼,這樣的話會(huì)提高代碼的可讀性并且減少一些輸入量。

可選值

有多少次我們困惑與函數(shù)的返回值該如何設(shè)置?我曾經(jīng)使用過(guò)NSNotFound, -1, 0,自定義的返回值來(lái)表示返回為空。

現(xiàn)在有了可選值的出現(xiàn)很好的解決了返回值為空的問(wèn)題,我們僅需要在數(shù)據(jù)類型的后面添加一個(gè)問(wèn)號(hào)就可以了。

我們可以這樣寫:

  1. class Person{ 
  2.     let name:String 
  3.     let car:Car? // Optional value 
  4.        
  5.     init(name:String){ 
  6.         self.name = name 
  7.     } 
  8.    
  9. // ACCESSING THE OPTIONAL VALUE *********** 
  10.    
  11. var Mark = Person(name:"mark"
  12.    
  13. // use optional binding  
  14. if let car = Mark.car { 
  15.     car.accelerate() 
  16.    
  17. // unwrap the value 
  18. Mark.car?.accelerate() 

這是個(gè)用了可選值來(lái)描述“某人有一輛車”的例子,它表示car這一特征可以是沒(méi)有的,因?yàn)檫@表示某人沒(méi)有車。

然后我們可以用optional binding或者unwrap來(lái)取得它的值。

如果對(duì)于一個(gè)屬性沒(méi)有設(shè)定為可選值,我們又沒(méi)有為其賦值的話,編譯器會(huì)立馬不爽快的。

一旦初始化了之后便沒(méi)有設(shè)定非可選屬性的機(jī)會(huì)了。

所以我們應(yīng)該事先考慮一下類的屬性與其它部分的關(guān)系以及在類進(jìn)行實(shí)例化的時(shí)候它們會(huì)發(fā)生什么變化。

這些改進(jìn)徹底的改變了構(gòu)思一個(gè)類的方式。

可選值的拆包

你會(huì)發(fā)現(xiàn)可選值這個(gè)東西難以理喻,因?yàn)槟悴粫?huì)理解為什么編譯器會(huì)提示你在使用之前對(duì)其進(jìn)行拆包。

Mark.car?

我建議你把可選值當(dāng)做一個(gè)結(jié)構(gòu)體(當(dāng)做結(jié)構(gòu)體的話會(huì)好理解一些),其中包括了一個(gè)你所設(shè)定的值。不過(guò)外面包裹了其他東西(wrap)。如果里面的值有定義,你就可以進(jìn)行拆包(unwrap)然后得到你所想得到的值。否則你就得到一個(gè)空值(nil)。

使用感嘆號(hào)"!"來(lái)進(jìn)行強(qiáng)制拆包而不管其中的值是否有定義,這樣做是有風(fēng)險(xiǎn)的,因?yàn)槿绻锩娴闹禌](méi)有定義的話應(yīng)用會(huì)崩掉。

委托模式

經(jīng)過(guò)多年的Objective-C和Cocoa代碼編寫我想大部分人都對(duì)使用委托模式養(yǎng)成了一種嗜好。注意了!我們還是可以繼續(xù)保留這種嗜好的,下面是一個(gè)非常簡(jiǎn)單的例子:

  1. @objc protocol DataReaderDelegate{ 
  2.     @optional func DataWillRead() 
  3.     func DataDidRead() 
  4.    
  5. class DataReader: NSObject { 
  6.       
  7.     var delegate:DataReaderDelegate? 
  8.     var data:NSData? 
  9.    
  10.     func buildData(){ 
  11.            
  12.         delegate?.DataWillRead?() // Optional method check 
  13.         data = _createData() 
  14.         delegate?.DataDidRead()       // Required method check 
  15.     } 

這里我們使用了一個(gè)簡(jiǎn)單的@optional來(lái)替換了使用respondToSelector檢測(cè)委托方法是否存在。

  1. delegate?.DataWillRead?() 

請(qǐng)注意我們?cè)趨f(xié)議之前必須加@obj前綴,因?yàn)楹竺媸褂昧薂optional。同時(shí)編譯器也會(huì)在這里報(bào)一個(gè)警告的消息以防你沒(méi)有加上@obj。

要實(shí)現(xiàn)協(xié)議的話,我們需要構(gòu)建一個(gè)類來(lái)實(shí)現(xiàn)它然后用曾經(jīng)在OC上用過(guò)的方式來(lái)指派。

  1. class ViewController: UIViewController, DataReaderDelegate { 
  2.                                
  3.     override func viewDidLoad() { 
  4.         super.viewDidLoad() 
  5.            
  6.         let reader = DataReader() 
  7.         reader.delegate = self 
  8.     } 
  9.    
  10.     func DataWillRead() {...} 
  11.        
  12.     func DataDidRead() {...} 

目標(biāo)-動(dòng)作模式

另一常用的設(shè)計(jì)模式:目標(biāo)-動(dòng)作模式。我們?nèi)匀煌瑯涌梢韵裨贠C中使用它那樣在Swift中實(shí)現(xiàn)它。

  1. class ViewController: UIViewController { 
  2.        
  3.     @IBOutlet var button:UIButton 
  4.        
  5.     override func viewDidLoad() { 
  6.         super.viewDidLoad() 
  7.            
  8.         button.addTarget(self, action: "buttonPressed:", forControlEvents: UIControlEvents.TouchUpInside) 
  9.     } 
  10.    
  11.     func buttonPressed(sender:UIButton){...} 

這里唯一不同的地方就是如何定義一個(gè)selector選擇器。我們可以變形使用像下面這樣的字符串來(lái)寫方法原型:

  1. Selector("buttonPressed:"

單件模式

簡(jiǎn)直又愛(ài)又恨。單件模式依舊是設(shè)計(jì)模式中最為常用的模式之一。

我們可以用GCD和dispatch_once來(lái)實(shí)現(xiàn)它,當(dāng)然還可以用let關(guān)鍵字來(lái)實(shí)現(xiàn)線程安全。

  1. class DataReader: NSObject { 
  2.        
  3.     class var sharedReader:DataReader { 
  4.            
  5.         struct Static{ 
  6.             static let _instance = DataReader() 
  7.         } 
  8.            
  9.         return Static._instance 
  10.     } 
  11. ... 

我們來(lái)快速瀏覽一下這段代碼:

1.sharedReader是一個(gè)靜態(tài)的復(fù)合屬性(我們也可以替換為方法)。

2.靜態(tài)屬性不允許在類被實(shí)現(xiàn)的時(shí)候重構(gòu),所以由于內(nèi)部類型是被允許的,我們可以再這里加入一個(gè)結(jié)構(gòu)體。

3._instance是一個(gè)常量,它不會(huì)被重寫而且保證線程安全。

可以參考下面DataReader單例的用法:

 
  1. DataReader.sharedReader 

結(jié)構(gòu)和枚舉

Swift中的結(jié)構(gòu)和枚舉簡(jiǎn)直神乎其神,你根本不會(huì)在其他的語(yǔ)言里面找到像它們這樣的。

它們支持方法:

  1. struct User{ 
  2.     // Struct properties 
  3.     let name:String 
  4.     let ID:Int 
  5.        
  6.     // Method!!! 
  7.     func sayHello(){ 
  8.         println("I'm " + self.name + " my ID is: \(self.ID)"
  9.     } 
  10.    
  11. let pamela = User(name: "Pamela", ID: 123456
  12. pamela.sayHello() 

如你所見(jiàn)在這里的結(jié)構(gòu)體使用了初始化,而且這個(gè)是Swift自動(dòng)創(chuàng)建的(我們可以添加一些自定的實(shí)現(xiàn))。

枚舉類型的語(yǔ)法比起我們用過(guò)的會(huì)稍難。

它的定義需要用到關(guān)鍵字case:

  1. enum Fruit {  
  2.   case orange 
  3.   case apple 

而且枚舉并不局限于int型:

  1. enum Fruit:String {  
  2.   case .orange = "Orange" 
  3.   case .apple = "Apple" 

而且還可以用的更復(fù)雜一些:

  1. enum Fruit{ 
  2.        
  3.     // Available Fruits 
  4.     case orange 
  5.     case apple 
  6.        
  7.     // Nested type 
  8.     struct Vitamin{ 
  9.         var name:String 
  10.     } 
  11.        
  12.     // Compound property 
  13.     var mainVitamin:Vitamin { 
  14.        
  15.     switch self{ 
  16.     case .orange: 
  17.         return Vitamin(name: "C"
  18.            
  19.     case .apple: 
  20.         return Vitamin(name: "B"
  21.         } 
  22.     } 
  23. }  
  24.    
  25. let Apple = Fruit.apple 
  26. var Vitamin = Apple.mainVitamin 

在上面我們?yōu)镕ruit枚舉類添加了一個(gè)內(nèi)部類型Vitamin和一個(gè)復(fù)合的mainVitamin,并且這樣的結(jié)構(gòu)還可以根據(jù)枚舉的值來(lái)進(jìn)行初始化里面的元素……是不是已經(jīng)感到眼花繚亂了?

可變與不可變類

在OC中我們總會(huì)用到可變以及不可變類,舉個(gè)例子?NSArray和NSDictionary。在Swift里面我們不在像這樣來(lái)區(qū)分?jǐn)?shù)據(jù)了,只需要用常量和變量的定義來(lái)替代。

數(shù)據(jù)變量是可以變的而數(shù)組常量的值不可更改。所以請(qǐng)記下這個(gè)公式:

“let = immutable. var = mutable”.

塊和閉包

我非常喜歡塊的語(yǔ)法,因?yàn)樗喈?dāng)簡(jiǎn)單而且好記。

  1. <p> 

順帶提一下,因?yàn)橛卸嗄闏ocoa的變成習(xí)慣所以有時(shí)候我會(huì)偏愛(ài)于用塊來(lái)替代簡(jiǎn)單的委托作業(yè)。這是很靈活快捷的方式,而且非常實(shí)用。

Swift中與塊相對(duì)的是閉包。閉包的作用極為強(qiáng)大而且蘋果在將其簡(jiǎn)單化上做得很棒,很容易就可以實(shí)現(xiàn)。

官方文檔里的示例只能說(shuō)讓我無(wú)言以對(duì)。

它是這樣定義的:

  1. reversed = sort(names, { (s1: String, s2: String) -> Bool in 
  2.     return s1 > s2 
  3. }) 

然后是這樣重構(gòu)的:

  1. reversed = sort(names, >) 

所以,由于類型判斷的存在我們能以不同的方式來(lái)實(shí)現(xiàn)一個(gè)閉包、速寫參數(shù)($0, $1)和直接操作函數(shù)(>)。

在這篇文章里我打算遍歷一下閉包的用法不過(guò)此前我想對(duì)如何獲取閉包中的值說(shuō)幾句。

在OC里面,我們定義一個(gè)變量像_block這樣,以方便我們想預(yù)備將它壓入塊。不過(guò)在閉包里面這些都沒(méi)有必要。

我們可以使用和修改周圍的值。事實(shí)上閉包被設(shè)計(jì)得非常聰明,足夠它獲取外部的元素來(lái)給內(nèi)部使用。每個(gè)被獲取的元素會(huì)作為拷貝或者是引用。如果閉包會(huì)修改它的值則創(chuàng)建一個(gè)引用,否則就生成一份拷貝。

如果閉包引用了一個(gè)包含或調(diào)用了閉包本身的實(shí)例,我們就會(huì)進(jìn)入一個(gè)循環(huán)強(qiáng)引用。

來(lái)看一下例子:

  1. class Person{ 
  2.        
  3.     var age:Int = 0 
  4.        
  5.     @lazy var agePotion: (Int) -> Void = { 
  6.         (agex:Int)->Void in 
  7.             self.age += agex 
  8.     } 
  9.        
  10.     func modifyAge(agex:Int, modifier:(Int)->Void){ 
  11.         modifier(agex) 
  12.     }    
  13.    
  14. var Mark:Person? = Person() 
  15. Mark!.modifyAge(50, Mark!.agePotion) 
  16. Mark = nil // Memory Leak 

這個(gè)agePotion閉包引用了它本身,而對(duì)當(dāng)前的實(shí)例保證了強(qiáng)引用。同時(shí)實(shí)例保持了一個(gè)隊(duì)閉包的引用。BOOM~~~我們進(jìn)入了一個(gè)循環(huán)強(qiáng)引用。

為了避免這種情況我們需要使用獲取列表Capture List.這個(gè)列表維護(hù)了我們想使用的實(shí)例的無(wú)主弱引用。語(yǔ)法十分簡(jiǎn)單,只需要在閉包定義前添加 [unowned/strong self] 就行,然后你會(huì)得到一個(gè)無(wú)主的弱引用來(lái)替代以前的強(qiáng)引用。

  1. @lazy var agePotion: (Int) -> Void = { 
  2.      [unowned self](agex:Int)->Void in 
  3.          self.age += agex 

無(wú)主弱引用

在OC里面我們知道弱引用是怎么運(yùn)作的。在Swift里面也一樣,基本沒(méi)什么變化。

所以什么是無(wú)主引用呢。我仔細(xì)的看了看這個(gè)關(guān)鍵詞的介紹,因?yàn)樗芎玫恼f(shuō)明了類間的關(guān)系的定義。

讓我們來(lái)簡(jiǎn)單的描述一下人Person與銀行賬戶BankAccount間的關(guān)系:

1.一個(gè)人可以擁有一個(gè)銀行賬戶(可選)。

2.一個(gè)銀行賬戶屬于一個(gè)人(必須)。

  1. We can describe this relation with code:  
  2. class Person{ 
  3.     let name:String 
  4.     let account:BankAccount! 
  5.        
  6.     init(name:String){ 
  7.         self.name = name 
  8.         self.account = BankAccount(owner: self) 
  9.     } 
  10.    
  11. class BankAccount{ 
  12.     let owner:Person 
  13.        
  14.     init(owner:Person){ 
  15.         self.owner = owner 
  16.     } 

這寫關(guān)系會(huì)創(chuàng)建一個(gè)引用循環(huán)。***種解決方案添加了一個(gè)弱引用給“BankAccount.owner”屬性。不過(guò)還用了一個(gè)無(wú)主引用作為約束:這個(gè)屬性必須有一個(gè)值,不能為空(之前的列表里的第二點(diǎn)令人滿意)。

好了,關(guān)于無(wú)主引用沒(méi)有更多要說(shuō)的了。其實(shí)它恰好就像一個(gè)沒(méi)有為所指引用增加作用的弱引用,不過(guò)為其保證了一個(gè)不為空的值。

總結(jié)

我不得不承認(rèn)我偶爾會(huì)在編譯器報(bào)錯(cuò)的時(shí)候無(wú)能為力的看著它心想:WTF。

我在Swift耗費(fèi)的實(shí)驗(yàn)和測(cè)試的次數(shù)越多我就會(huì)越清晰的明白其價(jià)值所在。在我們能舒坦的使用它之前脫離OC去接觸Swift開發(fā)和訓(xùn)練需要相當(dāng)大的興趣的。

本文鏈接:http://www.cocoachina.com/ios/20141011/9884.html

責(zé)任編輯:chenqingxiang 來(lái)源: cocoachina
相關(guān)推薦

2014-07-01 09:22:01

SwiftObjective-CiOS

2015-06-25 11:21:33

C++Objective-C

2015-02-05 00:18:44

SwiftObjective-C

2015-06-08 10:02:40

swiftOC兼容

2017-04-07 16:00:59

SwiftObjective-CFramework

2014-09-26 09:49:48

SwiftObjective-C

2014-06-05 13:54:03

SwiftiOSObjective-C

2014-09-24 11:15:05

Objective-CSwift

2011-07-06 14:41:34

Objective-C

2013-05-02 10:51:17

iOS開發(fā)Objective-C@property

2016-03-30 09:56:07

c語(yǔ)言變量聲明objectivec

2011-08-10 18:07:29

Objective-C反射

2015-07-08 10:47:57

Using Swift CocoaObjective-C

2013-03-27 12:54:00

iOS開發(fā)Objective-C

2011-05-11 11:20:26

Objective-C

2013-06-20 10:40:32

Objective-C實(shí)現(xiàn)截圖

2011-05-11 15:58:34

Objective-C

2011-07-08 18:44:09

Objective-C Self Super

2011-07-29 15:47:21

iPhone開發(fā) Objective- C

2011-08-02 13:16:36

Objective-C 語(yǔ)法 函數(shù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)