Objective-C iPhone起步開發的8條建議和技巧
作者經歷:[self.paradigm shiftFrom:@"ruby" to:@"objective-c"]
所以的語言都會教給我們一些編程藝術。作爲一名專注Ruby的開發者,我一向比較害怕諸如Java和C++等強類型的語言,還有就是它們的鼻祖C。所以當我決定學習Cocoa進行iPhone應用開發時我有點疑惑應該如何改變了,同時也期待我可以變成一個更好、更多面手的開發人員。幾周以後我可以說我實現了我的目標,當然期間也付出了很多汗水。
我想很多人的處境跟我一樣:想學習Objective-C進行iPhone編程,手頭上就只有一兩本書做嚮導。市面上很多Cocoa和iPhone SDK的學習教程都很好,但還是會有很多陷阱和風格上的技巧可能意味着理解一個語句和茫然看着它直至通過Google搞定之間的差別。該博文的目標是想讓你不通過Google就可以獲取到這些。這是8條最大的轉變,我真覺得要是我在開始學習Objective-C之前知道就好了。期待你可以學到一些可以避免我已經犯過的低級錯誤的東西。
1. 打開NSZOMBIEENABLED
這不是開玩笑。這是應用開發中用調試來發現錯誤的正確方式。
你可能會知道iPhone應用中沒有一個自動的垃圾回收器,所以你必須手動釋放(release)和保持(retain)對象。你有時可能不小心釋放了原本應該保持的對象。你的代碼在向一個nil對象發送消息的時候,應用就崩潰了,這是你一臉很茫然。當然你會得到一個EXC_BAD_ACCESS 錯誤以提示你在試圖訪問一個已經釋放的內存,但這起不了什麼作用。
如果你打開了NSZombieEnabled,釋放的實例就會保持在內存中並轉化成一個殭屍(Zoombie)。如果它們接收一個消息就會觸發錯誤。這樣你就可以真正調試內存問題了。
爲了打開該功能,你需要:
Ø 在Xcode中打開你的項目
Ø 項目列表中找到'Executables'部分,打開小三角形
Ø 右擊可執行文件名並選擇'Get Info'
Ø 單擊最上方的’Arguments'
Ø 單擊'Variables to be set in the environment'下方的plus圖標
Ø 鍵入NSZombieEnabled的變量名,值爲YES
馬上就行動吧,你會感謝我的。不過記得在發佈應用時候取消它,因爲在發佈的應用中你想要實例被釋放掉,而不是變成殭屍。
2. 把Nil當成朋友而不是敵人
這對我是一個很難轉換的一點。
在諸如Ruby等大多數的面嚮對象語言中,如果你調用一個nil對象的方法,你的程序會掛得很慘。這正是神奇的Ruby中Andand框架要防止的由於疏忽導致nil接收一個消息並觸發錯誤。
在Objective-C中如果對nil傳遞一個消息是合法的。實際上我應該進一步說這是Objective-C的一個神奇的特色。在iPhone的類中就廣泛使用到這點,因此你也應該使用。它會使得你的代碼類似如下的樣子:
if ([anObjectThatMayBeNil startProcessing]) {
// ...code...
}
你不需要檢查對象是否是nil。如果該聲明不爲true,或者startProcessing失敗,或者對象不存在,你都不打算執行code部分的代碼段。這點是否有點瘋狂完全取決於個人解讀。我是從Ruby轉過來我有點喜歡這點,不過我也可以感受到這會使得代碼很難調試。
我的建議就是擁抱這樣的瘋狂。Objective-C通過允許使用不存在對象的方法提供了很多強大的功能:應該關注如何使用這樣功能並讓程序更健壯。
3. 記得使用該死的@和;
.這真是一個簡單而弱智的建議。
NSString是大多數Objective-C類在需要字符串類似的對象時候使用的。它不僅有引號,還需要在之前加個@符號。
@"這是一個合法的NSString."
"這個不是,如果使用了就會導致讓人厭煩的奇怪錯誤。"
同樣,不要忘記分號。我知道說這句話很愚蠢,但出於Ruby的背景我就經常在語句後直接回而在編譯器出錯後茫然。慶幸的是你至少可以得到一個合理的消息從而讓你發現錯誤並補上分號。
4. 在代碼中使用委託(Delegate)
不過委託還是相當強大的,也是Objective-C中一個非常酷的一個風格元素。這使得你可以發送一個耗時或複雜的操作到另外一個對象並且確信你終究會聽到迴音,同時可以充分發揮多態從任何對象調用任務並根據情況響應任務。
這方面一個很好的例子就是CoreLocation ,它iPhone用來位置更新的框架。在應用中我使用單例的Locator來控制對CoreLocation框架的訪問。CLLocationManager 的委託如下:
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self.locationManager startUpdatingLocation];
當CLLocationManager接收到一個位置更新後它就會調用delegate上的locationManager:didUpdateToLocation:fromLocation:方法。我所做的就是在代碼裏實現該方法,我知道它只有在位置正確更新的時候纔會被調用。還有一個方法是用來處理更新位置時的錯誤。
這個功能的的優勢就是一個對象可以改變它的委託從而使得受委者可以對相同的消息做不同的響應。應用可以在位置更新時讓其中的一個控制器(Controller)顯示彈出窗口,而讓另一個顯示動畫。兩個控制器的方法是一樣的(locationManager:didUpdateToLocation:fromLocation:):。所做的只是更改下CLLocationManager的委託。
一旦你習慣了這樣的編程風格你就會很喜歡它。
5. NSLog所有的東西
NSLog(@"Hi there, the object you want is: %@", anObject);
Ruby在崩潰的時候會給一個很好的回溯記錄。我個人認爲Objective-C(即使帶有gdb)還需要做很多改善。經常log,在任何地方log任何東西,這樣在你的應用異常崩潰的時候你就可以檢查,也就更有可能發現元兇。
順便要提下NSString中的’%@’。這是一個對象替換的語法。這僅僅對NSObjects對象有效,它會調用對象的description方法。如果你試圖在普通C類型上使用它,就會崩潰。所以如下代碼是就犯了大錯誤的:
int i = 1;
NSLog(@"The number is: %@", i); // BOOM CRASH!
通過使用正確的字符串替換進行修改後:
int i = 1;
NSLog(@"The number is: %i", i); // sweet, sweet success
這是一個容易忽略的陷阱。其他類型的字符串替換可以查看《Cocoa 字符串替換》一文檔。
6. 爲自定義類提供description方法
和NSLog建議緊密相連的另一個建議是:爲你所有自定義的類提供一個description方法。
- (NSString *)description {
return self.name;
}
這樣log它們的時候就會返回一個合適的字符串,而不是nil。
7. Objective-C沒有真正使用強類型,你也不要
在合適的地方使用強類型,但你不需要受限於它,因爲Objective-C也不是強類型的。任何Objective-C的對象都可以使用“id”類型聲明,而不用各自的類型。這使得你可以使用一些具有潛在危險的多態實例。
Duck *aDuck = [[Duck alloc] init];
Goose *aGoose = [[Goose alloc] init];
Pond *bigLake = [[Pond alloc] init];
bigLake.inhabitant = aDuck;
[bigLake.inhabitant quack]; // The duck says: "quack!"
bigLake.inhabitant = aGoose;
[bigLake.inhabitant quack]; // The goose says: "do I look like a duck to you?"
這些僅需Pond類中的一個簡單聲明就可以實現了。
@interface Pond : NSObject {
id *inhabitant;
}
@property (nonatomic, retain) id *inhabitant;
Objective-C不會在意inhabitant是什麼,只要它是繼承自NSObject(該類定義了id)就好了。這些代碼會在編譯是警告inhabitant可能無法響應quack,所以還是要小心使用這個功能。如果你像給nil發送一個消息類似地將一個不合理的方法傳遞給一個對象,在你對象沒有定義該方法的時候你的程序就會崩潰。
但是你還是可以到處傳遞各種不同的對象。只要記着在使用它們時候確認下它們可以響應指定的方法就好了。
8. 閱讀API參考文檔,之後在通過Google覈對
有次我試圖在UIWebView對象上做一些巧妙地操作,但從默認API查看器給出的文檔來看這不大可能。Google幫了我並給了我提示(就是webView:shouldStartLoadWithRequest:navigationType:)。儘管文檔看起來很完整(即使這也無法達到,除非你註冊並下載下完整的文檔),不過還是很多人在Cocoa和iPhone SDK上比我嘗試了更久。一個簡單的Google搜索有時可能帶來意想不到的結果。遇到的問題你應該相信有些人已經經歷過了。
小結
我確信還遺漏了很多。我在單獨使用Ruby幾年後對C有些健忘了,學習Objective-C就有點困難。但是我覺得還是很值得的。Objective-C很簡單優雅,能給你更多的幫助並製作一些很神奇的東西。記住上述的8條建議,你的Objective-C程序也會很健壯。如果你有聲明可以分享的,記着發表評論,也讓其他人看看你有用的建議。