块总能修改实例变量
之前的文章中写了块可以截获当前环境中的局部变量,如果想要修改就要使用 __block 说明符。
但是针对类实例方法中的块,可以直接修改实例变量。
Worker.h
#import <Foundation/Foundation.h>
@interface Worker : NSObject
{
NSString * _wId;
}
-(id)initWihtId:(NSString *)wId;
-(void)changeId;
-(void)printfWorkerId;
@end
Worker.m
#import "Worker.h"
@implementation Worker
-(id)initWihtId:(NSString *)wId
{
self = [super init];
if (self) {
_wId = wId;
}
return self;
}
//将工号统一归零
-(void)changeId
{
void(^aBlock)() = ^{
_wId = @"0";
};
aBlock();
}
-(void)printfWorkerId
{
NSLog(@"the current Id is %@",_wId);
}
@end
main.m
#import <Foundation/Foundation.h>
#import "Worker.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
Worker *worker = [[Worker alloc]initWihtId:@"2015032801"];
[worker printfWorkerId];
[worker changeId];
[worker printfWorkerId];
}
return 0;
}
打印结果:
2015-03-28 08:10:58.820 Block_Demo[638:22232] the current Id is 2015032801
2015-03-28 08:10:58.821 Block_Demo[638:22232] the current Id is 0
Program ended with exit code: 0
注意事项:
这时候实例变量中的块同时捕捉到了self引用,此时相当于block持用self,若此时对象也持有block,则会造成保留环。
块截获的局部变量保存的是他们的指针
block截获的实例变量结构体中保存的都是他们的指针。
栈块、全局块、堆块
定义块的时候,他是分配在栈上的,也就是说,块只是在定义它的那个范围内有效。
实际使用中可能会写下这样的代码:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
printf("please input a number:\n");
int i;
scanf("%d",&i);
void(^aBlock)();
if (i==0) {
aBlock = ^{
NSLog(@"you type 0");
};
}else{
aBlock = ^{
NSLog(@"what fuck you type");
};
}
aBlock();
}
return 0;
}
输出:
please input a number:
77
2015-03-28 08:28:26.175 Block_Demo[680:26203] what fuck you type
Program ended with exit code: 0
这时候块可能由于执行范围结束,被销毁,从而输出错误结果。那么来实现一个安全的;
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
printf("please input a number:\n");
int i;
scanf("%d",&i);
void(^aBlock)();
if (i==0) {
aBlock = [^{
NSLog(@"you type 0");
}copy];
}else{
aBlock = [^{
NSLog(@"what fuck you type");
}copy];
}
aBlock();
//此时块被复制到堆中,只要不被手动释放,则可以随时引用,只有在第一次copy的时候执行复制到堆中的操作,此后的均为引用计数+1,ARC环境下内存自动管理引用计数。MRC下需要手动release。
}
return 0;
}
我们实现了栈块和堆块。
现实场景中我们还会经常一种全局块,也就是全局变量。
#import <Foundation/Foundation.h>
void(^block)() = ^{NSLog(@"这里实现一些编译期间确定的内容,相当于一个单例对象");};
int main(int argc, const char * argv[]) {
@autoreleasepool {
block();
//对全局块的copy操作时一个空操作。可以使用全局变量并进行修改。
}
return 0;
}