美文网首页
ios中block的基本了解和使用

ios中block的基本了解和使用

作者: Arthur澪 | 来源:发表于2017-12-06 22:21 被阅读0次

简介

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

声明

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

// 无参无返回
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赋一段代码。

调用

由其所属的类对象调用。类似方法调用
如:

//无返回
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.捕获变量

有两种方式:值传递、指针传递

  • 值传递的情况
    在声明Block之后、调用Block之前,对局部变量进行修改。调用Block后,局部变量值不变。
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单方面地对外部变量进行强引用,并不会造成内存泄漏。

相关资料

http://www.jianshu.com/p/14efa33b3562 *
http://www.jianshu.com/p/649fca982c6e
http://www.jianshu.com/p/45557fbef2bf
https://www.jianshu.com/p/c389afedbce6 *

相关文章

网友评论

      本文标题:ios中block的基本了解和使用

      本文链接:https://www.haomeiwen.com/subject/elwuhxtx.html