ios LLVM 4新功能

原文地址:http://blog.csdn.net/leeyehong_self/article/details/8002863

自從Xcode 4.2同ios5一起發佈,默認的編譯器就是LLVM3.0了。 蘋果從GCC切換到LLVM的一個目的是對Objective-C語言擁有更大的控制權。例如在Xcode 4.4中,蘋果通過添加對字面量的支持使得Objective-C更加簡潔。正是LLVM給了蘋果這種改變Objective-C語言的能力。

 字面量

  字面量並不是什麼新東西,Objective-C中一直以來都有字面量。接下來看一個簡單的NSString聲明語法。
1、NSString

NSString *greeting = [[NSString alloc] initWithCString:"Hello World!" encoding:NSUTF8StringEncoding]; //第一種方法:不使用字面量

//第二種方法:使用字面量
NSString  *greeting = @"Hello World !";

2、由標量直接創建NSNumber

NSNumber 是Foundation庫中的一個類對象,而數值1、2、3是標量。

 NSNumber *number = [NSNumbernumberWithInt:1];

 NSNumber *yesValue = [NSNumbernumberWithBool:YES];


有了LLVM 4,你可以使用如下語法來簡化代碼:

 NSNumber *number =@1;

 NSNumber *yesValue =@YES;

也可以通過添加F後綴來告訴編譯器將標量轉爲float類型。通過添加後綴U來將標量轉換爲無符號整型。

 NSNumber *valuePI =@3.14F;//使用float字面量聲明一個NSNumber對象

 NSNumber *radius =@3U;//使用無符號integer字面量聲明一個NSNumber對象


3、集合字面量(NSArray 和 NSDictionary)

    NSString *str1 =@"Hello";

   NSString *str2 =@"World";

   NSString *str3 =@"!";

   NSArray *myArray1 = [NSArrayarrayWithObjects:str1,str2,str3,nil];//用舊方法創建一個數組。


   NSArray *myArray1 =@[str1,str2,str3];//用集合字面量創建一個新數組。

使用字面量,不必再用nil標示數組末尾,編譯器自動完成這一任務。


把前面學過的集合字面量和數字標量結合起來可以很方便地創建一個NSNumber數組,如下所示:

 NSArray  *arrayOfIntegers =@[@1,@2,@3,@4];


使用字面量創建NSDictionary

NSDictionary *dictionary =@{@"key1" :@"value1",

                             @"key2" :@"value2"};

字典的key和value也不再是倒着先寫value,再寫key了;

在 LLVM 4以前,雖然標量數組支持下標操作,但是NSArray 和 NSDictionary並不支持通過下標訪問元素。需要使用 objectAtIndex:方法來訪問NSArray中的元素,使用

valueForKey:方法訪問NSDictionary中與某個鍵對應的值。在 LLVM4中,蘋果爲對象引入了下標訪問操作符。

    

  NSArray *array =@[@1,@2,@3,@4,@5];

  int elementAt3 = array[3];

通過下標訪問字典元素


 NSDictionary *dict =@{@"key1" :@"value1" ,

                          @"key2" :@"value2" ,

                          @"key3" :@"value3" ,};

 id elementAt3 = dict[@"key3"];


更多的示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  // 整數
  NSNumber *fortyTwo = @42;             // 等價於 [NSNumber numberWithInt:42]
  NSNumber *fortyTwoUnsigned = @42U;    // 等價於 [NSNumber numberWithUnsignedInt:42U]
  NSNumber *fortyTwoLong = @42L;        // 等價於 [NSNumber numberWithLong:42L]
  NSNumber *fortyTwoLongLong = @42LL;   // 等價於 [NSNumber numberWithLongLong:42LL]

  // 浮點數
  NSNumber *piFloat = @3.141592654F;    // 等價於 [NSNumber numberWithFloat:3.141592654F]
  NSNumber *piDouble = @3.1415926535;   // 等價於 [NSNumber numberWithDouble:3.1415926535]

  // 布爾值
  NSNumber *yesNumber = @YES;           // 等價於 [NSNumber numberWithBool:YES]
  NSNumber *noNumber = @NO;             // 等價於 [NSNumber numberWithBool:NO]

  // 空數組
  NSArray * array = @[];                // 等價於 [NSArray array]
  // 空的字典
  NSDictionary * dict = @{};            // 等價於 [NSDictionary dictionary]

怎麼樣?是不是簡單多了?而且,爲了方便你的舊代碼遷移到新的寫法,xcode專門還提供了轉換工具,在xcode4.4中,選擇 Edit -> Refactor -> Convert to Modern Objective-C Syntax即可。

局部的函數調用不用前向申明

這雖然是一個挺小的改進,但是很貼心。假如我們在一個源文件中有2個函數:分別名爲foo 和 bar,其中foo的定義在bar前面。那如果在foo函數內部直接調用bar,編譯器會報警告說找不到函數bar。

而現在,我們可以隨意地在源文件中放置函數bar的位置。編譯器在找不到bar時,會再源碼後面找,如果找到了bar,就不會報錯了。

帶有類型的enum

現在我們可以定義enum是無符號整數還是整數,這樣編譯器會更加智能的做類型檢查。如下所示:

1
2
3
4
5
6
7
8
9
10
typedef enum TableViewCellType : NSInteger {
    TableViewCellTypeQueue,
    TableViewCellTypeNewFans,
    TableViewCellTypeUserInfo,
    TableViewCellTypeOrganization,
    TableViewCellTypeFeedback,
    TableViewCellTypeRateApp,
    TableViewCellTypeRecommendation,
    TableViewCellTypeLogout
}TableViewCellType;

默認生成@synthesize代碼

以前寫完一個諸如 @property (nonatomic, strong) NSString * username; 變量定義後,馬上得轉到 .m文件中去增加相應的 @synthesize username = _username; 代碼。

現在,編輯器發現你沒有寫 @synthesize時,會自動幫你加上這一行。這同時在另一方面,起到了鼓勵大家使用以下劃線開頭的變量名作爲成員變量名的作用。

當然,爲了向下兼容,如果你的程序裏面已經有了 @property 變量對應的 @synthesize 代碼時,編輯器就不會自動幫你增加這個代碼了。

另外有2種特殊情況下,即使你沒有寫 @synthesize ,編輯器也不會自動幫你加上,這2種情況是:

  1. 你同時提供了該property的setter 和 getter方法。
  2. 你的這個property是 readonly 的。

遍歷元素

你是如何遍歷數組的元素的?通常我們有2種做法,一種是用 for in,另一種是用一個變量來循環數組下標。如下:

1
2
3
4
5
6
7
8
    NSArray * lines = ...
    for (NSString * line in lines) {
       // ...
    }
    for (int i = 0; i < lines.count; ++i) {
        NSString * s = [lines objectAtIndex:i];
        ...
    }

如果是字典,遍歷的代碼就要稍微複雜一點了:

1
2
3
4
5
6
    NSDictionary * dict = 
    NSArray * keys = [dict allKeys];
    for (NSString * key in keys) {
        NSString * value = [dict objectForKey:key];

    }

現在,xcode對於iOS4.0以上的系統,支持用block來遍歷元素了。用block來遍歷字典可以簡化代碼的編寫,建議大家都使用上這個新特性。

1
2
3
4
5
6
7
[lines enumerateObjectsUsingBlock:^(NSString * obj, NSUInteger idx, BOOL *stop) {

}];

[_urlArguments enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {

}];

Subscripting Methods

這個新特性在WWDC2012的視頻中提到了,但是在XCode4.4中沒有實現。也是一個很體貼的語法糖,它允許你用中括號來代替原本的方法來獲取和設置數組元素。

簡單來說,以前的 [array objectAtIndex:idx] 和 [array replaceObjectAtIndex:idx withObject:obj],可以直接寫作 array[idx] 和 array[idx] = obj了。其實這個特性在很多高級語言中都實現了,只是Objective-C生於80年代,一直沒改進這個。

這個改進同樣對NSDictionary有效。甚至,你也可以給你自己的類提供中括號操作符對應的方法。具體做法是實現如下兩個方法:

1
2
- (id)objectAtIndexedSubscript:(NSUInterger)idx;
- (void)setObject:(id)value atIndexedSubscript:(NSUInteger)idx;

期等XCode4.5中能夠使用上這個特性。

Tips

上面提到了不用寫 @synthesize 了,那原本寫的那麼多 @synthesize 怎麼辦呢?作爲有代碼潔癖的我很想把它們刪掉,但怎麼刪呢?一個文件一個文件打開,然後行一行刪掉嗎?放心,蘋果已經幫我們想了解決方案。在WWDC2012 Session 400 Developer Tools Kickoff 中,蘋果介紹了具體做法。步驟如下:

  1. 首先使用區域查找,因爲一般項目都會依賴第三方的開源庫,我們可不想更改別人的庫,所以我們只查找我們庫中的文件,如下圖所示:

  1. 接着我們用正則匹配,找到以 @synthesize開頭,後面接着是 var = _var; 格式的行。插入正則表達式很簡單,直接點擊查找輸入框左邊的放大鏡,選擇“insert pattern”,蘋果就會把常見的正則表達式都列出來,你直接選擇就可以了,非常方便。如下圖所示:

在插入好合適的正則表達式後,我們按回車,就可以搜索到結果。

  1. 我們點擊搜索界面的preview按鈕,查看替換效果,可以看到,對於我們測試代碼,XCode生成的預覽圖已經正確地當對應代碼刪掉了。然後我們就可以點擊替換,去掉所有的 @synthesize 代碼了。

在下載完XCode4.4後,我就把我們的工程代碼都轉換成了新特性的語法。在轉換後,我發現原本25000行的代碼少了將近1000行。心裏還是很開心的,因爲又可以少寫一些體力活類型的代碼了。

還是那句話,希望這些新特性能夠讓大家玩得開心。

參考資料

發佈了23 篇原創文章 · 獲贊 0 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章