__block修饰符的作用域问题

来源:互联网 发布:二分搜索算法流程图 编辑:程序博客网 时间:2024/05/21 17:08

~~~~我的生活,我的点点滴滴!!







我们知道,当在一个Block中想要访问这个Block之外的变量时,可以直接调用,但当我们想在Block中修改这个成员变量时,需要为

个外部变量使用__block关键字进行声明,前面我们使用__block声明了一个基本数据类型int,那么我们在Block内成功将n改为了2:


#import <Foundation/Foundation.h>typedef int(^Sum)(int, int);int main(int argc, const char * argv[]){    @autoreleasepool {                // insert code here...        //NSLog(@"Hello, World!");                int n = 1;                Sum sum = ^(int a, int b)        {            //n = 2;                        NSLog(@"n = %d", n);                        return (a+b) * n;        };                NSLog(@"n = %d, result = %d", n, sum(5, 6));            }    return 0;}


看看运行结果:

2015-04-29 08:23:12.186 blocktest[10816:303] n = 12015-04-29 08:23:12.188 blocktest[10816:303] n = 1, result = 11


不对啊!block里面打印的n=2,而外部打印的却是1,这是为什么呢?这说明使用__block修饰后的基本变量在block中的修改只对block中

有用,并不会真正改变这个变量的值!

此时会有人问:如果不把n声明为__block会怎么样了?如果没有添加关键字__block,block里面也能捕获到n的存在,只不过在里面不能更改n的值,

即此时要注释掉 n = 2,不然就会报错。

那么,对于基本变量如此,对于对象变量呢?我们再来试试:


新建一个测试对象:


TestObject.h

@interface TestObject : NSObject @property (nonatomic, retain) NSString * name; @end


TestObj.m

#import "TestObject.h" @implementation TestObject - (void)dealloc {    NSLog(@"%@被销毁了!",self);    [_name release];    [super dealloc];} @end




main.m


#import <Foundation/Foundation.h>#import "TestObject.h"typedef int(^Sum)(int, int);int main(int argc, const char * argv[]){    @autoreleasepool {                // insert code here...        //NSLog(@"Hello, World!");                int n = 1;                Sum sum = ^(int a, int b)        {            //n = 2;                        NSLog(@"n = %d", n);                        return (a+b) * n;        };                NSLog(@"n = %d, result = %d", n, sum(5, 6));                __block TestObject *obj = [[TestObject alloc] init];                obj.name = @"test out block";                NSString* (^Name)(TestObject *obj) = ^(TestObject *obj)        {            obj.name = @"test in block";                        return obj.name;        };                NSLog(@"%@", obj.name);        NSLog(@"%@", Name(obj));        //加不加__block 都输出 "test in block" 说明改变了其值,block里面此用的是指针地址        NSLog(@"%@", obj.name);    }    return 0;}



这里我们在main函数中定义了一个TestObject对象,并调用setter方法更改name的属性。然后将TestObject对象传入一个名为Name的block中,

在block再调用setter方法修改name属性。再在外部打印返回值和TestObject对象的getter方法的值:结果如下:

2015-04-29 08:23:12.186 blocktest[10816:303] n = 12015-04-29 08:23:12.188 blocktest[10816:303] n = 1, result = 112015-04-29 08:23:12.188 blocktest[10816:303] test out block2015-04-29 08:23:12.189 blocktest[10816:303] test in block2015-04-29 08:23:12.189 blocktest[10816:303] test in blockProgram ended with exit code: 0


结果外部和内部的都是一样的,说明传入给block中的是对象的指针,指向的是同一个地址。既然传入的是同一个地址,那么说明这个对象指针

其实是没有变的,所以,其实不需要__block也可以的:


#import <Foundation/Foundation.h>#import "TestObject.h" int main(int argc, const char * argv[]){    @autoreleasepool {        TestObject *obj = [[[TestObject alloc] init] autorelease];        obj.name = @"XCoder";         NSString * (^Name)(TestObject *) = ^(TestObject * myObj) {            myObj.name = @"XCoder Studio";            return myObj.name;        };         NSLog(@" In Block:%@", Name(obj));        NSLog(@"Out Block:%@", obj.name);    }    return 0;}



这样运行结果也是正确的!同样能得到上面的结果。


然而,如果我指针重新指向一个新的TestObject对象呢?

#import <Foundation/Foundation.h>#import "TestObject.h"typedef int(^Sum)(int, int);int main(int argc, const char * argv[]){    @autoreleasepool {                // insert code here...        //NSLog(@"Hello, World!");        //        int n = 1;//        //        Sum sum = ^(int a, int b)//        {//            //n = 2;//            //            NSLog(@"n = %d", n);//            //            return (a+b) * n;//        };//        //        NSLog(@"n = %d, result = %d", n, sum(5, 6));                TestObject *obj = [[TestObject alloc] init];                obj.name = @"test out block";                NSString* (^Name)(TestObject *obj) = ^(TestObject *obj)        {            obj = [[TestObject alloc] init];                        obj.name = @"test in block";                        return obj.name;        };                NSLog(@"%@", obj.name);        NSLog(@"%@", Name(obj));        NSLog(@"%@", obj.name);    }    return 0;}



我更改了指针指向,没有__block修饰,同样可以正常运行,不过运行结果不同:


2015-04-29 08:29:23.726 blocktest[10855:303] test out block2015-04-29 08:29:23.726 blocktest[10855:303] test in block2015-04-29 08:29:23.727 blocktest[10855:303] test out blockProgram ended with exit code: 0

由于block里面重新申请了内存,所以此时已经不指向同一个地址了,当然无法改变外部obj.name的值。


总的说明一点儿,__block修饰符只是针对基本数据类型,对于对象类型就无法适用!


结尾补充一张块的表示图,简单理解块就是C语言中的回调函数。






0 0