STRING 還是 NSSTRING

既然像 String 這樣的 Swift 的類型和 Foundation 的對應的類是可以無縫轉換的,那麼我們在使用和選擇的時候,有沒有什麼需要特別注意的呢?

簡單來說,沒有特別需要注意的,但是儘可能的話還是使用原生的 String 類型。

原因有三。

首先雖然 String 和 NSString 有着良好的互相轉換的特性,但是現在 Cocoa 所有的 API 都接受和返回 String 類型。我們沒有必要也不必給自己憑空添加麻煩去把框架中返回的字符串做一遍轉換,既然 Cocoa 鼓勵使用 String,並且爲我們提供了足夠的操作 String 的方法,那爲什麼不直接使用呢?

其次,因爲在 Swift 中 String 是 struct,相比起 NSObject 的 NSString 類來說,更切合字符串的 "不變" 這一特性。通過配合常量賦值 (let) ,這種不變性在多線程編程時就非常重要了,它從原理上將程序員從內存訪問和操作順序的擔憂中解放出來。另外,在不觸及 NSString 特有操作和動態特性的時候,使用 String 的方法,在性能上也會有所提升。

最後,因爲 String 實現了像 CollectionType 這樣的接口,因此有些 Swift 的語法特性只有 String 才能使用,而 NSString 是沒有的。一個典型就是 for...in 的枚舉,我們可以寫:

let levels = "ABCDE"
for i in levels {
    print(i)
}

// 輸出:
// ABCDE

而如果轉換爲 NSString 的話,是無法編譯的。

不過也有例外的情況。有一些 NSString 的方法在 String 中並沒有實現,一個很有用的就是在 iOS 8 中新加的 containsString。我們想使用這個 API 來簡單地確定某個字符串包括一個子字符串時,只能先將其轉爲 NSString

if (levels as NSString).containsString("BC") {
    println("包含字符串")
}

// 輸出:
// 包含字符串

A> Swift 的 String 沒有 containsString 是一件很奇怪的事情,理論上應該不存在實現的難度,希望只是 Apple 一時忘了這個新加的 API 吧。當然你也可以自行用擴展的方式在自己的代碼庫爲 String 添加這個方法。當然,還有一些其他的像 length 和 characterAtIndex: 這樣的 API 也沒有 String 的版本,這主要是因爲 String 和 NSString 在處理編碼上的差異導致的。

使用 String 唯一一個比較麻煩的地方在於它和 Range 的配合。在 NSString 中,我們在匹配字符串的時候通常使用 NSRange 來表徵結果或者作爲輸入。而在使用 String 的對應的 API 時,NSRange 也會被映射成它在 Swift 中且對應 String 的特殊版本:Range<String.Index>。這有時候會讓人非常討厭:

let levels = "ABCDE"

let nsRange = NSMakeRange(1, 4)
// 編譯錯誤
// 'NSRange' is not convertible to 'Range<String.Index>'
levels.stringByReplacingCharactersInRange(nsRange, withString: "AAAA")

let indexPositionOne = levels.startIndex.successor()
let swiftRange = indexPositionOne..<advance(indexPositionOne, 4)
levels.stringByReplacingCharactersInRange(swiftRange, withString: "AAAA")
// 輸出:
// AAAAA

一般來說,我們可能更願意和基於 Int 的 NSRange 一起工作,而不喜歡使用麻煩的 Range<String.Index>。這種情況下,將 String 轉爲 NSString 也許是個不錯的選擇:

let nsRange = NSMakeRange(1, 4)
(levels as NSString).stringByReplacingCharactersInRange(
    nsRange, withString: "AAAA")
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章