2010年12月27日 星期一

Objective-C 學習系列- 書本導讀 詳解 Objective C─iPhone / iPad / Mac OS X 標準程式設計與實作

這次的主角是這本書
中文官方網頁

原文封面對照

日文官方網

這是一本由日文翻成中文的書,筆者很早就買了日文版,因為日文版寫的太詳盡了,對於 Objective-C 有很深刻的了解,尤其是物件的觀念還有物件之間的互動,看到這本書的時候麥搭警為天人,但因為片假名和英文的對換比較難直接反應,下定決定閉關苦讀,大略對這本書有初步的掌握後,現在就讓我們來看看翻譯後的中文書,結果如何?

外觀和排版

內容是依照原文的排版下去套用,紙質的話就不比較了,所以內容排版還OK,外面封面就改比較多,多了一些層次的美感,只是麥克我是不喜歡字太多,原文也沒有什麼 iPhone / iPad / Mac OS X 的字樣在封面,顯的舒服許多,可能是不這麼寫怕沒人知道吧,書商的要求也說不定,不過如果不知道 Objective-C 就是 iOS 原生程式語言的人,應該也沒有興趣想買吧,因為夠用就好,也不用特別研究。
重點來了 Objective 和 C 之間,有一個橫槓,英文叫 hyphen 或 dash ,原文書也有寫,總之主編該打屁股了,這麼重要的字竟然寫錯,名字都叫給人家叫錯了,何況人家是個美女。orz.

涵蓋的範圍和介紹的順序

這本書從物件,類別,繼承關系,到多執行緒之間的互相溝通,都有詳盡的解說。Protocol,Category (我不懂為什麼要翻成類目?寫分類不就好了,不然也不用翻,原文書就是用片假名カテゴリ) Garbage Collection ,還有 Key-value coding/ observing 應有盡有了,更有簡介 Mac 的 App 架構,因為這本書很早( 2008 )就出了,很可惜沒有 Block 的觀念,但除此之外都有涵蓋了。
最後一點,麥克很喜歡最後本有 index 可以查,原文有,中文就拿掉了,這也是很可惜的地方。

需要有的背景知識

這本書是適合有 C 語言背景的,因為文中開場就提到物件,對於 C 的基本型別不多作介紹,也沒有著墨在流程判斷,迴圈等等,不過這樣也符合書本原意,本來就是介紹Objective-C 這個物件導向的語言。

結論

雖然有一些小缺點,看得出來校稿的人不太懂程式不然就是不熟 C 語言和 Objective-C 語言,常常不注意大小寫,是很有差別的,比如 printf 卻印成 Printf(中文書 P.61,原文書 P.62 還有 NULL 印成 Null (中文書 P.62,原文書 P.62)這都是很嚴重的錯誤,雖然可以理解,但正確性還是很重要。
翻譯的文句也有點文言,不太像是我們阿宅用的語言,大體上還算通順
不過,因為這本書介紹的重點實在太多了也很重要,麥克還是希望大家有空可以去天瓏翻一翻,畢竟這是中文裡 Objective-C 目前最值得參考的一本書了,好像也沒有別本 orz..。

P.S. 如果朋友有看不懂的地方,也許Post 上來麥克可以看一下問題在那,至少有原文書可以參考。呵

2010年12月14日 星期二

Objective-C 學習系列- 書本導讀 Learning Objective-C 2.0: A Hands-On Guide to Objective-C for Mac and iOS Developers (Developer's Library)

這系列的文章是第一次嘗試
因為很喜歡看書,買書,順便把看過的書整理一下,也可以當作初學者的一個參考看那一本書適合自已
先說好,這不是什麼書評,只是個導讀,盡量用接近開發者的語言來描述一本書的大概
書的導讀我想分個幾個項目來闡述
1. 外觀和排版
2. 涵蓋的範圍和介紹的順序
3. 需要有的背景知識
4. 結論

這次的主角是這本

書本的網頁 : http://www.informit.com/store/product.aspx?isbn=9780321711380

一本在 iPhone 開發相關書海之中,後來才出版的書。到底它有什麼魅力可以使麥克站在天瓏店裡,翻了兩下就決定買下它。
好,請大家放下手邊的工作,動動身子,泡杯茶,讓麥克帶領大家進入充滿書香的世界

外觀和排版
說真的我被它的厚度所吸引,300 多頁的厚度,竟然有完整的 Objective-C 2.0 的語法,尤其又有提到 Block 這個語法,是這 Objective-C 的書本中比較少看到的單元
簡單又不失去深度的排版 。
尤其封面這頁,有一種身在機器裡面向外看的反向思考。
文字相當的豐富,相對之下圖示就比較少,但是排版的方式使可讀性增加不少。
每篇最後還有 Exercises 可以幫助讀書回想剛剛書上提的觀念是否解讀正確
所有的 Example 都可以在書本網頁找到。


涵蓋的範圍和介紹的順序
從 C 語言的複習,物件的觀念,Objective-C 特有的關鍵字 @property @synthesize @dynamic @private 等等。都有詳細的例子和介紹
protocol, catagory, properties 都有介紹,甚至有提到一點 Core Foundation
進階的部分就有 Referencing Cycle, Garbage Collection, Block 等等的討論
看完這本書就有九成的 Objective-C 的基本知識了,相當受用,尤其又不厚
有點比較可惜的是,Key-Value Coding 的觀念就沒有提到,麥克我覺得這也是很重要的觀念。

需要有的背景知識
此書一開頭就說明,需要有 C 語言的知識,不過書本一開始有複習 C 語言,有學過的人不妨再聽聽這本書有什麼特別的說法
主要的讀者還是給想寫 iOS 程式的朋友,所以這本書的 memory management 也提到的很詳細

結論
只要手頭上有錢,是應該都要買一本當參考書的。應該是說對於單純語法來說,這是一本不可多得的好書,雖然單說語法的書,大部分讀者看了都會睡著,但一個盡責的工程師,就是要在大家都睡著的當中學到新知不是嗎?呵。不過還好 Developer's Note 這個粉絲團
http://www.facebook.com/pages/Developers-note/226724001803
都是一群不愛睡覺,喜歡吸收新知的朋友們而組成。所以不怕沒有地方可以找人討論,發問。
冰友,為自己的 iOS App 的成功,乾一杯吧。

2010年12月8日 星期三

認識 iPhone 程式架構

要從一個main function 裡的程式進而演化成一個iPhone的程式是有相當難度的一件事,那怕只是一些很基本的功能,要處理的事情可是非常之多。幸運的是Apple的工程師幫我們把這些基本又多的工作給完成,把一個好用的SDK 開放給大家使用,可以專心在自己的idea上面不需要花太多精神在這些基本建設上。這個部分就是要讓讀者快速地認識 SDK 還有讓讀者熟悉 SDK 開發的精神,這樣一來可以幫助讀者迅速了解工具,馬上可以開發自己的程式。實際開發 iOS 程式前,要先介給一個很重要的觀念 MVC Design Pattern 。

Model View Controller

不論程式大或小在規畫程式的時候有一個非常不錯的樣式或者說模版可以讓我們的程式裡各個Class 任務分明,彼此之間的錯誤不太會影響其他物件,專心負責自己的事情,這樣一來也方便開發者除錯。這個模版分成三個部分,分別是 Model,View和Controller 而彼此之間溝通的關系是這樣畫的。
View
  • 用來呈現資料給使用者看
  • 通常不會直接和管理資料的部分接觸
Model
  • 常用來管理資料和提供演算法
  • 和資料呈現的部分沒有直接關係

Controller
  • 負責程式的流程控
  • 在 View 和 Model 沒有溝通的管道時,提供這兩者間的資料交換

舉一個實際一點的例子,假設我們要寫一個程式要依照使用者點選的資料從資料庫裡把相關的資料找出來,然後適當的安排呈現資料到螢幕上供給使用者看。在這段話裡我們把動作細分成幾個部分再加上剛剛上述的三種角色重新詮釋一下。先看一個示意圖

  1. 使用者從鍵盤輸入想要資料的條件限制,按下 Enter
  2. Controller 接受到Enter這個事件
  3. 把使用者剛填入在某個 View 產生視覺元件的資料讀出送到 Model 去進行和資料庫的比對
  4. Model 收到資料後迅速地從資料庫裡找到符合使用者所設限制條件的資料傳給 Controller
  5. Controller 依 Model 給的不同的資料特色,適當地安排給要呈現資料的 View
  6. View 會依需求,動態地呈現資料或是利用原有的 View來呈現新產生的資料
只要我們記住這個觀念,不管程式大或小如此地編寫程式,權責分明,會幫助我們思考解決問題而且除錯時也比較容易到找錯誤的地方。而且Xcode 的開發套件也都是按照這個架構地底下完成的,了解這個觀念之後也可以讓我們比較快入手 iOS SDK 。

第一個 iOS 專案

不管三七,二十一我們先開啟一個 iOS 專案。
左邊欄選 iOS Application 右邊選 Window-based Application 且有個下拉選單記得選 iPhone
 選擇 Choose 之後,會有個視窗提醒我們存檔,選好位置,輸入檔名 PhoneApp

按下 Save 之後會看到一個 iPhone 的專案
接下來首先我們要確定一件事,就是要執行的程式是在模擬器上,而不是實體的 iPhone 機子,在最左上方有個下拉式選單,按下選 Simulator
接下來直接按下上方的 Build and Run 之後在下方程式列就會看到 iPhone 的模擬器

跑出來了。
結果就是這樣一張白白的圖內容什麼都沒有。接著讓筆者來解說一下這個專案的內容。

應用程式內容

首先來談談一個開發程式用的專案裡面,應該包涵那些東西。如果我們開啟一個 iOS 的專案在左邊Groups & Files 的地方應該會看到這些Group。



很明顯地這個專案的名字叫PhoneApp然後我們大致上可以這樣分類一下
Classes
  • 自己產生的程式碼,包含 .h 和 .m
Other Sources
  • 系統自行產生的程式碼有 main.m
Resources
  • 有 Xib 檔和設定檔(這個例子裡為PhoneApp-Info.plist),Xib 檔裡儲存 View 相關的設定,由 Interface Builder 來負責管理。在這個地方還可以存放一些圖片,音樂等等的資料
Frameworks
  • 基本的系統必要的Framework,在Cocoa Touch 之下除了 Foundation 之外,UIKit 也是基本的 Framework
UIApplication

一支iOS 程式就代表著有一個掌握全局的 UIApplication ,UIApplication 是 UIKit 的一員,其主要是處理事件的分配,程式最上方的狀態列,程式的icon 等等,處理一些基本的工作之後就會把任務交給開發者的 Class ,也就是每一次開啟新的專案的時候都會在 Classes 這個 Group 看到 xxxAppDelegate.h 和 xxxAppDelegate.m 。xxx 就是專案的名稱在 PhoneApp 的例子就是 PhoneAppAppDelegate.h 和 PhoneAppAppDelegate.m 。UIApplication 把一些基本的工作做完之後就會利用 delegate 把任務交給 PhoneAppAppDelegate 所以我們在 PhoneAppAppDelegate.h 會看到 <UIApplicationDelegate> 的宣告。如下方
@interface PhoneAppAppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
}
想當然在 PhoneAppAppDelegate.m 就會有 <UIApplicationDelegate> 的一些實作了。不過暫時先不討論有那些 method 需要實作先來看一下程式執行時的流程
iOS 的程式還是延續自 C 程式的習慣有由 main function 當成執行的進入點,只不過因應需求有稍做修改,不過還是先看看定義在 main.m 裡的 main function ,所有iOS 專案的 main.m 都放在 Other Sources 這個 Group 裡。
#import <UIKit/UIKit.h>

int main(int argc, char *argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, nil);
    [pool release];
    return retVal;
}
這個 main function 相當地簡單,和之前練習過的程式碼不同之處只有這列寫著
int retVal = UIApplicationMain(argc, argv, nil, nil);
就呼叫 UIApplicationMain 然後傳入 argc,argv,nil,nil 就這樣?我們直接來看這個 function 的宣告,在 iOS Reference Library 可以查得到,在 iOS Reference Library 有對每個傳入的參數,回傳值都有說明
int UIApplicationMain (
   int argc,
   char *argv[],
   NSString *principalClassName,
   NSString *delegateClassName
);
參數
argc
在 argv 裡元素的個數。通常對應 main 的參數。
argv
一串輸入值。通常對應 main 的參數。
principalClassName
UIApplication 或其子類別實體的 Class name,如果值是 nil 則認為是 UIApplication。
delegateClassName
接受 application 委任實體的  Class name 。如果 principalClassName 是 UIApplication 的子類別時,可以指定這個子類別當受委任者。其子類別的實體接受 application-delegate 訊息。如果是 nil 代表你要從 main nib 檔(在 iOS 是 xib 檔,且一開始預設為 MainWindow.xib )載入受委任者物件。
回傳值
雖然有設定回傳的型別,但是這個 function 不會回傳東西。當使用者按下 Home Button (唯一的實體按鈕 )的時候這個程式會進入背景。

討論
這個 function 從 principal class 實體化 application 物件,從給定的 (如果有的話)class name 實體化委任物件並設定委任的關系。它也會建立一個主要事件的迴圈包含程式執行的迴圈然後開始處理事件。如果程式的 Info.plist 有指定載入 main nib 檔,經由 NSMainNibFile 這個Key 相對應的合法 value 值,就會載入這個 nib 檔。
 (以上是不負責翻譯。:P)

其中特別說明一下 argc,argv 這兩個,而且如果有寫過 UNIX 程式的就知道,argc 是代表執行時傳入的參數的個數,argv 是參數的字串。比如有一個 UNIX 程式叫 a.out ,而要執行這個程式時,在命令列底下就這樣寫
./a.out
如果這個程式一開始就要傳入參數,比如
./a.out --encode utf-8
這時在 main 裡 argc 的值就是 2 ,而 argv 這個字列陣列的值就會是 {"--encode", "utf-8" } 就這樣。那後面的 principalClassName 和 delegateClassName  (兩個 nil )怎麼交互作用?那只傳這四個參數給 UIApplicationMain 就可以跑出一個簡單的 iPhone 程式?剛剛的一片白白的程式就是這樣執行出來的?不是這樣的吧?當然惡魔總是在細節中,看完這麼簡單的 main function 我們要來看這個專案的設定檔。PhoneApp-Info.plit 在 Resources 這個裡,其內容長這樣


點選左邊的 PhoneApp-Info.plist 之後右下就是其 plist 的內容,都是一些設定值,其中關鍵的地方在紅色圈起來的 Main nib file base name 的 MainWindow 。這個意思是說左邊的 Group & Files 會有一個檔案叫 MainWindow.xib 也就是筆者用紅色圈起來在 PhoneApp-Info.plist 上方的檔案。如果我們 Click 這個檔案則 Mac 程式列會有一個程式出現叫 Interface Builder
然後進入 Interface Builder 會看到這個視窗,
這個視窗叫 Document Window ,裡面有一個白白圖示的 Window,筆者用紅色下底線標示出,再 Click 一下就會出現。

這片白白的視窗就是剛剛 Build and Run 之後模擬器跑出來一片白白的畫面。不信的話,我們把 Library 叫出來。利用 Tool -> Library ,此時還是在 Interface Builder 裡面。
 
在不遠的旁邊會出現 Library 視窗
  
在其底下 Search Bar 輸入 label字樣,上方就會跑出 Label 的元件

然後,把上面的 Label 拉到 Window 畫面,拉過去之後,順手在 Label 點兩打,打上自己要 的字樣,比如 Hello IB

拉完,改完之後記得要存檔,可以按下 Command 加 S 。有沒有忘記存檔看剛剛 Document Window 左上角的紅色圈圈就知道了。
如果紅色圈圈中間有一個黑點,就是修改過且還沒存檔,存檔完就會變成。

中間黑色不見了。這樣 Interface Builder 被我們修改完了。現在回到 Xcode

 
之後再按下 Build and Run 或是快捷鍵 Command 加 Enter ,就會看到模擬器跑出來,新的畫面出現了。
剛剛在 Interface Builder 打的字樣出現了。
等等,問題來了,就這樣?那剛剛提到的 UIApplication 這個東西在什麼時候用到?別急,現在就要介紹。雖然我們很簡單地新增一個 Label ,其實 UIApplication 早就產生了。把 MainWindow.xib 這個檔再點兩下,由 Interface Builder 打開在 Document Window 裡有一個 File’s owner 如下圖
 
 Fileʼs owner 的 Type 是 UIApplication 就代表這個 xib 檔是屬於 UIApplication 的,我們就是 透過 main function (在 main.m ) 裡的 UIApplicationMain 來產生 UIApplication 實體 ,在 xib 這樣設定的話系統就會讓這個 淡黃色有點透明的立方體 (這個圖形在 Interface Builder 要代表 external object ,有寫在 Library ,也就是外部己產生的物件 )和 UIApplication 的實 體做一個連結,接著,還記得之前提過 UIApplication 這個 Class 只是處理一些基本的工作 之後會把接下來的工作透過 delegate 交給 PhoneAppAppDelegate ,於是我們在 Document Window 往下找,果然找到一個東西 Type 寫著 PhoneAppAppDelegate 。
 圖上這個橙色的立方體代表的是一個物件,右邊的Type就是其 Class 在這裡就是 PhoneAppAppDelegate 所以它相對應的程式碼就是 PhoneAppAppDelegate.h 和 PhoneAppAppDelegate.m 。所以我們點開 PhoneAppAppDelegate.h 在右邊的下方的編輯區就會看到 PhoneAppAppDelegate.h 有採用 <UIApplicationDelegate>
代表著 PhoneAppAppDelegate 會接著 UIApplication 之後去完成接下來的工作。所以接下來的工作就都定義在 <UIApplicationDelegate> 這個 protocol 裡,而 PhoneAppAppDelegate.m 就會去實作 <UIApplicationDelegate> 所定義的 method 。我們點開 PhoneAppAppDelegate.m 來看看一個目前對我們而且最重要的 method
 
叫這個 method 叫做
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
這個 method 只是把  window 這個實體變數讓呼叫 makeKeyAndVisible ,讓 window 可以被使用者看見 window ,window 這個變數的型別是 UIWindow ,一個 iOS 程式裡常通只會有一個 UIWindow,目前先認識到這樣,之後在解說 UIView 的時候會再解說 。重點是這個 method 可以視為 iOS 專案裡寫程式進入點,就好像 Console App 的 main function 一樣。可能會有讀者有疑問,這個專案也有 main function 啊?就在 main.m 為什麼我們不把這個 main function 當成寫程式進入點?因為在呼叫 main function 的時候 UIApplication 還有一些事情還沒完成,甚至每個一程式就有一個 UIWindow 可能也還沒準備好,所以和 Console  App 不一樣的是 iOS 依賴 UIApplication 和 UIWindow 的工作完成才可以使開發者接下來的工作比較方便進行。而且
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
一當程式啟動之後只會被呼叫一次,所以滿適合當寫程式的進入點的,這點要請讀者千萬要記住。說到這讀者們有頭昏了嗎?先暫停一下幫大家做一個小整理,從一個最簡單的 iOS 程式 ( window-based 專案 ) 執行的時候的流程是這樣的。

在 UIApplication 實體被產生後就會開啟一個無限的迴圈,一直等待使用者去產生一些事件,比如按按鈕,撥動等等,直到程式被關掉。
在這個例子中,很明顯有看到利用 MVC 工作分配的效果。View 比較直覺知道就是 xib 檔也就是 MainWindow.xib ,PhoneAppAppDelegate 可以視為 Controller ,當 UIApplication 把某些事情做完 (如 application:didFinishLaunchingWithOptions:)或是有事件要通知就呼叫 PhoneAppAppDelegate , PhoneAppAppDelegate 可以去更新 MainWindow.xib 定義的UI元件,如此可知 UIApplication 扮演著 Model 的角色。