使用block语法
1 block块的感性认识
块这种语法,在其他语言中叫做闭,把一定的变量关闭到一定的作用域之内。
块可以帮助开发者封装了指令,病切内联在其他代码里,用于获取作用域的值,产生的结果对象与其他对象一样,可以进行复制,也可以进行值传递
块的奇妙之处,可以块取得外面的作用域的变量的值。通常没必要将所有的参数都打包在一个参数列表里面,可以只是简单设定作用域,使用里面的变量就可以。
2 block语法
int captured =1
int (^offsetter)(int) = ^(int x){return x + captured ;} ;
第一行创建一个本地变量captured
第二行 声明一个命名为offsetter的变量,同时也是一个块,创建或者定义一个块使用^,这个块返回一个整数值,并使用一个整形的参数。
在右边,进行块的定义使用(^符号
),看起来有些类似C函数的定义:指定参数X,括号里面是块体。
注意:
其一,并没有指明块返回的类型,但编译其能根据返回语句进行判断;
其二,在块内部引用了变量captured。说此处获取的captured变量在块内部的值。这就是块的强大特性之一。
3 调用block
int answer = offsetter(2)
注意这时返回值是3(2+1=3)如果改变captured的值后在才调用 会怎么样呢?
captured =64
answer =offsetter(2)
这是返回值还是 3
,这是因为captured的值只在定义块是获取,不能在块的外面改变captured的值反作用域块内部,当然也不能在块的内部改变captured的值,为了实现在块内部改变变脸的值,需要使用__block的类型指定语句。
-(void) testBlock {
int captured =1 ;
int (^offsetter)(int) = ^(int x) {return x + captured ; } ;
NSLog(@" %d" , offsetter(2)) ;
captured = 64 ;
NSLog(@" %d" , offsetter(2)) ;
}
-(void) testModifyBlock {
__block int captured = 1 ; //这样可以修改了,获得最近的修改值
NSLog(@"[testModifyBlock] captured= %d" , captured) ;
int (^offsetter)(void) = ^(void) { captured =2 ; return 1 ;} ;
offsetter() ;
NSLog(@"[testModifyBlock] captured= %d" , captured) ;
}
4 block 与 self和属性
//.h
@property (nonatomic , copy) NSString *stringProperty ;
//.m
void (^correctBlockObject)(id) = ^(id self) {
NSLog(@"self =%@" , self) ;
//直接读写取属性都是错误的 ,要通过setter、getter函数
// self.stringProperty = @"hello world"; //编译错误
[self setStringProperty:@"hello world"] ;
NSLog(@"self.self.stringProperty =%@" , [self stringProperty]) ;
} ;
5 block 与 强引用
NSString* aString = [NSString stringWithFormat:@"One = %i", 1];
void(^MyBlock)(void) = ^(void)
{
NSLog(@"The string is %@", aString);
};
aString = nil;
aString is still in memory, because MyBlock is keeping it around!
6 block与若引用
NSString* aString = [NSString stringWithFormat:@"One = %i", 1];
__weak NSString* weakString = aString;
void(^MyBlock)(void) = ^(void)
{
NSLog(@"The string is %@", weakString);
};
aString = nil;
aString is no longer in memory, and calling MyBlock will print The string is (null)”
7 防止循环引用
typedef void(^CallbackBlock)(void);
@interface Monster : NSObject
@property (copy) CallbackBlock onDeathBlock;
@property (copy) CallbackBlock onHitBlock;
@end
void(^MyBlock)(void) = ^(void) {
NSLog(@"I am %@", self); // block now retains self
};
self.aBlock = MyBlock; // self now retains block; retain cycle! 
__weak id weakSelf = self;
void(^MyBlock)(void) = ^(void) {
NSLog(@"I am %@", weakSelf); // block does NOT retain self
};
self.aBlock = MyBlock; // self now retains block; no retain cycle
8 使用block的场景
- 在异步操作完成,要调用的代码
- 处理异步调用的错误。
- 处理异步的通知
- 为迭代器(sort,enumeration..) 使用lambda函数,
- UIView动画和转换
9 其他形式的写法
//另外的一种写法
void(^MyBlock)(void);
MyBlock = ^(void) {
NSLog(@"Hello from the block!");
};
MyBlock();
//例子
typedef void(^ExampleBlock)(void);
ExampleBlock myBlock = ^(void) { NSLog(@"i SPILL my DRINK!");};
//例子
typedef BOOL(^ParameterBlock)(NSString* string, int number);
ParameterBlock paramBlock = ^(NSString* string, int number)
{
NSLog(@"I received a string %@, and a number %i!", string, number);
return YES;
};
paramBlock(@"Hello", 1337);
//没有参数
void(^ExampleBlock)(void);
ExampleBlock aBlock = ^{
NSLog(@"Whoa!");
};