今天是 Mountain Lion 出閘的日子。 而對於開發者來說, Xcode 4.4 才是我們關注的焦點, 接下來讓麥克帶領大家, 來一場 Xcode 4.4 之旅。
首先要從 Mac App Store 下載 Xcode 4.4。 如圖。
安裝好之後,打開 Xcode, 先確定一下版本。為下圖。Version 4.4 (4F250)
二話不說先來開啟一個 Project 選 Master-Detail Application 如下圖
大致上和 4.3 沒什麼改變。眼尖的讀者應該會看到, 左邊 iOS 部分 cocos2d 的 Template
Project 保留下來了。 因為 Template 資料夾在 ~/Library/Developer/Xcode/Templates/ 而不在Xcode 執行的資料夾裡, 不會受到更新 Xcode 而影響。
選擇 Next 之後看到的視窗也和 4.3 差不多,如下,給個名字。 Hello4Table。
注意,這個 Project 的 Class Prefix 我是寫 GL。 選擇一個路徑之後按下 Create。 如下。
選擇 Project 設定 -> Build Setting 的搜尋欄填上 compiler 下方按鈕要選 all 。 如下圖就會看到主角出現了。 Apple LLVM Compiler 4.0.
來看看 source coe 有什麼改變。 先看看 AppDelegate.h 和 AppDelegate.m 如下圖。
左邊的 .h 有 @property 右邊的 .m 卻沒有 @synthesize ? 聰明的大家猜到了吧, 是的。 在 Interface 的 property 不需要寫 synthesize 了, compiler 自動會幫大家補上。
《需要換 Xcode 4.4 理由加一》
再來把鏡頭轉到 GLMasterViewCotnroller.m 的 line 46 insertNewObject: 這個 method 身上。 如果沒看到 Line Number 可以在 Xcode Preference 的 Text Editor 打勾 如下
回到程式碼,看下方截圖。
紅色框起來的部分是
@[indexPath
] 對照 4.3 寫的應該是
[NSArray arrayWithObject:indexPath
]. 好的,究竟 @的作用是什麼呢?讓我們繼續看下去。
有看到之前文章
LLVM 新語法的朋友們,就會猜到了。@[@"one"] 指的就是 [NSArray arrayWithObject:@"one" ]。此文中還有提到 NSNumber 還有 NSDictionary 都可以用 @ 來改寫。這篇文章要做更深入的探討。首先來看
NSNumber
Integer
NSNumber * intNum = [NSNumber numberWithInt:10];
intNum = @10;
Float
NSNumber * floatNum = [NSNumber numberWithFloat:100.5];
floatNum = @100.5;
Bool
NSNumber * boolNum = [NSNumber numberWithBool:YES];
boolNum = @YES;
More
NSNumber *piOverTwo = @(M_PI/2);
看到 @ 就是看到物件,直接把數值寫在後面,@100 就是一個 NSNumber 的物件,非常的合理和簡明。
NSArray
1. NSString * str = @"4.4";
2. NSArray * array = [NSArray arrayWithObjects:[NSNumber numberWithInt:2],@"Xcode",str,[NSDate date], nil];
2.1 NSArray * array = @[@2, @"Xcode",str, [NSDate date]];
2. 的寫法可以改成 2.1 用 @[, , ,] 來取代一堆的文字,變得多麼簡單一目瞭然。要注意的是 @[@"one"] 等同於 [NSArray arrayWithObject:@"one"] 並不是 [[NSArray alloc] initWithObject:@"one"] ,如果不是用 ARC 來管理記憶體的話,要多加小心,@[] 一開始就會被放到 autorelease pool 上,method 結束記憶體就沒了。
也許有讀者會好奇了,那 mutable 怎麼辦?@[] 是 NSArray 那 NSMutableArray 呢?有沒有另一個寫法?答案是,用
mutableCopy 如下
NSMutableArray * mArray = [@[@"one", @"two", @"three"] mutableCopy];
或是
[NSMutableArray arrayWithArray:@[@"one", @"two", @"three"]];
這樣一來 @[] 就會轉成 mutable array 了。
存取的時候非常方便,如下。
mArray[2] = @"four"; // write
NSLog(@"%@", mArray[2]); // read
對變數直接用 [] 就可以存取某個 index 的值了,不只初始化好用,存取的時候更是方便。
NSDictionary
1. NSDictionary * dict = [NSDictionary dictionaryWithObjectsAndKeys:@"value",@"key",@"Michael",@"name", nil];
2. NDictionary dict = @{@"key":@"value", @"name":@"Michael"};
dictionary 就是用 @{} 來表示,@[] 是 array,要注的是用 dictionaryWithObjectsAndKeys 的時候是先寫 object 再寫 key ,用 @{} 來表示的時候是先寫 key 再寫 value。
至於 mutable 的部分也是用
mutableCopy
NSMutableDictionary * myDict = [@{@"Name":@"Michael" } mutableCopy];
myDict = [NSMutableDictionary dictionaryWithDictionary:@{@"Name":@"Michael"}];
存取 key 值的時候也很方便直接把 key 物件丟到 [] 裡。如下
myDict[@"Name"] = @"morning"; // write
NSLog(@"%@", myDict[@"Name"]); // read
就和 Javascript 的 associative array 一樣。
綜合 array 和 dictionary 來看初始化的時候用 @[] 和 @{} 來區別,但是存取值的時候都用 [],來操作,只是 array 的 [] 放的是整數值,dictionary 的 [] 放的是物件。
用新的語法還有什麼好處呢?來看下方的程式碼
-(id) getNil{
return nil;
}
- (IBAction)insertNil:(id)sender {
NSLog(@"%@", @[ [self getNil], @"hello",]); // line a
NSLog(@"%@", [NSArray arrayWithObjects:[self getNil], @"hello", nil]); // line b
}
因為在 LLVM 4.0 之前的寫法 nil 在 array 或是 dictionary 裡面是當成結束,也就是說,萬一一開始就是 nil 那之後的元素就不理會,而新的語法可以在 compile 的時候找出奇怪的地方,因為新的語法裡不會有 nil 出現。如上方程式碼,[self getNil] 故意回傳 nil ,用新語法,line a 可以在 compile 時候就提出錯誤,而 line b 在執行的時候才會有可能被找到錯誤。
提筆至此,其實又可以增加一個
《需要換 Xcode 4.4 理由加一》
不過筆者不肯就此罷休,再提出一個問題來。自訂的 Class 想使用 [] 這個操作?
自訂 Class 使用 []
首先要分清楚,[] 裡面要放的東西,就我們所知有兩種,整數和物件。(從
array 和 dictionary 得知) 比如我想支援以下操作。
Car * car = [Car new]; // Any Class
car[1] = @"name"; // scalar write
NSLog(@"%@", car[0]); // scalar read
就必需在自己的Class 覆寫,這兩個 mehtod。就可以用 [] 裡面放 NSInteger 了
- (id) objectAtIndexedSubscript: (NSInteger) index{
return @"Car";
}
- (void) setObject: (id) thing atIndexedSubscript: (NSInteger) index{
NSLog(@"setting index %d with %@",index, thing);
}
如果 [] 要放的是物件,如下的操作
Car * car = [Car new]; // Any Class
car[@"dict"] = @"value"; // object write
NSLog(@"%@", car[@"good"]); // object read
就要覆寫以下兩個 method
- (id) objectForKeyedSubscript: (id) key{
return [@"dict-like " stringByAppendingFormat:@"%@", key];
}
- (void) setObject: (id) thing forKeyedSubscript: (id<NSCopying>) key{
NSLog(@"set %@ with %@", key, thing);
}
有沒有看到
setObject: forKeyedSubscript: 傳入的參數型別是 id<NSCopying> 。也就是說想用 myClass[key] = obj; 的時候,key 的 class 要有實作 <NSCopying> 提到的 required method 也就是 - (id)copyWithZone:(NSZone *)zone 。
好了,此次 Xcode 之旅就先暫時到這邊了,咱們下次再會,期待下次的 Xcode 之旅也會讓讀者們有所收獲。
最後請注意一下,筆者在寫這篇文章的時候,Xcode 4.4 (4F250) 上面的程式碼是可以執行的,但是換到 Xcode 4.4.1 (4F1003) 在幾個地方會有問題,@YES,@NO,或是 dict[@"key"], array[1] = @5 這種 subscript 的存取方式,可以參考 Apple
官方網頁,不過這些問題,"做夢夢到" 會在 Xcode 4.5 解決。