第一、综述
block是OC中另外一种对象和对象的通信方式,是一对一的关系,类似于delegate,而通知时一对多的关系
第二、定义block类型
int (^myBlock)(int)
第三、block的声明
mylock=^(int a)
{
int result =a*a;
return result;
}
第四、block的调用
block(20);
code sample如下所示:
<span style="font-family:Microsoft YaHei;font-size:18px;">int(^myBlock)(int);
myBlock=^(int a){
NSLog(@"%d",a);
return 0;
};
myBlock(20);
</span>
<span style="font-family:Microsoft YaHei;font-size:18px;"> void (^myBlcoks)(void);
myBlcoks=^(void)
{
NSLog(@"in blocks");
};
NSLog(@"before block");
myBlcoks();
NSLog(@"after block");
</span>
第五、另外一种声明方法
sample1:
typedef int(^MyBlock)(int);
MyBlock myblock=^(int a)
{
NSLog(@"%d",a);
return 30;
};
myblock(30);
sample2:
typedef void (^MYBlcoks)(void);
MYBlcoks myBlcoks=^(void)
{
NSLog(@"in blocks");
};
NSLog(@"before block");
myBlcoks();
NSLog(@"after block");
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//define block defination
NSLog(@"before");
MyBlock myblock=^(int a)
{
NSLog(@"%d",a);
return 30;
};
[self testBlock:myblock];
}
-(void)testBlock:(MyBlock)myblock
{
myblock(10);
}
第七、block和变量
局部变量:
在block中,会把局部变量当成常量变量
int num=10;
int num=30;
MyBlock myblock=^(int a)
{
num=20; //此处会报错
NSLog(@"%d",a);
return 30;
};
原因:block代码块不会在写的地方执行,是在其他地方调用时才会执行,局部变量在跳出此作用域时销毁,所以block代码块会将局部变量当成一个常量变量来处理,要修改前面加__block
__block 型态变数
我们可以藉由将一个由外部汇入block的变数放上修饰词__block来让这个变数由唯读变成可以读和写,不过有一个限制就是传入的变数在记忆体中必须是一个占有固定长度记忆体的变数,__block修饰词无法使用于像是变动长度的阵列这类不定长度的变数。
<span style="font-family:Microsoft YaHei;font-size:18px;"> __block int num=10;
MyBlock myblock=^(int a)
{
NSLog(@"before the val of num is %d",num);
num++;
return 30;
};
num=30;
[self testBlock:myblock];
NSLog(@"after the val of num is %d",num);
</span>
输出结果是:
2013-10-28 15:38:24.602 blockDemo[1541:70b] before the val of num is 30
2013-10-28 15:38:24.603 blockDemo[1541:70b] after the val of num is 31
Block作为变量传递
第一、当用typedef声明block后,及声明了一种变量类型,这种类型是无函数名的指针,那么就可以看做不同的变量,用于函数间的传递
myBlock myblock=^(int a)
{
NSLog(@"参数 %d",a);
return 10;
};
[self testBlock:myblock];
函数:
-(void) testBlock:(myBlock)blockObj
{
blockObj(20);
}
第二、局部变量在block函数中被编译为不可变变量,所以下面代码是有问题的
int number=20;
myBlock myblock=^(int a)
{
number=30;
NSLog(@"参数 %d",number);
return 10;
};
如果想修改,应该在命名前加__block
__block int number=20;
myBlock myblock=^(int a)
{
number++;
NSLog(@"参数 %d",number);
return 10;
};
number=10;
myblock(10);
NSLog(@"参数 %d",number);
结果:
2013-12-25 20:29:52.773>参数 11
2013-12-25 20:29:52.774>参数 11
说明:添加了__block后,block里的函数变量number变量int number=20;
myBlock myblock=^(int a)
{
NSLog(@"参数 %d",number);
return 10;
};
number=10;
myblock(10);
NSLog(@"参数 %d",number);
结果:
参数 20
参数 10
由此可见,不添加__block时block函数内的变量和函数外的变量不是同一块内存
int num=10;
void (^blk)(void)=^{
NSLog(@"%d",num);
};
num=20;
blk();
输出值为10代码的编译过程是自上而下,所以在编译极端是blk函数打包进去的num值为10,当正式执行的时候,虽然num=20,但是blk编译打包时num=10,所以输出值为10.
第一、block本身可以copy和release
两种copy的方式:
【_block copy】;
Block_copy(_block);
两种release的方式:
【_block release】;
Block_release(_block);
第二、block创建后内存是分配在栈上,调用copy方法,会将block从栈移到堆上.
当block声明为全局变量时,我们应该调用block的copy方法。
第三、在拥有参考计数(reference-counted)的环境中,若我们在block中参考到Objective-C的物件,在一般的情况下它将会自动增加物件的参考计数,不过若以__block为修饰词的物件,参考计数则是不受影响。
l 若直接存取实体变数(instance variable),self的参考计数将被加1。
l 若透过变数存取实体变数的值,则只变数的参考计数将被加1。
第四、block的应用
@class blockButton;
typedef void(^TouchBlock)(blockButton*);
@interface blockButton : UIButton
@property(nonatomic,copy)TouchBlock block;
@end
定义一个TouchBlock,返回类型是void,输入参数是blockButton
.m文件的实现如下所示:
@implementation blockButton
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self addTarget:self action:@selector(clickAction) forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
-(void)clickAction
{
self.block(self);
}
添加点击事件,调用自身block(别忘了block是个函数)
blockButton *button=[[blockButton alloc]initWithFrame:CGRectMake(20, 40, 100, 20)];
button.backgroundColor=[UIColor blueColor];
[button setTitle:@"按钮" forState:UIControlStateNormal];
button.block=^(blockButton *btn)
{
NSLog(@"the button has been tapped");
};
[self.window addSubview:button];
[button release];
给button的block赋值,当点击时调用此函数,实现回调
-(id)loadNibWithClassName:(NSString*)classname
{
Class class = NSClassFromString(classname);
NSArray *objects = [[NSBundle mainBundle] loadNibNamed:classname owner:nil options:nil];
int index = [objects indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
return [obj isKindOfClass:class];
}];
assert(index != NSNotFound);
return [objects objectAtIndex:index];
}
上述函数根据nib创建一个class,在函数中内联了block函数,遍历objets,判断其是不是是创建好的类,将不是class的过滤掉