Blocks编程
1.介紹
Block是一個C Level的語法以及運行時的一個特性,非常像標準C中的函數(函數指針),但是其運行需要編譯器和運行時支持,目前LLVM+Clang可以很好的支持Block(蘋果修改過的GCC也可以)。Block和函數不同的是其語義?閉包?特性,以及可以有匿名block的存在。 你可以在LLVM的官方網站查看Block語言規范.?
你可以通過{}內的.
上面代碼中的 2. 聲明創建和調用
聲明Block變量?
Block變量保存著指向Block的指針,聲明一個Block變量就和聲明一個函數指針變量類似,只是將*改成了.?其他的就和C的類型系統保持一致了。
另 Block還支持可變參數variadic (...) ,沒有參數的話,變量列表的地方必須寫上void關鍵字.
聲明Block類型?你可以通過typedef聲明Block的類型,這樣多個地方需要使用同種類型的Block的時候會比較方便,
typedef float (^MyBlockType)(float, float); MyBlockType myFirstBlock = // ... ; MyBlockType mySecondBlock = // ... ;Block創建?聲明了一個Block變量之后,可以為這個變量賦值
blockReturningVoidWithVoidArgument = ^{ printf("%s","Block Returing Void With Void Argument."); }當然你可以在聲明變量的同時賦值
void (^blockReturningVoidWithVoidArgument)(void) = ^{ printf("%s","Block Returing Void With Void Argument."); }Block調用?Block的調用和函數的調用是非常相似的,如上面定義的blockReturningVoidWithVoidArgument,調用的時候則直接blockReturningVoidWithVoidArgument();便可.
匿名Block?當一個Block作為函數參數的時候,一般實參都是以匿名Block的方式傳過去的。
void callVoidVoid(void (^closure)(void)) { closure(); } int main(int argc, char *argv[]) { __block int i = 10; callVoidVoid(^{ ++i; }); if (i != 11) { printf("*** %s didn't update i\n", argv[0]); return 1; } printf("%s: success\n", argv[0]); return 0; }當然你也可以直接調用匿名Block,如
^{ ++i; }();3.Block和變量
一個Block的內部是可以引用自身作用域外的變量的,包括static變量,extern變量或自由變量(定義一個變量的時候,如果不加存儲修飾符,默 認情況下就是自由變量auto,auto變量保存在stack中的.除了auto之外還存在register,static等存儲修飾符) ,對于自由變量,在Block中是只讀的。在引入block的同時,還引入了一種特殊的變量存儲修飾符 代碼示例 3.1
__block int blockValue = 0; int autoValue = 0; void(^printValue)(void) = ^{ printf("blockValue = %d\n",blockValue); printf("autoValue = %d\n",autoValue); }; blockValue ++; autoValue ++; printValue();3.1中的代碼,輸出的值為
blockValue = 1 autoValue = 0可以看到自由變量盡管自增了,但是在調用printValue這個Block的時候,看到的還是其定義的時候看到的那個autoValue的值,autoValue的值在Block的內部示無法修改的,要不然編譯器會報錯:
Semantic Issue: Variable is not assignable (missing __block type specifier)Block定義時內存是分配在stack上的,當其作用域結束,就會被自動釋放,所以你不需要去擔心它的內存情況,我們可以對一個Block進行Block_copy()之后,Block會被拷貝到heap中的內存中,且其所有的引用到的自由變量也將會被拷貝,當然你得記得通過 在Block內部如果引用到對象或者對象的成員變量,那么當Block被拷貝 代碼示例 3.2
NSObject *testObject = [[NSObject alloc] init]; NSLog(@"%lu",[testObject retainCount]); //1 NSLog(@"%lu",[self retainCount]); //1 void(^testBlock)(void) = ^{ NSLog(@"The Test String : %@", testObject); NSLog(@"The Window Object : %@", _window); }; NSLog(@"%lu",[testObject retainCount]); //1 NSLog(@"%lu",[self retainCount]); //1 void(^testBlock2)(void) = Block_copy(testBlock); //testBlock會被拷貝到heap中,所以用完了要自己調用Block_release進行釋放 NSLog(@"%lu",[testObject retainCount]); //2 NSLog(@"%lu",[self retainCount]); //2 testBlock2(); Block_release(testBlock2); NSLog(@"%lu",[testObject retainCount]); //1 NSLog(@"%lu",[self retainCount]); //1 [testObject release];Block的閉包特性使得Block可以脫離其定義的作用域進行運行,所以你可以在一個函數中返回一個Block,在別的線程或者當前線程的RunLoop中進行運行,而不用擔心那些引用到的外部變量是否被釋放掉了。
4.Block實際應用
那么我們一般什么時候會用到Block呢? Blocks通常是一小段自包含的代碼片段.所以它經常被用于多線程運行的代碼單元(如GCD),或用于處理聚合類元素單元,或者作為某個函數調用完成后的回調函數.
Block用作回調函數比傳統的回調函數有以下的優越性: (Jacky Shin:下面這個是重點,需要仔細理解使用場合)
- 在函數調用的時候,將Block作為一個參數傳給函數
- 允許訪問本地變量,這樣可以避免通過結構體將本地變量封裝后傳遞給回調函數
應用1: Animations & Completion Handler
[UIView animateWithDuration:2 animations:^{ self.view.backgroundColor = [UIColor redColor]; } completion:^(BOOL finished){ if (finished){ self.view.backgroundColor = [UIColor blueColor]; } }]; 應用2: Enumeration?
對數據集合類中的每一個元素進行遍歷,每次傳入一個對象,進行處理
應用3: Notification Handler
[[NSNotificationCenter defaultCenter] addObserverForName:@"TestNotification" object:nil queue:aNSOperationQueue usingBlock:^(NSNotification *notification){ NSLog(@"Notification: %@",notification); }];應用4: GCD
dispatch_queue_t imageDownloadQueue = dispatch_queue_create("Image Download Queue", NULL); dispatch_async(imageDownloadQueue, ^{ NSURL *imageURL = [NSURL URLWithString:@"http://xxx.xx.com/a.png"]; NSData *imageData = [NSData dataWithContentsOfURL:imageURL]; UIImage *image = [UIImage imageWithData:imageData]; dispatch_async(dispatch_get_main_queue(), ^{ [imageView setImage:image]; }); });轉載于:https://www.cnblogs.com/duyuiOS/p/4899908.html
總結
- 上一篇: IOS关于图片上传
- 下一篇: maven package 知识(转载)