~~~~我的生活,我的点点滴滴!!
我们知道,当在一个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语言中的回调函数。