block的使用浅析

1 block的基本概念

1.1 block的产生和用途

代码块Block是苹果在iOS4开始引入的对C语言的扩展,用来实现匿名函数的特性,Block是一种特殊的数据类型,其可以正常定义变量、作为参数、作为返回值,特殊地,Block还可以保存一段代码,在需要的时候调用,目前Block已经广泛应用于iOS开发中。Block实际上是OC语言对闭包的实现,是带有自动变量值的匿名函数。Block既可以定义在函数内部也可以定义在函数外部。只有在调用block的时候,block{}内的代码才会执行。

1.2 闭包的概念

闭包就是一个函数,或者一个指向函数的指针,加上这个函数执行的非局部变量。闭包允许一个函数访问声明该函数运行上下文中的变量,甚至可以访问不同运行上文中的变量。

1.3 block的声明与定义

 int (^myBlock)(int) = ^(int num){

return num*num;

};

int 代表返回类型 ^代表的这是一个block

myBlock代表block的名字 (int)代表参数类型

(int num)代表形参的类型及名字

在定义block的时候一定不要忘记在最后加上分号

block是一个对象,内部是一个结构体,在创建block 的时候就把它的指针传给了block,所以可以直接调用block块

但是为了使用block方便,一般在定义block的时候会用typedef简化block如:typedef void(^myBlock)(int) ;

1.4 block的实质

通俗点说,block是一个结构体,它里面包含了函数指针以及block外部上下文变量等信息,这个函数指针指向的是在定义block时的代码块。

1.5 block最常使用的情况

block最常使用的方式:界面传值;回调

2 Block对变量的访问与修改

2.1 block对局部变量的访问与修改

(1) block1 = ^{
        NSLog(@"哈哈哈哈哈哈");
    };
    block1();

(2) NSInteger aaa = 100;
    block2 = ^{
        aaa++;    //会报错
        NSLog(@"aaa的值为%ld",aaa);
    };

(3)__block NSInteger aaa = 100;
    block2 = ^{
        aaa++;  
        NSLog(@"aaa的值为%ld",aaa);   //aaa = 101
    };

(4) NSInteger aaa = 100;
    block5 = ^{
        NSLog(@"aaa的值为%ld",aaa);//aaa = 100
    };
    aaa = 105;
    block5();

(5)__block NSInteger ddd = 10;
    block7 = ^{
        ddd = ddd +1;
        NSLog(@"ddd现在的值为%ld",ddd);
    };
    ddd = 100;
    block7();

通过(1)说明block只有在调用的时候其内部代码才会执行,不调用其内部代码不会执行,通过(2)和(3)说明block可以访问局部变量,但是不能对其进行修改,如果要在block里面修改局部变量的值,那么要在局部变量前面加_ block修饰符 。通过(4)和(5)可以看出如果局部变量不加 block来进行修饰,那么当在block定义后block调用前修改局部变量的值,那么block里面的局部变量依然是block定义时的值(因为在block定义的时候就将局部变量的值传给了block所指向的结构体,所以局部变量的改变不会影响block里面的局部变量,但是block里面的局部变量也是不可修改的),如果局部变量前面加 _block修饰,那么当在block定以后block执行前对局部变量进行修改,block里面的局部变量值也会进行相应的改变(因为用__block声明局部变量后,在block里面是把局部变量的指针传给block指向的结构体的,所以其值可以被改变)。

2.2block对全局变量的访问

(1)// 声明全局变量global
int global = 100;
void(^myBlock)() = ^{
   NSLog(@"global = %d", global);
};// 调用后控制台输出"global = 100"
myBlock();
(2)// 声明全局变量global
int global = 100;
void(^myBlock)() = ^{
 NSLog(@"global = %d", global);// 调用后控制台输出"global = 101"
};
global = 101;
myBlock();
(3)// 声明全局变量global
int global = 100;
void(^myBlock)() = ^{
    global ++;
   NSLog(@"global = %d", global);// 调用后控制台输出"global = 101"
};
myBlock();

结论:block可以直接对全局变量进行访问和修改(全局变量所占用的内存只有一份,供所有函数共同调用,在Block定义时并未将全局变量的值或者指针传给Block变量所指向的结构体,因此在调用Block之前对局部变量进行修改会影响Block内部的值,同时内部的值也是可以修改的)

2.3 block对全局静态变量的访问

(1)// 声明静态变量global
static int global = 100;
void(^myBlock)() = ^{
   NSLog(@"global = %d", global);// 调用后控制台输出"global = 100"
};
myBlock();
(2)// 声明静态变量global
static int global = 100;
void(^myBlock)() = ^{
    NSLog(@"global= %d", global);// 调用后控制台输出"global = 101"
};
global = 101;
myBlock();
(3)// 声明静态变量global
static int global = 100;
void(^myBlock)() = ^{
    global ++;
   NSLog(@"global = %d", global);// 调用后控制台输出"global = 101"
};
myBlock();

结论:block里面可以直接访问和修改静态全局变量(因为在Block定义时便是将静态变量的指针传给Block变量所指向的结构体,因此在调用Block之前对静态变量进行修改会影响Block内部的值,同时内部的值也是可以修改的)

3 block的使用方式

block的使用与代理很类似,代理是让某个类满足自己的某个协议,然后实现协议里面的方法。Block是自己在本类定义了一个代码块,但是在需要的时候才会去调用。下面是一个block使用的小列子:
业务需求是在一个封装的view中点击了tableView的某一行,然后通过block把这一行上的字符串传出去进行处理,下面是具体实现:

view的.h文件:
typedefvoid (^ChooseViewClick)(NSString*);
@interfaceChooseView : UIView<UITableViewDataSource,UITableViewDelegate>
@property(nonatomic,copy)ChooseViewClick chooseClick;
@end

当tableView的某一行被点击时:

- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [self dismiss];
    NSString *str =_showArray[indexPath.row];
    if(self.chooseClick) {
       self.chooseClick(str);
    }
 }

在另一个控制器进行处理

 _chooseView.chooseClick = ^(NSString *str)
  {
           _selectTag = 0;
            [btnsetTitle:str forState:UIControlStateNormal];
        };

4 block使用之避免循环引用

在使用block的时候要特别注意的是避免循环引用,循环引用指的是两个对象都相互强引用了对方,从而导致谁也释放不了,引起内存泄露问题。最常见的分为两种情况,一种是这个对象拥有这个block,但是在block块里面又引用了这个对象本身,第二种是block是宿主的一个属性,但是在block里面又访问了宿主的其他属性。
第一种情况,block是self本身的一个属性,在block里面又访问了宿主本身:

self.myblock = ^{
[self doSomething];
};

在这里会引起循环引用,解决办法是用__weak修饰,正确代码如下:

__weak typedef(self) weakSelf = self;
self.myblock = ^{
[weakSelf doSomething];
};

第二种情况,block是宿主本身的属性,在block里面又访问了宿主的其他属性:

self.myblock = ^{
[self.muArray removeAllObjects];
};    //引起循环引用

此时解决方案跟上面一样,可以加__block 或者__weak 来修饰,正确代码如下:

__block typedef(self) weakSelf = self;
self.myblock = ^{
[weakSelf.muArray removeAllObject];
};
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容