Block
2016-05-07 本文已影响262人
闲得一B
inlineBlock:快速生成block代码
block其实就是一个对象:苹果文档有解释。
使用clang指令
clang -rewrite-objc main.m
得到一个cpp文件
你定义完block之后,其实是创建了一个函数,在创建结构体的时候把函数的指针一起传给了block,所以之后可以拿出来调用。
结论:
block在MRC下使用copy,在ARC下使用strong和copy一样,尽量用strong。
>
block修饰的变量存放的位置:
在MRC和ARC下:
block没有使用局部变量或者static修饰的局部变量时,block会存放在全局区。
在MRC下:
block中使用局部变量时或__block修饰的局部变量时,block会存放在栈里面。
__block修饰的局部变量不会改变属性的生命周期。
在ARC下:
block中使用局部变量时,block会存放在“堆”里面
__NSMallocBlock__堆
__NSGlobalBlock__全局
__NSStackBlock__栈
int b;//全局变量
static int f = 0;//被static修饰的全局变量,作用域会修改,只能在当前文件下使用。
-(void)ViewLoad{
int a;//局部变量
__block int d;//局部变量
static int c;//被static修饰的局部变量,延长生命周期,跟整个应用程序有关,被static修饰的局部变量,只会分配一次内存,被static修饰的局部变量,程序一运行就会给static修饰的变量分配内存。
}
MRC补充:
MRC下没有strong和weak。有assign,retain,copy。
MRC下使用copy才会将block放在堆里面,并且要使用self来访问,
而不要使用下划线来访问。如果使用retain修饰的block会放在栈里面,会自动销毁。
MRC下没有强指针,默认一个对象就是基本类型。
MRC 下:
block引用局部变量,block放在栈区(和局部变量的位置一样)。
block没有使用局部变量(static修饰的局部变量时,变量生命周期延长和app一样)(因为MRC下没有强弱指针,都是基本数据类型,所以都放栈里保存),block放在全局区。
ARC下:
局部变量默认都是强指针,所以block只要引用了局部变量,block放在堆里面。
block声明、定义、取别名
// block声明:返回值(^Block变量名)(block参数类型),参数变量名可以省略
void(^block)();
void(^block1)(int);
>
// block定义: 等号右边 ^(参数类型 参数变量名){};
void(^block2)(int a) = ^(int a){
>
};
>
// block定义二: 等号右边 ^返回值(参数类型 参数变量名){};,返回值可以省略,但是也有不省略
int(^block3)(int a) = ^int(int a){
return 2;
};
>
// block定义三: 当没有返回值,没有参数,可以省略
void(^block4)() = ^{
>
};
>
block用Strong
block声明成属性
方式一:
@proprty (nonatomic, strong) void(^myBlock)();
给block取别名 typedef void(^myBlock)();
方式二@proprty (nonatomic, strong) myBlock;
传值:
逆传:代理,block,通知。
代理用weak
block用strong
通知需要先监听,最后记得移除观察者
iOS中通过代理,通知,KVO,addTarget都能实现监听
区分MRC和ARC:
ARC下不能调用[super dealloc];
MRC下能调用release、retain、retainCount。
内存5个区:堆、栈、方法区、常量区、全局区。
MRC下:
堆:需要手动管理。
栈:自动管理,代码块一过,就会自动释放。
在MRC下:
block中使用局部变量时或__block修饰的局部变量时,block会存放在栈里面。__block修饰的局部变量不会改变属性的生命周期。
block没有使用局部变量或者static修饰的局部变量时,block会存放在全局区。
在ARC下:
block中使用局部变量时,block会存放在“堆”里面
block没有使用局部变量或者static修饰的局部变量时,block会存放在全局区。
ARC管理原则:默认一个局部变量对象,都是强指针,存放堆里面。
ARC下如果一个对象没有强指针指向,就会销毁。
MRC下没有强指针,存放在栈里面。
循环引用:
ARC管理原则:默认一个局部变量对象,都是强指针,存放堆里面。
block会对外部的强指针进行强引用,不会对外部的弱指针强引用。
在block外部声明weakSelf弱指针:
使用__weak typeof(self) weakSelf = self;
>
block中异步回主线程更新UI
延迟操作或者异步任务,才需要用strongSelf,让block成为强指针,防止销毁
在block内部用__strong typeof(weakSelf) strongSelf = weakSelf;
block用__strongSelf.png
block值传递
默认block访问外部局部变量没有被任何关键字修饰的变量,都是值传递。
block访问外部变量被__block,static修饰的都是指针传递。
访问的全局变量也是指针传递。
值传递(block内部和外部都是两个不同地址,变量互不影响)
指针传递(block内部和外部都是同一个地址,一方影响另一方)
block当参数
封装一个功能时,当这个功能所做的事情,
由外界决定,而什么时候调用用内部决定,
这时候就需要把block充当参数去使用。
>
苹果内部的block:
相当于苹果内部定义了一个block属性,
并且已经在内部某个地方调用了,
而我们则是在外部写block里面要做的事。
当block结合其他参数使用时,block建议放到最后。
比如AFN,AFN内部自定义了`有请求头参数`和`带参数的block`组成的方法,
当把`请求头参数`传递过去,先发送请求执行这个`请求头参数`,
获取到结果,将结果给`带参数的block`的参数。
当我们在外部写`带参数的block`中的代码时,
其实`带参数的block`的参数已经有值了,
这时候这些值要做什么事情就由我们来决定。
示例:
在Person中有一个带有blok为参数的方法。
这里的block:想要做的事情由以后决定(给ImageView设置图片)。
外界调用此方法,通过传递URL地址,方法内部通过发送请求获取到图片,将这个图片当做block的参数,外界通过block的参数直接就可以获取到这个图片,给ImageView设置图片。(其实还可以理解为,一个方法能通过block返回多个值,只需设置多个参数就可实现)
Person.h
#import <UIKit/UIKit.h>
typedef void(^urlBlock)(UIImage *);
@interface Person : NSObject
+(void)PersonWithURL:(NSString *)url TestBlock:(urlBlock) urlBlcok;
@end
Person.m
#import "Person.h"
@implementation Person
+(void)PersonWithURL:(NSString *)str TestBlock:(urlBlock)urlBlcok
{
//处理url,例如发送网络请求
//注意:耗时操作尽量放到子线程中,这里没有放到子线程
NSURL *url = [NSURL URLWithString:str];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
//将请求后的数据当参数传递给urlBlock
urlBlcok(image);
}
@end
ViewController.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end
ViewController.m
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100, 100, 200, 200)];
[self.view addSubview:imageView];
[Person PersonWithURL:@"http://cdn.duitang.com/uploads/item/201411/16/20141116223619_CeWfT.thumb.700_0.jpeg" TestBlock:^(UIImage *image) {
imageView.image =image;
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
Person.h.png
Person.m.png
ViewController.h.png
ViewController.m.png
效果图.png
block有参数有返回值
有参数能将现在的的值通过参数传递出去,供外部使用。
返回值能将外部获取到参数计算的结果或者其他计算的结果传递进来,供内部使用。
block充当参数实现逆向传值
其实就是在上面的例子中将这个没有返回值的block改为由返回值的block。
那么Person.m中的
····································
//将请求后的数据当参数传递给urlBlock
urlBlcok(image);
····································
这句话就有值返回值了。
而在ViewController.m中
对图片操作完之后就能有返回值,就实现了所谓的block的`逆向传值了`。
block充当返回值能实现链式编程。
- (void)viewDidLoad {
[super viewDidLoad];
self.test();
} - (void(^)())test
{
return ^{
};
}
![普通链式编程.png](http:https://img.haomeiwen.com/i1170347/8d9e7b264be8cfd5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
![block链式编程.png](http:https://img.haomeiwen.com/i1170347/a6a9c2bca338745f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)