本篇文章的主要內(nèi)容
- 了解何謂block,。
了解block的使用方法。
Block 是iOS在4.0版本之后新增的程序語法.
在iOS SDK 4.0之后,,Block幾乎出現(xiàn)在所有新版的API之中,,換句話說,如果不了解Block這個(gè)概念就無法使用SDK 4.0版本以后的新功能,,因此雖然Block本身的語法有點(diǎn)難度,,但為了使用iOS的新功能我們還是得硬著頭皮去了解這個(gè)新的程序概念。
一,、看一看什么是Block
我們使用^
運(yùn)算符來聲明一個(gè)Block變量,,而且在聲明完一個(gè)Block變量后要像聲明普通變量一樣,最后要加;
,。
聲明Block變量
接下來,,我們通過一個(gè)例子來聲明一個(gè)簡單的Block變量.
int (^block)( int ) = NULL;
我們一起來看一下聲明Block變量的語法
數(shù)據(jù)返回值類型 (^變量名) (參數(shù)列表) = NULL;
賦值Block變量
block = ^(int m){
return m * m;
};
- 使用Block變量
NSLog(@"10的平方是:%d",block(10));
注意,到目前我們應(yīng)該有發(fā)現(xiàn)block變量的使用步驟,,有類似于函數(shù)的步驟
- 首先都要聲明(聲明函數(shù),聲明block變量);
- 然后都要進(jìn)行實(shí)現(xiàn)(實(shí)現(xiàn)函數(shù),,為block變量賦值實(shí)現(xiàn)過程);
- 最后都要進(jìn)行調(diào)用才能實(shí)現(xiàn)具體功能
二、看一看如何直接使用block參數(shù)
數(shù)組排序
NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithObjects:@"5",@"2",@"3",@"9",@"7", nil];
[mutableArray sortUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSString *value1 = (NSString *)obj1;
NSString *value2 = (NSString *)obj2;
return [value1 compare:value2];
}];
NSLog(@"%@",mutableArray);
簡單的網(wǎng)絡(luò)異步請求
NSURL *url = [NSURL URLWithString:@"http://www.qq.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",result);
}];
可以看出ios平臺中的很多功能都已經(jīng)集成了Block語法的處理方法.
三,、看一看深入理解Block語法
在本節(jié),,主要要去介紹的就是使用__block
修飾的變量能夠完成的作用。
先來看一個(gè)例子,。
int intValue = 3;
int (^block)(int) = ^(int m){
return m * intValue;
};
NSLog(@"block(5) = %d",block(5));
在上面的例子中,我們將intValue
變量稱為block
執(zhí)行過程中的外部變量,在block
執(zhí)行過程中可以直接使用該外部變量,。
再看一個(gè)例子?!?/p>
int intValue = 3;
int (^block)(int) = ^(int m){
intValue++;
return m * intValue;
};
NSLog(@"block(5) = %d",block(5));
在上面的例子中,我們編譯程序后發(fā)現(xiàn)編譯器會有紅色錯(cuò)誤,錯(cuò)誤提示為
Variable is not assignable (missing __block type specifier)
為什么會出現(xiàn)不能被賦值的錯(cuò)誤提示呢,?
block
在實(shí)現(xiàn)時(shí)就會對它引用到的它所在方法中定義的棧變量進(jìn)行一次只讀拷貝- 在 block 塊內(nèi)使用該只讀拷貝。
那為了避免上述錯(cuò)誤,,就要使用__block
修飾符來修飾外部變量,用來通知編譯器該外部變量intValue
與block
中的intValue
指的是同一塊兒內(nèi)存地址,,而不需要內(nèi)存拷貝。
<br/>
如下例:
__block int intValue = 3;
int (^block)(int) = ^(int m){
intValue++;
return m * intValue;
};
NSLog(@"block(5) = %d",block(5));
四,、使用Block要注意的內(nèi)存問題
使用weak–strong dance
技術(shù)來避免循環(huán)引用
舉例如下
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
{
id observer;
}
- (void)viewDidLoad
{
[super viewDidLoad];
observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"kThemeChangeNotification" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
NSLog(@"%@",self);
}];
}
- (void)dealloc
{
if (observer) {
[[NSNotificationCenter defaultCenter] removeObserver:observer];
}
}
@end
在上面代碼中,,我們添加向通知中心注冊了一個(gè)觀察者,,然后在 dealloc 時(shí)解除該注冊,,一切看起來正常。但這里有兩個(gè)問題:
在消息通知 block
中引用到了 self
,,在這里 self
對象被 block
保留一次,而 observer
又 retain 該 block
的一份拷貝,,通知中心又持有 observer
,。因此只要 observer
對象還沒有被解除注冊,block
就會一直被通知中心持有,,從而 self
就不會被釋放,,其 dealloc
就不會被調(diào)用。而我們卻又期望在 dealloc 中通過 removeObserver
來解除注冊以消除通知中心對 observer/block
的 保留次數(shù),。
同時(shí),,observer
是在 self
所在類中定義賦值,因此是被 self retain
的,,這樣就形成了循環(huán)引用,。
解決方式如下.
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
{
id observer;
}
- (void)viewDidLoad
{
[super viewDidLoad];
__weak ViewController *wSelf = self;
observer = [[NSNotificationCenter defaultCenter] addObserverForName:@"kThemeChangeNotification" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note){
ViewController *bSelf = wSelf;
if (bSelf) {
NSLog(@"%@",bSelf);
}
}];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (void)dealloc
{
if (observer) {
[[NSNotificationCenter defaultCenter] removeObserver:observer];
}
}
@end
- 在
block
之前定義對 self
的一個(gè)弱引用 wSelf
,因?yàn)槭侨跻?,所以?dāng) self
被釋放時(shí) wSelf
會變?yōu)?code style="padding: 2px 4px; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 12px; color: rgb(101, 123, 131); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; background-color: rgb(253, 246, 227); border: none; white-space: pre;">nil,; - 在
block
中引用該弱應(yīng)用,考慮到多線程情況,,通過使用強(qiáng)引用 bSelf
來引用該弱引用,,這時(shí)如果 self
不為 nil
就會 retain self
,以防止在后面的使用過程中 self 被釋放; 在之后的 block
塊中使用該強(qiáng)引用 bself
,,注意在使用前要對 bSelf
進(jìn)行了 nil
檢測,,因?yàn)槎嗑€程環(huán)境下在用弱引用 wSelf
對強(qiáng)引用 bSelf
賦值時(shí),弱引用 wSelf
可能已經(jīng)為 nil
了,。
通過這種weak-strong
手法,,block
就不會持有 sel
f 的引用,從而打破了循環(huán)引用,。