iosblock在什麼時候編譯
『壹』 如何在iOS中使用Block
你可以使用^操作符來聲明一個Block變數,它表示一個Block的開始。
int num1 = 7;
int(^aBlock)(int) = ^)int num2) {
return num1+nunm2;
};
在如上代碼中我們將Block聲明為一個變數,所以可以將它當做一個函數中使用:
NSLog(@"%d", aBlock(49)); //adds 49 to 7 which gives us 56.
我們剛看過了將block當做變數的情況,但通常情況下我們會以內聯的方式使用Block,比如在一個變數中。API要麼會使用Block在一個對象集合上執行某種操作,要麼將其作為一個操作完成後的回調。
NSComperator compareStringsBlock = ^(id stringA, id stringB) {
NSRange rangeS = NSMakeRange (0, [stringA length]);
return (stringA compare:stringB options:comparisonOptions range:rangeS locale:currentLocale];
};
NSArray *compareSortArray = [arrayOfStringDays sortArrayUsingComparator: compareStringsBlock]);
Block具有將臨時函數體創建為表達式的優勢。Apple文檔中指出:
Block是符合如下要求的匿名內聯的代碼集:
和函數一樣具有一個指定類型的參數列表
有一個可以推導或聲明的返回值類型
可以從它被定義的詞義范圍中捕捉狀態
可以在需要的時候改變詞義范圍的狀態
可以和相同的詞義范圍中定義的其他的Block共享更改的可能。
可以在詞義范圍(堆棧幀)被銷毀後繼續共享和修改該詞義范圍(堆棧幀)的狀態。
Block是一個自包含的小代碼段,封裝了用於遍歷(線性遍歷)或者回調,可以並發執行的任務單元。
聲明和使用Block
Apple文檔中介紹了如何將一個Block聲明為變數,並將其作為一個函數使用:
int (^oneFrom)(int) = ^(int anInt) {
return anInt - 1;
};
// 我們創建了一個內聯塊^(int anInt)... ,其函數體和結果被傳到了另外一個名為OneFrom的Block。
printf("1 from 10 is %d", oneFrom(10));
// 列印出: "1 from 10 is 9"
// 這個block函數(distanceTraveled)傳入3個float型參數,返回float值。
float (^distanceTraveled) (float, float, float) =
^(float startingSpeed, float acceleration, float time) {
float distance = (startingSpeed * time) + (0.5 * acceleration * time * time);
return distance;
};
你也可以傳入一個Block作為一個參數,而不要以如上的方式聲明它們,這樣就可以在需要將block作為參數的時候以內聯代碼的方式簡單地實現。
NSArray *anArray = [NSArray arrayWithObjects: @"cat", @"dog",nil];
sortFunction(anArray, ^(string *a string *b){
if ( a == @"cat") return TRUE; });
這樣我們就看到一個內聯的block代碼段占據了最後一個參數(必須是參數列表的最後一個參數)的位置。Cocoa提供了很多使用Block的方法,這樣你就可以傳入Block作為方法的參數:
NSArray *array = [NSArray arrayWithObjects: @"A", @"B", @"C", nil];
NSSet *filterSet = [NSSet setWithObjects: @"A", @"Z", @"Q", nil];
BOOL (^test)(id obj, NSUInteger idx, BOOL *stop); //Block declaration returns BOOL, params inc. id and BOOL
//body of block gets the block literal ^(id obj, NSUInteger idx, Bool *stop)... and the body logic
test = ^ (id obj, NSUInteger idx, BOOL *stop) {
if (idx < 5) {
if ([filterSet containsObject: obj]) {
return YES;
}
}
return NO;
};
Apple提供的另外一個例子是:
__block BOOL found = NO;
NSSet *aSet = [NSSet setWithObjects: @"Alpha", @"Beta", @"Gamma", @"X", nil];
NSString *string = @"gamma";
//we provide below a way of how to enumerate, using our own compare logic
[aSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
if ([obj :string] == NSOrderedSame) {
*stop = YES;
found = YES;
}
}];
掌握它需要一點時間,但一旦領會了還是很簡答的,是不?我建議大家看下Apple的文檔,並看看其中引用到的一些API以確認下它們是如何使用的。多練習,熟能生巧!
『貳』 arc是一種編譯時特性還是運行時特性
ARC本質 ARC編譯器()特性運行特性更垃圾收器(GC) Automatic Reference Counting (ARC) is a compiler-level feature that simplifies the process of managing object lifetimes (memory management) in Cocoa applications. ARC相於MRC(Manual Reference Counting或稱非ARC文我直使用MRC指代非ARC管理式)改進前技術本質沒區別具體信息參考ARC編譯器官文檔 ARC啟與關閉 同於XCode四創建工程選擇關閉ARCXCode5創建工程默認啟ARC沒關閉ARC選項 需要特定文件啟或關閉ARC工程選項選擇Targets -> Compile Phases -> Compile Sources面找應文件添加flag: 打ARC:-fobjc-arc 關閉ARC:-fno-objc-arc 圖: ARC修飾符 ARC主要提供四種修飾符別:__strong,__weak,__autoreleasing,__unsafe_unretained __strong 表示引用強引用應定義property"strong"所象沒任何強引用指向才釋放 注意:聲明引用加修飾符引用默認強引用需要釋放強引用指向象需要強引用置nil __weak 表示引用弱引用應定義property用"weak"弱引用影響象釋放即要象沒任何強引用指向即使依00弱引用象指向沒用該象依釋放象釋放同指向弱引用自置nil技術叫zeroing weak pointer效防止效指針、野指針產__weak般用delegate關系防止循環引用或者用修飾指向由Interface Builder編輯與UI控制項 __autoreleasing 表示autorelease pool自釋放象引用MRC代autorelease用相同定義property能使用修飾符任何象property都應該autorelease型 見誤解ARC沒autorelease自釋放看起像點余誤解能源自於ARC自autorelease自混淆其實要看每iOS Appmain.m文件能知道autorelease僅存著並且變更fashion:需要再手工創建需要再顯式調用[drain]釋放內存池 兩行代碼意義相同 NSString *str = [[[NSString alloc] initWithFormat:@"hehe"] autorelease]; // MRC NSString *__autoreleasing str = [[NSString alloc] initWithFormat:@"hehe"]; // ARC 關於autoreleasepool做展詳細信息參考官文檔或者其文章 __autoreleasingARC主要用參數傳遞返值(out-parameters)引用傳遞參數(pass-by-reference)情況 __autoreleasing is used to denote arguments that are passed by reference (id *) and are autoreleased on return. 比用NSError使用: NSError *__autoreleasing error; if (![data writeToFile:filename options:NSDataWritingAtomic error:&error]) { NSLog(@"Error: %@", error); } (面writeToFileerror參數類型(NSError *__autoreleasing *)) 注意error定義strong型編譯器幫隱式做事情保證終傳入函數參數依__autoreleasing類型引用 NSError *error; NSError *__autoreleasing tempError = error; // 編譯器添加 if (![data writeToFile:filename options:NSDataWritingAtomic error:&tempError]) { error = tempError; // 編譯器添加 NSLog(@"Error: %@", error); } 所提高效率避免種情況我般定義error候其(實實==)聲明__autoreleasing類型: NSError *__autoreleasing error; 加__autoreleasing相於MRC返值error做事情: *error = [[[NSError alloc] init] autorelease]; *error指向象創建放入autoreleasing pool等待使用結束自釋放函數外error使用者並需要關*error指向象釋放 另外點ARC所種指針指針 (NSError **)函數參數加修飾符編譯器默認認定__autoreleasing類型 比面兩段代碼等同: - (NSString *)doSomething:(NSNumber **)value { // do something } - (NSString *)doSomething:(NSNumber * __autoreleasing *)value { // do something } 除非顯式給value聲明__strong否則value默認__autoreleasing 點某些類隱式使用自autorelease pool種候使用__autoreleasing類型要特別 比NSDictionary[]: - (void)loopThroughDictionary:(NSDictionary *)dict error:(NSError **)error { [dict :^(id key, id obj, BOOL *stop){ // do stuff if (there is some error && error != nil) { *error = [NSError errorWithDomain:@"MyError" code:依 userInfo:nil]; } }]; } 隱式創建autorelease pool面代碼實際類似於: - (void)loopThroughDictionary:(NSDictionary *)dict error:(NSError **)error { [dict :^(id key, id obj, BOOL *stop){ @autoreleasepool // 隱式創建 { if (there is some error && error != nil) { *error = [NSError errorWithDomain:@"MyError" code:依 userInfo:nil]; } } }]; // *error 已經dict做枚舉遍歷創建autorelease pool釋放掉 :( } 能夠使用*error我需要strong型臨引用dict枚舉Block用臨引用保證引用指向象dict枚舉Block釋放確式: - (void)loopThroughDictionary:(NSDictionary *)dict error:(NSError **)error { __block NSError* tempError; // 加__block保證Block內修改 [dict :^(id key, id obj, BOOL *stop) { if (there is some error) { *tempError = [NSError errorWithDomain:@"MyError" code:依 userInfo:nil]; } }] if (error != nil) { *error = tempError; }
『叄』 如何在iOS中使用Block──How to use Blocks with iOS
Block可以幫助我們組織獨立的代碼段,並提高復用性和可讀性。iOS4在UIKit中引入了該特徵。超過100個的Apple API都使用了Block,所以這是一個我們必須開始熟悉的知識。
Block是什麼樣的?
你可以使用^操作符來聲明一個Block變數,它表示一個Block的開始。
int num1 = 7;
int(^aBlock)(int) = ^)int num2) {
return num1+nunm2;
};
在如上代碼中我們將Block聲明為一個變數,所以可以將它當做一個函數中使用:
NSLog(@"%d", aBlock(49)); //adds 49 to 7 which gives us 56.
我們剛看過了將block當做變數的情況,但通常情況下我們會以內聯的方式使用Block,比如在一個變數中。API要麼會使用Block在一個對象集合上執行某種操作,要麼將其作為一個操作完成後的回調。
NSComperator compareStringsBlock = ^(id stringA, id stringB) {
NSRange rangeS = NSMakeRange (0, [stringA length]);
return (stringA compare:stringB options:comparisonOptions range:rangeS locale:currentLocale];
};
NSArray *compareSortArray = [arrayOfStringDays sortArrayUsingComparator: compareStringsBlock]);
Block具有將臨時函數體創建為表達式的優勢。Apple文檔中指出:
Block是符合如下要求的匿名內聯的代碼集:
和函數一樣具有一個指定類型的參數列表
有一個可以推導或聲明的返回值類型
可以從它被定義的詞義范圍中捕捉狀態
可以在需要的時候改變詞義范圍的狀態
可以和相同的詞義范圍中定義的其他的Block共享更改的可能。
可以在詞義范圍(堆棧幀)被銷毀後繼續共享和修改該詞義范圍(堆棧幀)的狀態。
Block是一個自包含的小代碼段,封裝了用於遍歷(線性遍歷)或者回調,可以並發執行的任務單元。
聲明和使用Block
Apple文檔中介紹了如何將一個Block聲明為變數,並將其作為一個函數使用:
int (^oneFrom)(int) = ^(int anInt) {
return anInt - 1;
};
// 我們創建了一個內聯塊^(int anInt)... ,其函數體和結果被傳到了另外一個名為OneFrom的Block。
printf("1 from 10 is %d", oneFrom(10));
// 列印出: "1 from 10 is 9"
// 這個block函數(distanceTraveled)傳入3個float型參數,返回float值。
float (^distanceTraveled) (float, float, float) =
^(float startingSpeed, float acceleration, float time) {
float distance = (startingSpeed * time) + (0.5 * acceleration * time * time);
return distance;
};
你也可以傳入一個Block作為一個參數,而不要以如上的方式聲明它們,這樣就可以在需要將block作為參數的時候以內聯代碼的方式簡單地實現。
NSArray *anArray = [NSArray arrayWithObjects: @"cat", @"dog",nil];
sortFunction(anArray, ^(string *a string *b){
if ( a == @"cat") return TRUE; });
這樣我們就看到一個內聯的block代碼段占據了最後一個參數(必須是參數列表的最後一個參數)的位置。Cocoa提供了很多使用Block的方法,這樣你就可以傳入Block作為方法的參數:
NSArray *array = [NSArray arrayWithObjects: @"A", @"B", @"C", nil];
NSSet *filterSet = [NSSet setWithObjects: @"A", @"Z", @"Q", nil];
BOOL (^test)(id obj, NSUInteger idx, BOOL *stop); //Block declaration returns BOOL, params inc. id and BOOL
//body of block gets the block literal ^(id obj, NSUInteger idx, Bool *stop)... and the body logic
test = ^ (id obj, NSUInteger idx, BOOL *stop) {
if (idx < 5) {
if ([filterSet containsObject: obj]) {
return YES;
}
}
return NO;
};
Apple提供的另外一個例子是:
__block BOOL found = NO;
NSSet *aSet = [NSSet setWithObjects: @"Alpha", @"Beta", @"Gamma", @"X", nil];
NSString *string = @"gamma";
//we provide below a way of how to enumerate, using our own compare logic
[aSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {
if ([obj :string] == NSOrderedSame) {
*stop = YES;
found = YES;
}
}];
As you can see, it takes a little while to have it sink in but once you get it, it's quite simple. I suggest looking at Apple's documentation, as well as looking at the referenced APIs to see how they are used. Practice makes perfect.