ios中block的基本了解和使用

简介

Block是将函数及其执行上下文封装起来的对象。能够保存一段代码,在须要的时候调用。javascript

声明

格式为: 返回值类型(^Block名字)(参数列表); 如:java

// 无参无返回
void (^aBlock)(void);

// 无参有返回
int(^aBlock)(void) ;

// 有参有返回
NSString* (^aBlock)(NSString * x, int y);

// 无参有返回
NSString* (^aBlock)(void);
复制代码
  • block属性,使用copy修饰,最好不用strong。
@property(nonatomic,copy)NSString* (^ablock)(void);
复制代码
  • 自定义Block类型
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.传递数据(把数据传递出去、逆传)异步

  • 在本身的.h中,声明带参数的block属性。
@interface PDMineVC : PDViewController

@property(nonatomic,copy)void (^rebackBlock)(NSString *flag);

@end
复制代码
  • 在.m中,调用block。
// 调用,把须要传递的信息 做为参数
self.rebackBlock(@"425");
复制代码
  • 在外界

类对象定义本身的block属性。函数

PDMineVC *vc = [[PDMineVC alloc] init];
vc.rebackBlock = ^(NSString *flag) {
    NSLog(@"--%@",flag);
};
[self.navigationController pushViewController:vc animated:YES];
复制代码
2.捕获变量

有两种方式:值传递、指针传递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;
}

复制代码
5.block做为函数的返回值(少用)
复制代码

block内存管理

若是对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来修饰,以免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… *

相关文章
相关标签/搜索