成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Swift開發的幾個小技巧

移動開發 iOS
正所謂掌握一樣技術最好的辦法就是用它來做一個東西,于是這段時間的實戰讓我對 Swift 的理解更深了一層,也積累了一些使用技巧。今天就分享一則:如何正確地定義一個類變量(和類常量)。

正所謂掌握一樣技術***的辦法就是用它來做一個東西,于是這段時間的實戰讓我對 Swift 的理解更深了一層,也積累了一些使用技巧。今天就分享一則:如何正確地定義一個類變量(和類常量)。

Swift 語言對于無論是靜態語言過來還是動態語言過來的開發者來說,都有點點不適應,很多問題的解決思路不能用已經習以為常的方法去做。

如何正確的定義一個類變量(和類常量)

Swift 支持用 class func 來修飾一個「類方法」,然而卻不能用「class var」和「class let」來指定類變量和類常量,一旦你嘗試這樣做了,那么 Xcode 會提示你:Class variable not yet supported。真是遺憾…

不過從這個提示可以看出,Class variable 的支持只是時間問題。那么現階段我們要怎么完成這一目標?總不能用丑陋的 Workaround 吧。辦法還是有的,我從 Apple 官方的例子中學到了如何去定義一個類級的常量和變量,那就是用 struct。

來個 demo 你就明白了:

  1. class MyClass {  
  2.      struct Constants {  
  3.          static let name = "MyClass"  
  4.      }  
  5.      struct Variables {  
  6.          static var age = 0  
  7.      }  
  8.  } 

然后在調用的時候,就可以這樣來調用: MyClass.Constants.name 和 MyClass.Variables.age

雖 然中間還隔了一層 Constants 和 Variables,但是我覺得這樣也挺好,相當于有了一個 Prefix,直接看代碼時就知道是常量還是變量了。如果你不喜歡這種方式,也可以用 computed property 的形式來模擬真實的類變量(常量)的調用。比如:

  1. extension MyClass {  
  2.     class var name: String { 
  3.        get { 
  4.            return Constants.name 
  5.        } 
  6.     } 
  7.     class var age: Int { 
  8.         get { 
  9.             return Variables.age 
  10.         } 
  11.         set { 
  12.             Variables.age = newValue 
  13.         } 
  14.     }  
  15.  } 

定義了這種方式后,就可以直接用 MyClass.name 和 MyClass.age 來訪問類常量或修改類變量了。

這種方式在語法上兼容了未來會得到支持的類變量和類常量,但就是自己要寫一大堆 getter 和 setter,有點麻煩,大家可以根據自己的需要決定是不是要采用這種方式。

關于本文的 demo 代碼,大家可以粘貼進「swift」這個命令行工具來實踐一下。效果正如我們想要的那樣,常量不允許修改,變量可以修改,所有的這些操作都是在 MyClass 上進行,而不需要實例化。

雖然現在用 Swift 來做一些常用的任務還略顯麻煩,不過作為一個年輕的語言,目前它確實已經能用在生產環境中寫出真正可用的 App 了,隨著接下去的發展,我相信它會變得越來越好的。

PS:現在我只想 SourceKitService 崩潰的少一點…

用Optional來避免異常指針問題

最近在用 Swift 開發的過程中,又碰到了一個問題。簡單的說,系統在該返回非 nil 值的地方返回了一個異常指針(即指向 0x0000 地址,產生 KERN_INVALID_ADDRESS 異常)造成了 App 的 crash,算是 iOS UIKit 的一個 Bug。

這個問題需要 SDK 的升級來解決,但是在 SDK 升級之前,我們可以通過一個小小的 Workaround 去解決。來龍去脈是這樣的:

iOS 的 Swift 版的 API 與 Objective-C 的 API ***的不同是,你需要看 Objective-C 的 API 文檔才知道一個系統返回的值是不是可能是 nil。

比如 UIDataSourceModelAssociation 這個用來還原 UITableView 和 UICollectionView 位置的 Protocol,它有兩個方法,其中一個是:

  1. 1 
  2.      
  3. - (NSString *)modelIdentifierForElementAtIndexPath:(NSIndexPath *)idx inView:(UIView *)view 
  4.  
  5. 光看 Objective-C 這個方法,你是不知道系統返回的 idx 有沒有可能是 nil 的,但是一看 Swift 版本,就非常顯然了: 
  6. 1 
  7.      
  8. func modelIdentifierForElementAtIndexPath(_ idx: NSIndexPath, inView view: UIView) -> String 
  9.  
  10. idx 和 inView 一樣,都沒有 ? 和 !,因而它們不是 Optional,所以值不可能是 nil。如果 idx 和 inView 可能是 nil 的,那么它應該是用 ! 來修飾,以警告開發者,這個值可能是 nil,請小心使用。 
  11. 1 
  12.      
  13. func modelIdentifierForElementAtIndexPath(_ idx: NSIndexPath!, inView view: UIView!) 

Swift 這種比 Objective-C 更徹底的 API 即文檔的表達形式,我在編碼一段時間后非常喜歡。

然而,也正是系統的框架還進化的不徹底的原因,這些 API 依然可能會返回 nil 的值,但是 API 因為被標記不會返回 nil,于是就會發生 swift_dynamicCastClassUnconditional 的異常,***導致 App crash。

下圖即是 modelIdentifierForElementAtIndexPath 這個方法在應該返回值的情況下,卻返回了一個指向 0x0000000000000000 的對象。然后 Swift 在包裝值的時候,沒能包裝成功而發生 crash。

 

那么如何避免因為這個問題造成的 App crash 呢?實際上很簡單,只需要手動用 Optional 包裝一下這個 0x0000 對象,再判斷它是不是 nil,就不會發生問題了。比如這樣的代碼:

  1. let optionalIdx = Optional(idx) 
  2. if optionalIdx == nil { 
  3.     return "Do something" 

剛開始遇到這個問題我也很苦惱,后來突然想到,是不是可以用 Optional 去包裝一下這種異常指針再檢查是不是 nil,一試果然可以。于是問題就這樣解決了。

幸好,這種坑沒有多到讓我抓狂的步地,我能繼續用 Swift 愉快的寫下去了…

如何用 Swift 思維設計網絡請求

近來在用 Swift 開發 App 的過程中,***的心得就是:我開始漸漸用「Swift 思維」來思考了。回顧剛開始我用 Swift 時,只是套用它的語法而已,腦子里依然是 Objective-C 思維。

這段時間,隨著對 Swift 基本特性的掌握,我開始有意識地學習并嘗試一些 Swift 才有的特性,此謂「Swift 思維」。Swift 有很多專有(Objective-C 沒有的)的模式,今天我就從一個很簡單的例子講起,那就是:

如何用 Swift 思維設計網絡請求。

做過網絡類應用的同學應該都知道,我們做一個網絡請求時,通常會有兩個結果:一個是失敗,返回錯誤,一個是成功,返回結果。當然途中還會有更復雜的情況,比如:1、網絡請求本身的失敗(比如網絡超時);2、API 端返回的內部結果型失敗(比如密碼不正確)。這里我們就不細分了。

在傳統的 Objective-C 的項目里,有幾種處理這種異常的情況,主要是:

直接判斷 NSError

  1. NSError *error = nil; 
  2. id result = [API doSomething:&error]; 
  3. if (error != nil) { 
  4.    NSLog("Oh Error!"

這種處理太直白,一般會阻塞當前的線程,因而不推薦。一般用的比較多的是下面兩種:

通過 success,failture 的 block 來處理

  1. [API doSomethingWithSuccess:^(id result) { 
  2.     NSLog(@"Seems good"
  3. } failure:^(NSError *error) { 
  4.     NSLog(@"Oh Error!"
  5. }]; 

這種就相對好點了,通過 Block 及內部實現,可以做到不阻塞當前線程,在有結果的時候再進行處理。在對應的 Block 處理對應的情況:成功 or 失敗。 不過這個設計依然還有一點缺陷,因為它對結果的處理分散在不同的 Block,如果我需要統一處理無論成功或失敗的情況,那么需要分別調用,不是太直觀了。所以,我們還有第三種模式。

通過統一的 completionHander 的 block 來處理

  1. [API doSomethingWithCompletionHandler:^(id result, NSError *error) { 
  2.     if result != nil { 
  3.         NSLog(@"Seems good"
  4.     } 
  5.     if error != nil { 
  6.         NSLog(@"Oh Error!"
  7.     } 
  8. }]; 

這種通過 CompletionHandler 來統一作成功結果和錯誤失敗的處理應該是現在設計的首先,包括系統自己的 API 也是這樣設計的。特別適合在一個 Block 里就把所有情況處理掉的需求。

Swift 式網絡請求處理

簡單列舉了三種 Objective-C 下常見的網絡請求類處理方式,看起來還不錯,那么 Swift 模式是什么樣的,能做好更好嗎?我覺得是的。

Swift 里有著非常棒的 enum 機制,所有的枚舉情況不但可以是任何類型,而且可以是不一樣的類型。這意味著,我們在 Swift 里可以包裝一種結果型 enum,比如:

  1. enum Result { 
  2.     case Error(NSError) 
  3.     case Value(JSON) 
  4.     init(_ e: NSError?, _ v: JSON) { 
  5.         if let ex = e { 
  6.             self = Result.Error(ex) 
  7.         } else { 
  8.             self = Result.Value(v) 
  9.         } 
  10.     } 

這段是我真實世界的代碼,用在了我的微博客戶端里。

代碼很簡單,我定義了一個名為「Result」的 enum 對象,它會包裝兩種情況,一種是 Value,在網絡請求成功時,它就是一個 JSON 值;第二種時 Error,是一個 NSError 值,在網絡請求失敗時,包含著具體的錯誤信息。

這樣,就成功地把一個網絡請求下的可能的兩種情況包裝在了一個 Result 對象里,這個對象,要么是成功的結果,要么就是失敗的錯誤,永遠不會有同時有結果和錯誤。于是,我們的網絡請求處理代碼可以更為簡單的設計成這樣:

  1. API.doSomethingWithCompletionHandler({ (result) -> Void in 
  2.     switch (result) { 
  3.     case let .Error(e): 
  4.         NSLog("Oh Error!"
  5.     case let .Value(json): 
  6.         NSLog("Seems good"
  7.     } 
  8. }) 

看起來似乎和前面 Objective-C 的第二種模式一樣?似乎又像第三種?估且稱之為混合模式吧。讓我來簡單說說這種模式有什么好處:

首先,我們通過 Switch 條件判斷這種非此即彼的模式,我們可以減少很多錯誤的發生,保證條件分支判斷不會出問題;其次,我們依然只是在一個 Closure (這里換成 Swift 術語,而不是 Objective-C 的 Block)處理我們的一個請求結果 result,因而可以在前前后后做些其他對結果的統一處理,保證我們邏輯的統一性。

這就是我所認為的 Swift 這種模式的好處了。

通過這種模式改造我的項目后,我覺得代碼變得更整潔、邏輯清晰,也不會有遺失的錯誤處理情況。當然我做采用的還只是簡化版的 Swift 模式網絡處理,更為強大的例子大家可以參考 swiftz 項目的 Result 對象,它使用了 Swift 的 Generic 特性,從而使其可以包裝任意值(不僅僅是 JSON),從而大大增強了擴展性:https://github.com/typelift/swiftz/blob/master/swiftz_core/swiftz_core/Result.swift#L12

我依然還在用 Swift 思維改造項目的過程中,目前這種模式應該還是有改進余地的,希望能和大家做更多有關這個的討論與交流。

責任編輯:chenqingxiang 來源: cocoachina
相關推薦

2011-01-19 09:07:20

Thunderbird

2022-11-16 09:04:36

SQL查詢SELECT

2020-08-26 13:10:03

微信小程序前端代碼

2022-08-18 10:01:35

Jmeter技巧

2022-06-07 23:28:05

線程安全后端

2011-06-13 17:36:43

外鏈

2011-07-05 14:59:17

java

2023-04-12 08:18:40

ChatGLM避坑微調模型

2009-06-17 15:38:57

java軟件安裝

2018-11-13 15:50:41

干貨Java源碼

2022-03-21 21:05:40

TypeScript語言API

2022-07-18 08:08:16

Go?語言技巧

2021-11-29 11:11:45

SQL查詢技巧

2022-04-27 20:52:48

JSChrome元素

2020-07-22 15:15:28

Vue前端代碼

2011-02-21 17:15:14

SilverlightNEY

2024-05-07 07:04:05

前端調試技巧瀏覽器

2011-07-28 20:22:17

2009-07-31 16:23:00

linux cd命令cd命令技巧

2009-10-09 10:21:31

Visual Stud
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 九九精品视频在线 | 天天干成人网 | 一区二区视频在线观看 | 一级日批片 | 亚洲精品在线看 | 日韩在线观看网站 | 国产精品成人av | 一级片在线视频 | 国产成人一区二区 | 91久久久精品国产一区二区蜜臀 | 嫩呦国产一区二区三区av | 欧美一页 | 午夜免费精品视频 | 成人亚洲性情网站www在线观看 | 日韩伦理一区二区 | 精品国产乱码久久久久久丨区2区 | 亚洲精品福利在线 | 久久av网站| 亚洲成人999 | 欧美日韩网站 | 成人a免费 | 国产ts人妖一区二区三区 | 欧美1—12sexvideos | 国产成人精品一区二 | 欧美日韩久久 | 久久四虎| 国产精品久久久久久久久免费樱桃 | 欧美一区二区在线 | 在线亚洲一区 | 91视频在线 | 亚洲天堂男人的天堂 | 欧美高清视频一区 | 久久精品国产一区 | 桃花av在线 | 成人国产在线视频 | 欧美一级二级在线观看 | 久久大陆| 精品成人免费一区二区在线播放 | 欧美激情在线精品一区二区三区 | 成人av电影在线观看 | 日韩欧美一区二区三区免费观看 |