Swift 會不會取代 Objective-C?

說到 Swift 會不會完全取代 Objective-C,目前看起來是,在 iOS 8 推出之後,應該不少應用程式會使用 Swift 開發,但是 Framework 這一層還是要用 Objective-C 來寫。

我們還是要回來看 Objective-C 與 Swift 的 run time 是怎麼實作的。無論是在 Objective-C 或 Swift 中,一個 class 有哪些 method,都是儲存在 virtual method table (以下簡稱 vtable)中,但是實作方式不一樣。

Objective-C 的 vtable 是個像是 dictionary 的實作,table 中每一筆資料都是 C 字串當 key(又稱 selector),對應到相對的 C Function pointer,所以每次呼叫某個 Objective-C 物件的某個 method,就是透過一個叫做 objc_msgSend 的 function,在表格中根據字串當 key,尋找對應該執行的 function—如果找不到,還會去問這個 Class 是否有實作 forwardInvocation: 這個 method,還是沒有的話,就會丟出找不到 method 的 exception,這部份可以參考蘋果自己的官方文件

至於 Swift 的 vtable 則是一個 array,對某個物件呼叫某個 method 時,相當於要求執行這個 function array 當中的第幾個 function(參見 Mike Ash 的文章)。

如此就會造成以下影響:在 Swift 中,尋找要呼叫的 method 的速度,理論上就會比 Objective-C 來得快,因此同樣功能的程式,用 Swfit 寫,整體上應該會比用 Objective-C 來得快。但同時,Swift 的 vtable 中每個 function 的順序就不能改變,在編譯的時候,vatble 裡頭是什麼順序,在執行的時候就得要是什麼順序,如果是執行的時候載入了不同的 runtime,順序不對,那就會呼叫到錯誤的 function。

蘋果是怎麼確保 compile 時用到的 runtime 與執行時的 runtime 是同一份呢?就是,在編譯應用程式的時候,Xcode 會自動把一份 Swift runtime 複製到應用程式的 bundle 中;所以,你的裝置中有多少個 Swift 應用程式,就會有多少份 Swift runtime。Swift 的 runtime 本身不大,這麼做還沒什麼問題,但是你寫一個 iOS 應用程式還會用到 Foundation、UIKit…一大堆的 Framework,如果要把每個 Framework 都複製一份,聽起來就很不對,照裡說不會換成 Swift 才對,Objective-C 當初用字串當 key,某方面來看,也就是為了處理像 DLL Hell 這樣的問題。

外部開發者比較沒有機會寫到比較底層的 Framework,如果只是寫一個 iOS 應用程式的話,按照蘋果的宣稱,全都用 Swift 寫看來不是什麼問題。

而在 iOS 8 之後,蘋果也終於開放在應用程式 bundle 中,放置自己寫的、或別人包好的 Framework(Mac OS X 從一開始就開放了)。如果是自己寫的 Framework,而且這個 Framework 與主要應用程式的 Target 是在同一個 Xcode project 中,跟著主應用程式 Target 一起編譯,那應該還不會有什麼問題,但如果用的是別人已經編譯好的 Framrwork,那就相當危險—你不能夠保證別人的這個 Framework,與你現在的開發環境用的是同一個版本的 Swift runtime。

iOS 8 同時也開放了一些系統 extension,這些 extension 感覺起來原理就是 Mac OS X 上的 plug-in bundle,透過 dynamic loading 讀入外部的 library。感覺起來 extension 用 Swift 寫似乎也頂危險的—一個應用程式載入一堆 plug-in,每個 plug-in 可能相依於不同的 Swift runtime,看起來就會出亂子。不過目前還沒看到蘋果自己在這方面有什麼文件。

Swift

來講講從今年 WWDC 之後,到目前為止練習 Swift 語言的心得。

想想其實蘋果推出一門新語言其實並不奇怪。雖然對許多人來說,是最近幾年才開始學 Objective-C,但是 Objective-C 算一算已經有三十多年的歷史,而三十年過去,自然不少人會看到這門語言的缺陷。

Continue reading

你為什麼不該在你的 iOS 軟體專案中使用 Storyboard

Storyboard 是蘋果從 iOS 5 起在 Xcode 開發工具中增加的新功能。

一直以來,無論是 Mac OS X 或是 iOS,都可以將應用程式所需要的介面呈現放在 nib 或是 xib 檔案中。我們可以用介面設計工具 Interface Builder(Xcode 4 整合到 Xcode 中),使用視覺化方式編輯 nib 或 xib 檔案,在程式執行時讓 runtime 將檔案中的 UI 定義轉換成對應的 Objective-C 物件。

因為之前有人問我為什麼有些 UIView subclass 在建立時會呼叫 initWithCoder:,而不是 initWithFrame:,其實並不難懂,這邊簡單解釋一下:nib 檔案是將 Objective-C 物件 serialize 成 binary data 的格式,所以用 nib 建立 UI,其實可以想成就是把 serialize 過的 data 再轉回物件;Objective-C 中負責處理物件/serialized data 相互轉換的物件叫做 NSCoder,所以你定義在 nib 裡頭的 view 在被建立時,呼叫到的就是 initWithCoder: 了,這套物件與資料轉換的機制,同時也是 Mac OS X 與 iOS 上實作 copy/paste 的基礎。而 xib 檔則是用 XML 格式表示 nib 檔的內容,在現在的開發流程中,平時我們會編輯 xib 檔案,但 xib 檔案會在 compile time 時被編譯成 nib 檔。

Storyboard 是這種視覺化開發方式的進一步發展。

在 iOS 5 之前,如果應用程式中有許多畫面,負責每個畫面的是各自的 view controller,在每個 view controller 中除了可以用程式碼撰寫建立 UI 物件外(實作 loadView: 這個 method),另一種方式則是讓每個 view controller 有各自對應的 nib 或 xib 檔案;Storyboard 則是將應用程式中原本有多個 nib 或 xib 檔案,合併成一個巨大的 XML,不但可以一次看到所有的畫面設計,也可以看到每個畫面之間透過線條串連起來的關係。或許可以這麼說:Storyboard 除了是一套畫面的設計工具外,也是一套說明在時間中畫面如何變化的敘述工具。

不過,在你的軟體開發專案中,建議不要使用 Storyboard。

Continue reading

與其說語言影響思考,不如說不同語言中就該用不同的方法做事

前陣子被同事抓出來一段 code 有些問題。

我之前有一段 code,由於開始的時候對於整個程式的流程應該怎麼做不怎麼有把握,所以先用 Python 寫了 POC,覺得沒什麼問題之後,才用 Objective-C 重寫。裡頭有一段是這樣:我有兩個 array(當然,在 Python 裡頭用的是 list),叫做 a1 與 a2 好了,裡頭都是一堆字串,而我現在要把 a1 中拿掉所有出現在 a2 的內容;用 Python 想事情,自然就會想到使用 list comprehension 或是呼叫 filter()。

Continue reading

在 Mac OS X/iOS 上指定中文排序

前一陣子遇到一個需求:我們現在有一個 array,裡頭是一堆中文字串,現在我們想要讓這些中文字串按照一些個定的中文索引方式排序,像是使用筆劃、拼音…等等。搞了半天,發現只要在 compare 的時候,選擇特定的 NSLocale 就好了,但是蘋果自己的文件中,居然對於有這些 Locale 可以設沒什麼著墨,顯然很多時候光看蘋果的文件是不夠的。

我們先來看段使用筆畫排序的程式碼:

NSArray *a = @[
	@"落魄江湖載酒行",
	@"楚腰纖細掌中輕",
	@"十年一覺揚州夢",
	@"贏得青樓薄倖名"];
NSLocale *strokeSortingLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"zh@collation=stroke"];
a = [a sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
	return [obj1 compare:obj2 options:0 range:NSMakeRange(0, [obj1 length]) locale:strokeSortingLocale];
}];
for (NSString *s in a) {
	NSLog(@"%@", s);
}

Continue reading