__block修饰符的作用域问题

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







我们知道,当在一个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 = 1
2015-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 = 1
2015-04-29 08:23:12.188 blocktest[10816:303] n = 1, result = 11
2015-04-29 08:23:12.188 blocktest[10816:303] test out block
2015-04-29 08:23:12.189 blocktest[10816:303] test in block
2015-04-29 08:23:12.189 blocktest[10816:303] test in block
Program 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 block
2015-04-29 08:29:23.726 blocktest[10855:303] test in block
2015-04-29 08:29:23.727 blocktest[10855:303] test out block
Program ended with exit code: 0

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


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


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






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值