Block是将函数
及其执行上下文
封装起来的对象
。能够保存一段代码,在须要的时候调用。javascript
格式为: 返回值类型(^Block名字)(参数列表);
如:java
// 无参无返回
void (^aBlock)(void);
// 无参有返回
int(^aBlock)(void) ;
// 有参有返回
NSString* (^aBlock)(NSString * x, int y);
// 无参有返回
NSString* (^aBlock)(void);
复制代码
@property(nonatomic,copy)NSString* (^ablock)(void);
复制代码
typedef void (^Block)(void);
typedef int (^MyBlock)(int a, int b);
typedef void(^ConfirmBlock)(BOOL isOK);
typedef NSString *(^AlertBlock)(NSInteger alertTag);
复制代码
赋值格式为: Block变量名 = ^返回类型(参数列表){ 函数体 };
如:程序员
// 无参无返回
self.aBlock = ^{
NSLog(@"... ...");
};
// 无参有返回
self.ablock = ^NSString *{
NSLog(@"dd");
return @"dd";
};
// 有参有返回
self.ablock = ^NSString *(int a) {
return @"vv";
};
// 有参无返回
self.aBlock = ^(NSString *x, int y){
NSLog(@"mmm");
};
复制代码
block由其所属的类对象调用,指明要作什么。block中包含的是一段代码,含义是执行一些操做,具体什么操做,至关于给属性赋值,只是这里给block赋一段代码。markdown
由其所属的类对象调用。相似方法调用 如:网络
//无返回
self.ablock();
//有返回
NSString *result = self.ablock(2);
复制代码
在处理异步问题的时候,例如HTTP请求,有点像javascript
的回调,在获得回复的时候更新主线程,而不会占用主线程,比Delegate
逻辑好看多了;或者,当你要返回多个值又懒得建立一个类的时候。数据结构
#####1.传递数据(把数据传递出去、逆传)异步
@interface PDMineVC : PDViewController
@property(nonatomic,copy)void (^rebackBlock)(NSString *flag);
@end
复制代码
// 调用,把须要传递的信息 做为参数
self.rebackBlock(@"425");
复制代码
类对象定义本身的block属性。函数
PDMineVC *vc = [[PDMineVC alloc] init];
vc.rebackBlock = ^(NSString *flag) {
NSLog(@"--%@",flag);
};
[self.navigationController pushViewController:vc animated:YES];
复制代码
有两种方式:值传递、指针传递oop
在声明Block以后、调用Block以前,对局部变量进行修改。调用Block后,局部变量值不变。atom
int temp = 100;
// 声明Block
void(^myBlock)() = ^{
NSLog(@"global = %d", temp);
};
temp = 101; // 修改变量的值
// 调用Block
myBlock();
// 调用后输出"temp = 100"
复制代码
解释:声明Block的时候,只是把变量的值
保存进Block代码块中,因此调用Block时,打印的仍然是变量原来的值。
引用block 外的变量,block 默认是将变量的
值
复制到其数据结构中来实现访问的。
对于上一种状况,只需用__block
修饰变量便可,只要变量值改变,值就跟着改变。
__block int temp = 100;
复制代码
解释:对于用 __block 修饰的外部变量引用,block 是复制其引用地址
来实现访问的。
注意:
不能够在Block中修改局部变量; 全局变量、static
静态变量,在Block中的值也会随修改而变。
#####3.保存一段代码 在本类中定义Block,本类对象在另外一个类中调用Block。
#####4.block做为函数的参数 把block当成方法的参数使用 在外界写block的声明,在方法内部调用block。 例子
方法的声明
+(void)checkNetworkStatusOn:(void (^)(NSString * status))CallBack;
方法的定义
+(void)checkNetworkStatusOn:(void (^)(NSString * status))CallBack{
// ...
// blcok调用,传递信息
CallBack ? CallBack(@"网络处于断开状态") : nil;
}
方法的调用,并声明Block
[self checkNetworkStatusOn:^(NSString *status) {
NSLog(@"---->%@",status);
}];
复制代码
// 定义带参的block类型,本类对象调用,参数来自本类对象
typedef void(^selectedHandler)(NSUInteger index,NSString *title);
// 声明方法,block做为参数
- (instancetype)initWithFrame:(CGRect)frame
titles:(NSArray *)titles
selectedHandler:(selectedHandler)handler;
- (instancetype)initWithFrame:(CGRect)frame titles:(NSArray *)titles selectedHandler:(selectedHandler)handler {
if ( [super initWithFrame:frame]) {
self.ablock = handler ; // 外界传入代码块,外界来决定作什么
}
return self;
}
复制代码
复制代码
若是对Block进行一次copy操做,那么Block的内存会被移动到堆
中,这时须要开发人员对其进行内存管理。
在Block存储在堆中时,若是在Block中引用了外面的对象,会该对象进行一次retain
操做。即便在Block自身调用了release
操做以后,不会release
该对象,这时会形成内存泄漏。
Person *pObject = [[Person alloc] init];
void(^myBlock)() = ^{
NSLog(@"------%@", pObject);
};
myBlock();
Block_copy(myBlock); // copy操做
// ...
Block_release(myBlock);
[pObject release];
// -->Person对象在这里没法正常被释放,由于其在Block中被进行了一次retain操做。
复制代码
为了避免对所引用的对象进行一次retain
操做,可使用__block
来修饰对象
__block Person *pObject = [[Person alloc] init];
复制代码
若是对象内部有一个Block属性,而在Block内部又访问了该对象,那么会形成循环引用。 解决:
__block
修饰在对象的前面使用__block
来修饰,以免Block对对象进行retain
操做。 __block Person *p = [[Person alloc] init];
新建立一个弱指针来指向该对象,并将该弱指针放在Block中使用,这样Block便不会形成循环引用。
__weak typeof(Person) weakP = p;
void(^myBlock)() = ^{
NSLog(@"------%@", weakP);
};
复制代码
这样虽然解决了循环引用,可是也容易涉及到另外一个问题: 由于Block是经过弱引用指向了Person对象,那么有可能在调用Block以前,Person对象已经被释放。因此咱们须要在Block内部
再定义一个强指针
来指向Person对象。
__weak typeof(Person) wp = p;
aBlock = ^(NSString *flag) {
__strong typeof(Person) sp = wp;
NSLog(@"%@", sp);
};
复制代码
补充:
在ARC默认状况下,Block的内存存储在堆中,ARC会自动进行内存管理,程序员只须要避免循环引用便可。 在Block内部定义的变量,会在做用域结束时自动释放,Block对其并无强引用关系,且在ARC中只须要避免循环引用便可,若是只是Block单方面地对外部变量进行强引用,并不会形成内存泄漏。
www.jianshu.com/p/14efa33b3… * www.jianshu.com/p/649fca982… www.jianshu.com/p/45557fbef… www.jianshu.com/p/c389afedb… *