高見龍

iOS app/Ruby/Rails Developer & Instructor, 喜愛非主流的新玩具 :)

近期讀書書目

image

提供一點近期我自己讀過、正在讀或是打算要讀,覺得不錯的iOS開發工具書及網路資源供大家參考。我個人對這些工具書的作者並沒有利益關係,他們賣再多本我也抽不到趴,僅以我個人的角度提供一些的看法(也可能不夠客觀),至於我沒讀過或沒翻過的書我就沒辦法了。

工具書:

Programming in Objective-C 2.0

image

這本差不多快啃了3/4本,個人感覺算是滿中規中矩的教課書。這本有中譯版,不過我沒看過。

Cocoa and Objective-C

image

這本大概讀了2/3左右,作者英文用字不會太艱深,讀起來算是滿輕鬆的,是比較入門的書。

Cocoa Design Patterns

image

design pattern在Cocoa Framework是很重要的,特別是MVC跟delegate pattern幾乎貫穿全場。這是本算是比較進階的書,才剛開始看第一章而已,不過看起來是相當有內容的。(希望農曆年期間能把它讀完)

Learn iPhone and iPad Cocos2D Game Development

image

Cocos2D 是一套很棒而且是BSD license的Python framework,後來移植到iOS上變成Cocos2D for iPhone,用來開發2D遊戲很方便,目前App Store裡也有不少的作品是用它開發的。如果先前有過AS3的基礎的話應該會覺得這套framework用起來很友善。這本書目前只讀了2個章節,但可以感受得到作者的用心,而且在網站twitter上也相當活躍。

網路資源:

首推當然是Apple自家的網站,有足夠多的參考資料,除了有挖不完的寶之外,也可以順便練一下英文。

再來,Stanford University的CS193P課程是品質相當好的。上課影音檔跟投影片都可以在線上下載到完整版本,也可以在iTunes免費訂閱到完整的內容。我自己偏好是整個下載到iTunes裡,即使沒有網路也是可以收看;或是把內容同步到iPad上躺在床上睡覺前悠哉的慢慢看。另外國內有人整理了課程摘要(中文)。

目前最新的課程是2010年fall版本,如果你下載的Xcode是比較新的版本(4.x版),那在收看之前的2009 spring或是2010 winter的課程時可能會遇到操作介面不同的問題。2010 fall用的是比較新版本的Xcode,而且課程名稱也從原本的”iPhone Application Programming”調整成”Developing Apps for iOS”了。

除了Stanford的CS193P之外,Madison Area Technical College也有一系列的課程,內容是比較進階的,在iTunes store裡搜尋”Advanced iPhone Development”可以找到免費訂閱。

這裡有整理了一些值得follow的iOS developers的twitter

為什麼上面都推薦原文的?

在資訊界來說,很現實的是外國的月亮比較圓一點,原文的資料的確豐富許多。其實原文書沒想像中的難讀,有的不用一字一句全部精選,只要看書裡的範例程式碼就大概猜得出來那個章節在講什麼了,若有看不懂的地方再回頭細讀內容即可。

再者,真的要小小的抱怨一下,有不少中譯版電腦書翻得不只錯字多多(有的中文字錯就算了,還有的連範例程式碼都有錯..),語意也不見得通順,讀起來可能比原文還難懂。哪些書我就不方便明講了,一來我的個人觀感不見得客觀,二來也免得擋人財路。

另外,大家在購買工具書之前可能要注意一下書裡的版本,目前最新iOS的SDK是4.x版,但市面上有些書是用3.x版的畫面在做範例。基本上內容是沒差太多,也大多能正常編譯執行,但IDE的操作介面可能會有改位置,對初學者來說可能會有找不到選項的困擾。

常在討論區看到有人建議推薦書目,我覺得適合我的書不見得適合你,建議還是親自走一趟書局,翻一下章節大綱、試讀幾個章節之後再決定囉。以上,就我個人一點點的淺見跟大家分享,如果有覺得不錯的也歡迎大家推薦 :)

iOS Developer的行前準備

image

如果想要對iOS App的開發有興趣的話,需要買哪些設備? 又要花多少錢? 我們一項一項來看:

註冊:

Apple ID:

如果你要下載開發工具跟SDK,會用到這個;如果你要上傳你開發好的app,會需要這個;就算你不是要開發,只是想在App Store裡下載軟體,也還是會用到這個。反正不用錢,就註冊一個吧。

網址:http://appleid.apple.com/

iOS Developer Program:

若你想要上傳你的app到App Store賺它個幾百萬的話,那就肯定要加入。保護費費用是每年3,200元台幣,這個費用包含app的上架費,也就是說上架的時候不會被另外收錢。雖然開發工具裡有內建模擬器,但如果你想把app放到你的iPhone/iPad上測試看看,你也需要加入這個program才能取得一些認證的檔案,把這些認證檔安裝到你的開發環境裡,你才能把app傳到iPhone/iPad上。(JB的就不特別提了)

網址:http://developer.apple.com/

硬體:

Mac電腦:

mac mini、iMac、Macbook Pro..都可,規格及價錢可參考Apple網站。我個人偏好可以到處跑來跑去的laptop,MBA的造型雖然輕薄但不是我的菜(純粹個人喜好),我目前使用的是MBP。

不久之前曾經發生過某個標錯價的事件,但老實說mac系統不是每個人都用得習慣,很多人當初只是抱著撿便宜的心態去下標的。所以也許可以到拍賣網站試試手氣,說不定可以找到全新而且比標錯價還便宜的mac mini。

是不是一定要mac電腦? 網路上有看到人用一些方法讓PC也可以裝Mac OS,至於之後的開發能不能順利,或是provisioning profile能不能正常運我就不確定了。所以,這個問題的答案是不一定要有,但有的話可以省下不少麻煩。

iPhone/iPad:

是不是一定要買一台來測試? 這應該是在全部需求項目裡最不需要”一定要有”的了。開發工具裡有內建模擬器(for iPhone跟iPad的都有),如果你的App沒有用到硬體相關的功能,大部份的功能用模擬器就可以測試。當然,如果你有足夠的預算,那買一台來玩也不錯。

但我們在模擬器上互動測試用的是電腦的鍵盤跟滑鼠,不過實際上的實機互動卻我們的手指頭,這著有相當大的差異。另外在模擬器上用的是電腦的記憶體,但實機能用的記憶體卻少得可憐,在電腦上可能跑得很順,但在實機上可能不是這麼一回事。所以即使這個項目雖然不是一定要有,但在App正式上架之前,建議最好還是想辦法弄一台來測測看。

軟體:

Xcode:

是iOS App專用的開發IDE,作業系統安裝光碟裡就有一份,但版本會有點舊,可從Apple網站上免費取得最新版本(需Apple ID)。不用Xcode行不行? 當然行,只是會寫得非常痛苦而已。

網址:http://developer.apple.com/

iOS SDK:

可從Apple網站免費取得(需Apple ID),不用SDK行不行? 當然不行!

網址:http://developer.apple.com/

做個表格簡單整理一下:

image

Google Doc連結

個人的感想:

Objective-C不是很好學,很多語法跟慣例跟其它的程式語言不同,把在其它地方養成的習慣直接帶過來不見得行得通,可能要有碰壁吃灰的心理準備。

下一篇再來整理一下我最近看的一些工具書,以及一些我個人覺得比較看得懂的網站 :)

在你的app裡加入廣告

image

蘋果的App Store上有許多的軟體,有的重量級的大作是直接掛個價錢就上架,有的是先提供免費的試玩版,滿意再買正式版,其中有些則是不收費,但會放一些廣告在裡面。這些軟體的開發者有的是真的佛心,有的是純練功,不過置入廣告來賺取一些生活費並沒什麼對錯的問題,畢竟大家也都是要過日子。放個廣告上來只要不影響整個app的使用也沒應該沒什麼大礙,畢竟這些開發者也還是需要一些”動力”才能繼續幫大家開發更好用的軟體。

你也許會好奇放這個廣告是能賺什麼錢,在不久前有個故事,就是有個人做了一個手電筒的app,裡面放了廣告,結果這個開發者在第一天就賺了將近1,400美元的收入,CTR將近12%。我不知道這個故事的真實性,也許這個故事只是為了吸引更多的開發者上勾,也或許這只是個特例,不過iAd的拆帳比例是六四分,開發者六,蘋果四。跟一般我們買網站banner的利潤比起來,六成的拆帳不算低。也許是大家覺得新奇,又或是不小心點到(畢竟iPhone那麼小一隻),跟一般網站banner的CTR比起來,手機上的廣告CTR都還滿高的。

其實要在app上置入廣告還滿容易,不需要寫到程式碼,一樣以前面那個地圖app做範例,首先點擊我要放廣告的那個xib檔,跳出interface builder,在元件庫裡可以找到一個iAd的元件:

image

把它拉到場景上,調整一下位置跟尺寸:

image

最後,因為project預設並沒有把iAd framework放進來,所以需要手動自己加,在Frameworks上按右鍵,選擇”Add” -> “Existing frameworks”:

image

測試看看,你應該可以看到一個測試的banner:

image

點擊之後的效果:

image

大概這樣就完成了,記得廣告不要放太大塊而影響整個app的運作囉(放大太塊到時候送審的時候也不一定會過)。

建議閱讀:

Apple Developer – iAd

iPhone app 實作練習 - 幫你的地圖 app 加上大頭針

image

前面幾篇有提到一些@category@progocol,還有一些記憶體管理的東西,我自己也看得頭很花,不過看一堆的理論還不如直接實作來得快。所以,接下來我們就來把前面那個陽春的地圖功能,加上一些註解或大頭針的功能,讓整個畫面看起來豐富、實用一些。

首先,我想要做的效果是在地圖上加個大頭針跟註解,如下圖:

image

做法就是在原來的MapView上加上一個註解(Annotation),讓MapView把它畫出來。要注意的是,Annotation本身不一種View,所以不是看得到的元件,不會直接在畫面上看得到。Annotation類別只是描述一些資料,例如title、subtitle,加到MapView之後,有個叫做MKAnnotationView的類別幫我們畫出來的。而把annotation加到MapView的語法是:

1
[map_view addAnnotation:(id <MKAnnotation>)annotation]

這可以讓你一次加一個Annotation到MapView裡,如果你要一次加多個大頭針進去,則可使用addAnnotations,後面接一個NSArray,裡面裝你要標示的Annotation即可。如果要移掉,則是使用removeAnnotation,如果要移掉多個則是使用removeAnnotations,詳細使用方法可再請參考使用手冊。

回來看上面那行,希望你還記得protocol的東西,如果不記得的話請再看一下這篇複習一下,那行的意思就是說addAnnotation方法後面接的參數必須是個有實作MKAnnotation這個protocol的物件。但是Cocoa Touch並沒有內建Annotation的類別可以直接塞給它,我是滿好奇這麼常用的功能為什麼不直接就內建進來,直接new一個來用就好了。不過沒關係,沒有的話我們就自己手動刻一個。

首先,先在Classes裡新增一個Objective-C class檔案,我把它命名為MyCompany(.m跟.h),然後我的Classes群組看起來會像這樣:

image

再來,修改一下MyCompany.h裡的@interface,讓它實作自MKAnnotation protocol:

1
2
3
4
5
6
7
8
9
10
// 檔案:MyCompany.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

@interface MyCompany : NSObject <MKAnnotation>
{

}

@end

好了,然後呢? 要實作哪些方法要怎麼看? 在MKAnnotation上按滑鼠右選,選擇”find text in documentation”,它會去找到這個protocol的相關詳細說明。但我個人會更偏好在MKAnnotation上按住command鍵加上double click,它會跳到這個protocol的定義,直接看原始碼是最快的。MKAnnotation這個protocol的定義如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#import <CoreGraphics/CoreGraphics.h>
#import <CoreLocation/CoreLocation.h>
#import <Foundation/Foundation.h>

@protocol MKAnnotation <NSObject>

// Center latitude and longitude of the annotion view.
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;

@optional

// Title and subtitle for use by selection UI.
- (NSString *)title;
- (NSString *)subtitle;

// Called as a result of dragging an annotation view.
- (void)setCoordinate:(CLLocationCoordinate2D)newCoordinate __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_0);

@end

從定義看來,實作這個protocol只需要實作做coordinate這個getter就行了,其它的都是optional的。但因為我想要在大頭針上面加上註解說明,所以需要再實作title跟subtitle的setter,程式碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 檔案:MyCompany.h
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>

@interface MyCompany : NSObject <MKAnnotation>
{
  CLLocationCoordinate2D coordinate;
  NSString *title;
  NSString *subtitle;
}

@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
@property (nonatomic, retain) NSString *title;
@property (nonatomic, retain) NSString *subtitle;

@end

骨架好了,再來跳到MyCompany.m,把肉填起來:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 檔案:MyCompany.m
#import "MyCompany.h"

@implementation MyCompany

@synthesize coordinate;
@synthesize title;
@synthesize subtitle;

-(id) initWithCoordinate: (CLLocationCoordinate2D) the_coordinate
{
  if (self = [super init])
  {
    coordinate = the_coordinate;
  }
  return self;
}

-(void) dealloc
{
  self.title = nil;
  self.subtitle = nil;
  [super dealloc];
}

@end

前面幾行的@synthesize是對應到@property用的,這裡唯一比較長的程式碼是initWithCoordinate,這是個委任的建構子,用來在init的時候把coordinate也一併傳進來。

OK! 到這裡的前置工作已經完成了,接著要把它併到之前那個範例的程式碼裡了,首先別忘了要先把MyCompany.h給import進來:

1
#import MyCompany.h

再來一樣直接偷懶的把程式碼全部寫在viewDidLoad裡面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
- (void)viewDidLoad
{
  // 建立一個CLLocationCoordinate2D
  CLLocationCoordinate2D mylocation;
  mylocation.latitude = 25.01141;
  mylocation.longitude = 121.42554;

  // 建立一個region,待會要設定給MapView
  MKCoordinateRegion kaos_digital;

  // 設定經緯度
  kaos_digital.center = mylocation;

  // 設定縮放比例
  kaos_digital.span.latitudeDelta = 0.003;
  kaos_digital.span.longitudeDelta = 0.003;

  // 準備一個annotation
  MyCompany *mycompany = [[[MyCompany alloc] initWithCoordinate:mylocation] autorelease];
  mycompany.title = @"高思數位網路";
  mycompany.subtitle = @"媽,我在這裡啦!";

  [map_view setRegion:kaos_digital];

  // 把annotation加進MapView裡
  [map_view addAnnotation:mycompany];

  [super viewDidLoad];
}

上面這段程式碼是從前面那篇借來用的。做到這裡,按下Build and Run,應該就可以看到有一根紅色的大頭針定在畫面上:

image

再點一下大頭針就會跳出說明:

image

其實MKAnnotationView能做的變化還不少,例如變更大頭針的樣式、顏色,或是在註解的左邊或右邊加上按鈕,按下按鈕之後會執行其它的事情(callout),更詳細的說明可再參考Apple的官方手冊,地圖在行動裝置上能做的應用還挺多的,大家可以再想想怎麼拼裝組合囉 :)

原始檔下載

建議閱讀:

iOS Reference Library – MKAnnotationView

Category in Objective-C

image

OOP的精神之一,就是如果你想研發一台新款式的車子,你並不需要重新發明輪子,通常的做法會去繼承某個現有的”車子類別”,然後加上你要的功能跟屬性,改一改就變成一款新的車子可以來騙錢了。

不過有時候你想幫原來的類別加功能,但又不想動到原來的程式碼,例如你可能下載了某款功能超強的2D物理引擎程式碼,但因為某些小地方寫的不合你的需求,於是你便動手改原始碼來加功能。這當然沒問題,但萬一原作出新的版本,你要不就選擇維持自己原來的版本不update,不然就是update之後,你原來加在舊版本的程式碼得再重貼一次到新版。

Objective-C裡有個叫做category的東西可以幫你在現有的類別加上新功能,這樣一來上面這個問題就可以搞定了。跟別的程式語言比較起來,category的觀念有點像是在Ruby的mixin或是Python的open class,都是在不影響或修改原來的類別或模組的情況下去修改原有的功能。

舉個例子,因為NSObject是所有物件的源頭,但我想要加一個方法讓所有的子類別都可用(把要加的功能放在繼承階層的最源頭並不是好的設計,在這裡只是舉個例子而已)。程式碼這樣寫:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// interface
@interface NSObject(MySuperObject)
-(void) printRetainCount;
+(void) sayHello;
@end

// implementation
@implementation NSObject(MySuperObject)

-(void) printRetainCount
{
  NSLog(@"The retain count is %d", [self retainCount]);
}

+(void) sayHello
{
  NSLog(@"Hello everybody!");
}

@end

這裡用的是在後面加個小括號以及category的名稱。要注意的是category只能加method(instance method或是class method都行),沒辦法增加instance variable(其實也不是完全不行,只是可能要用一些怪招,不過如果要做到這種程度,是不是該考慮直接用一般的繼承就好?)。使用起來的樣子:

1
2
3
4
5
6
7
8
9
10
11
// 建立Book物件
Book *b = [[Book alloc] init];

// instance method from category
[b printRetainCount];

// 用完放掉
[b release];

// class method from category
[Book sayHello];

上面這段程式碼如果一般的情況下,在編譯階段就會跳出警告(認不得printRetainCount跟sayHello這兩個方法),硬是執行的話就會直接錯誤。但因為我們已經有了category的加持,所以執行結果會是:

The retain count is 1
Hello everybody!

因為category是在原來的類別裡加功能,所以你可能會想萬一原來的類別裡有個跟你的category同名的方法怎麼辦? 答案是,會以category的定義為主,也就是原來類別裡的那個方法就被你蓋掉了,當然這不見得是你想要的結果。所以通常這種方法擴充的,會建議可以在前面加個prefix,避免跟原來的方法有重複而造成不幸的結果。

另外,前面有篇提到protocol的文章,也提到了informal protocol,其實它就是一種依附在NSObject上,但是沒有把功能實作出來的category。一般的protocol必需乖乖實作所有@required的方法(在Objective-C 2.0以前全部預設都是@required),但在informal protocol並沒有強制規定全部都要實作出來。事實上,在Objective-C 2.0之後才在protocol裡加進來的@optional語法,就是打算用來取代informal protocol的,在比較新版本的SDK大多都是用標準的protocol在寫了。

範例原始檔下載