iOS Programming Tips (5)

Protocol/Delegate

Protocol 是 Delegate 的介面,定義了 Delegate 必須實作什麼,用其他語言的概念來說明,Delegate 就像是 Callback。Delegate 不一定需要 Protocol,不過最好是要有,程式看起來會比較清楚。

Block

Block 是 iOS 4 以後加入的 Syntax Sugar,它其實就是 anonymous function,我覺得這應該可以用來取代比較沒有復用性的 Delegate,有的時候採用 Block 的寫法能讓程式更清楚易懂,例如 UIView 的 beginAnimation vs. animateWithDuration 兩種寫法我就覺得 Block 方便太多了。

Block 的缺點是有時候不能下中斷點,例如 iPhone Simulator + GDB 的情況,Debug 起來比較不方便,不過我猜也有可能是我沒設定好之類的。

Notification Center

Notification Center 就是 Event/Listener,iOS 中共有四種 Notification Center,分別是 NSNotificationCenter、NSDistributedNotificationCenter、DarwinNotificationCenter 及 TelephonyNotificationCenter。這很適合用來處理全域事件、降低物件耦合性,例如在自定類別中呼叫 UIViewController 更新畫面。

Base SDK? iOS Deployment Target?

Base SDK 是你的 App 可以支援的最新 SDK 版本,而 iOS Deployment Target 是你的 App 可以支援的最老 SDK 版本,所以 Base SDK 最好設定為 Latest SDK。

[UIDevice uniqueIdentifier] is not UUID

它不是 UUID,雖然在 Simulator 中它是,但是在 Device 中則是 UDID,也就是你在 Xcode Organizer 看到的 Identifier。

iOS Programming Tips (4)

Beautiful Formatting

Coding Style 有兩份文件可以參考,Apple 的 Coding Guidelines for Cocoa 以及 Google 的 Objective-C Style Guide

要自動整理程式碼,可使用 Uncrusitify。使用前必須先有一份設定檔,Tyler Neylon 提供了他的 Uncrustify 設定檔Tony Arnold 提供了給 Xcode 4 使用的 Automator Service,可以更方便地在 Xcode 中執行 Uncrustify。

Run You App on a Device

開發 iOS App,使用實機來測試是必須的。以下列出將 App 放到 iDevice 上的操作流程。

  1. 購買 $99 的 iOS Developer Program。
  2. 使用 Keychain 建立開發憑證授權要求
    1. 使用 Keychain 建立憑證授權要求。
    2. 點選選單中的「鑰匙圈存取」→「憑證輔助程式」→「從憑證授權要求憑證…」。
    3. 輸入你的電子郵件位址、名稱,然後圈選「儲存到硬碟」。
    4. 按下「繼續」將產生出的憑證授權要求檔案儲存起來,這個時候你的 Keychain 中會多出兩把名稱相同的金鑰,一個是公鑰、一個是密鑰,所以我想如果要在另一台 Mac 上使用,可能會需要轉移這兩把金鑰。
  3. 要求開發憑證授權
    1. 在 iOS Dev Center 找到 iOS Provisioning Portal,點選超連結進入。
    2. 點選左側主選單的 “Certificates”,在 Development 頁面上傳剛才製作好的憑證授權要求。
    3. 等你的憑證授權要求被 iOS Developer Program 的 Admin 或 Agent 核准以後,會在 Your Certificate 中多出一個 “Download” 的按鈕,將這個憑證下載回來後,直接滑鼠雙擊就能安裝。
    4. 在等待核准的時候,可以先下載 WWDR 憑證並安裝。
  4. 註冊你的 iDevice
    1. 連接你的 iDevice,然後開啟 Xcode 的 Organizer。
    2. 點選 “Use for development”。
    3. 在左側主選單中你的裝置上按右鍵,然後點選 “Add Device to Provisioning Portal”,用這個方法可以把註冊裝置以及安裝 Team Provisioning Profile 一次完成,當然這也可以分別手動在 Web 上操作,或者是我聽說在 Run Project 的時候 Xcode 也會自動問你要不要安裝 Provisioning Profile。
  5. 設定 Code Signing Identity
    1. 在 Project Settings 找到 Code Signing Identity。
    2. 可能會有一大堆,全部設定為 Automatic Profile Selector 中 iPhone Developer。

應該就這樣。

iOS Programming Tips (3)

Debugging Bad Memory Access Issues

當發生 EXC_BAD_ACCESS 時(程式試圖存取不應該存取的記憶體),通常 Debugger 會直接死掉,什麼訊息也沒有。啟用 NSZombie 能夠提供更詳細的 Callstack,迅速找到問題。啟用方法為:

  1. 點選 Group & Files 中的 Executables。
  2. 右上會出現現有的 Excutables,在上面按右鍵,選擇 Get Info。
  3. 切換到 Arguments 頁籤,在下方新增一個 Variable,名稱叫做 NSZombieEnabled,值為 YES

Auto-completion

Xcode 的自動完成功能很方便,但是只能列出一個近似的選項,是這樣嗎?其實按 Esc 就可以列出所有可能的選項。

How Reference Counting Works?

雖然 Objective-C 2.0 加入了 Garbage Collection 機制,但是 Mac 才有,iOS 沒有,iOS 只有 Reference Counting。

Reference Counting 的運作是基於 ownership。當程式要使用物件時,必須取得物件的 ownership,一個物件可以有很多 owner;而當程式不再使用物件時,則需要放棄 ownership。直到物件沒有任何 owner 時,物件就會自動被 dealloc。

取得物件的 ownership 的方法可分為兩種,其一是透過 alloc、new、copy 產生出物件。如果物件是從其他來源獲得,而不是由 alloc、new、copy 產生的話,則可以使用 retain 來取得物件的 ownership。要放棄物件的 ownership,則使用 release,雖然非 owner 也能呼叫這個 method,但這樣相當容易發生問題,請不要這樣作。

我們希望 owner 自己 release 自己的 ownership,但如果物件要作為函式回傳值的話,物件就必須要等到對方接收到物件並取得 ownership 之後才能 release,物件若在函式內就 release 掉,對方就可能收不到物件。為了解決這個問題,可以使用 autorelease1,讓函式只暫時地擁有物件的 ownership,在 event 結束以後的某個時點,物件會自動被 release。對方接收到物件後,必須用記得 retain 取得 ownership、或是用 copy 複製一份物件,以免未來物件 autorelease 後發現沒有 owner,就會被 dealloc。

另一個更好的解法則是不要使用 alloc、new、copy 產生物件,例如使用 NSString 的 stringWithFormat、NSArray 的 arrayWithObjects。以這種方式產生出的物件本身就已經是能夠 autorelease 的,好處是可以節省一些 code。

iOS Programming Tips (2)

What’s Nib Files?

Nib 檔是由 Interface Builder 產生的文件,內容包含了介面的描述。過去 Nib 檔的副檔名就是 .nib,分為一個 XML 檔及一個二進位檔案,而 Interface Builder 3 以後預設改為使用一個 .xib 檔案的格式,實際上最後仍然會編譯成 .nib 檔。雖然副檔名變更了,不過 Xcode 介面中許多地方仍然採用「Nib 檔」這個名稱,對於剛接觸的開發者可能會造成誤解。

Memory Management with NSAutoreleasePool

Cocoa Framework 有個 NSAutoreleasePool 類別,使用方法很簡單,首先要 init 出一個 NSAutoreleasePool 物件,最後 release 這個物件,這時在 init 到 release 之間如果有可以 autorelease 的物件,他們就會自動被 release 掉,另外如果程式執行途中想要命令 NSAutoreleasePool 自動釋放目前不再使用的物件的話,則可以呼叫 drain。不過許多教學是說要 release 掉現有的 NSAutoreleasePool 然後馬上重新 init 一個,我不知道原因是什麼?

如果你使用 Xcode 提供的專案範本的話,它會在 main() 裡面使用這個類別,而由於 main() 是程式的進入點,所以這個 NSAutoreleasePool 會自動釋放掉程式中「幾乎」所有的物件佔用的資源——之所以說「幾乎」是因為如果物件是由 alloc、new、copy 產生出來或是有 retain 過這個物件,就不會自動被釋放1,必須使用 release 或 autorelease 來釋放,慣例上 release 或 autorelease 必須由物件的 owner 來呼叫。

如果要手動釋放的話,則可以呼叫 release,但如果函式要回傳一個物件,這個物件就不可能由函式來 release,而需要在呼叫此函式的對方取得物件後才將它 release,以上是 C 的慣例。Objective-C 的慣例則是在函式回傳物件以前,先呼叫 autorelease 標示物件可以被 autorelease,然後再將物件傳遞出去,這樣對方就不需要管理記憶體。當下次 NSAutoreleasePool 執行 drain 或 release 時,已經不再使用的物件才會被銷燬。

  1. 這樣子好像幾乎都還是要自己釋放嘛… orz

iOS Programming Tips (1)

其實以下這些 Mac Programming 應該也適用,都是很基本的東西,只是作個筆記。

Run Static Analyzer

Static Analyzer 可以用來抓出潛在的記憶體洩漏風險、多餘的變數等問題。Xcode 有內建一個 Static Analyzer,是基於 Clang Static Analyzer 修改來的。直接就能使用!或者也可以照著 Clang Static Analyzer 網站上建議的,手動安裝他們提供的最新版。

執行的方法為 Build / Build And Analyze。

Set Global Breakpoint on objc_exception_throw

意思就是說在丟出 Exception 的時候中斷程式,光用想像的就覺得超實用的啊!

新增的方法是到 Run / Show / Breakpoints,在 “Double-Click for Symbol” 上點兩下,然後填入 objc_exception_throw12

Treat Warnings as Errors

Warnings 表示沒有 Compile Error,但是卻有 Runtime Error 的風險,所以建議勾選這個選項。

這個選項的位置在 Project / Edit Project Settings,Build 頁籤當中。

Use LLVM Compiler if Possible

LLVM 編譯器在 Xcode 3.2 當中已內建,穩定程度已經足夠,並且預期能夠產生比 GCC 更小的可執行檔、更快的執行速度,不過實際效果仍然要以測試為準。LLVM GCC 是 GCC-compatible 的 LLVM,若無必要可以直接選用 LLVM compiler。Xcode 3.2 內建的 LLVM compiler 同樣比較舊,需要的話也可以自行編譯最新版 LLVM compiler 來使用。

這個選項的位置在 Project / Edit Project Settings,Build 頁籤當中,名稱叫做 “C/C++ Compiler Version”。

Use Instruments for Profiling

Instruments 是包含於 Xcode 之中的一個 App,它可以用來記錄、分析程式的運作,有助於最佳化程式效能。3