美文网首页IOS收藏
从应用的角度看block(待续)

从应用的角度看block(待续)

作者: 一声雷 | 来源:发表于2016-02-12 16:39 被阅读47次

一、什么是block?

按照苹果官方文档的说法,block是一个oc对象。(原文:Blocks are Objective-C objects, which means they can be added to collections like NSArray or NSDictionary. )其实,本质就是一个函数。
当然,block也可以理解成oc的一种数据类型,我个人认为把block理解成一种数据类型更便于我们理解和记忆。下面我就从这个角度详细介绍block。

二、block的介绍

我们在定义一个变量的时候,都包含了以下三个步骤:
1、确定这个变量的数据类型
2、声明变量
3、定义变量

// 1.比如确定这个数据是 int 类型
int  value ;         // 2.声明
value = 15 ;         // 3.定义


// 当然,也可以声明的同时进行定义
int value = 15 ;

从代码中认识block

例如:
//   1.一个有参数有返回值的block类型:int (^) (int ,int)
int (^block1) (int ,int);           // 2.block的声明
block1 = ^int(int n1,int n2){       // 3.block的定义
    int  sum = n1 + n2;
    return  sum;
}
block1(10,20);                      // 4.block的调用


// 当然,也可以声明的同时进行定义
void(^block2)(int) = ^(int a){ 
           NSLog(@"你输入的值是:%d",a );    
     };
block2(999);
// 我们可以看出block2的类型是:void(^)(int)

1.block的类型

格式:返回值类型(^)(block参数类型)
block的类型大致可以分为四种:
a: 无参数,无返回值
b: 无参数,有返回值
c: 有参数,无返回值
d: 有参数,有返回值

2.block的声明

格式:**返回值类型(^Block变量名)(block参数类型 参数变量名) **

int (^block11)(int a,int b);
int (^block22)(int,int);             // 注意:参数变量名可以省略

3.block的定义

格式:^返回值类型(参数类型 参数变量名) { // 代码块 } ;

// 注意1:声明的时候参数的变量名可以省略,当定义是参数的变量名一定不能省略
  void(^block111)(int) = ^void(int a) {           
    };
  int(^block222)(int) = ^int(int a) { 
       return 2;   
    };  
// 注意2:返回值的类型是可以省略的
   void(^block111)(int a) = ^(int a) {           
  };
  int(^block222)(int a) = ^(int a) { 
       return 2;   
   };  
 
// 注意3: 当没有返回值,没有参数时,可以省略括号
    void(^block333)() = ^{       
    };

4.block的调用

格式:block变量名(参数);

5.如何声明一个block属性

方式一:

@interface ViewController ()
@property (nonatomic, strong) void(^block)();         // 方式一
@end

方式二:

typedef  void(^BlockType)();           // BlockType:block类型别名
@interface ViewController ()
@property (nonatomic, assign) BlockType block1;      // 方式二
@end

三、block的内存管理

我们都知道内存是可以划分成堆,栈,方法区,常量区,全局区5个区。而block是可能被存放在以下三个区中的任意一个中。

1.在全局静态区:_NSConcreteGlobalBlock
2.在栈中:_NSConcreteStackBlock
3.在堆中:_NSConcreteMallocBlock

MRC中:
1.如果block没有访问外部的局部变量或者局部变量被static修饰,block默认存放在"全局区"
2.如果block访问外部的局部变量,block存放在"栈"里面

  MRC:不能使用retain声明block,依然放在栈里面,会自动销毁.
  MRC:使用copy声明block,才会放在堆里面.

ARC如何管理Block:
1.如果block没有访问外部的局部变量或者局部变量被static修饰,block默认存放在"全局区"
2.如果block访问外部的局部变量,block存放在"堆"里面

  ARC:使用strong声明block,不要使用weak.

四、block的循环引用问题

------------“你强我就强,你弱我就弱”------------

在block的内部访问了一个对象:
1.如果这个对象本来就有强指针指着,那么这个block也会强引用这个对象;
2.如果这个对象只有弱指针引着,那么这个block就不会对这个对象进行强引用。

Person类:



#import <Foundation/Foundation.h>

@interface Person : NSObject
@property(nonatomic,strong)NSString *name;  // 姓名
@property(nonatomic,assign)int age;         // 年龄
@property(nonatomic,assign)int height;      // 体重
// 声明block
@property(nonatomic,strong) void(^block)();
- (void)eat;
@end

@implementation Person
- (void)eat
{
    self.height += 1 ;
    _block = ^{
          // 在block的内部访问了自身这个对象。
        NSLog(@"吃完饭后的体重是:%d",self.height);
    };
    _block();
}
@end

Person类外部使用:

// 这时候,p1这个强指针引着Person对象。
Person *p1 = [[Person alloc] init];
// eat内部调用block时,block就会强引用这person对象;
// 而本身person对象内部就强引着block。
[p1 eat];
// person对象和block两者互相强引着,谁也不能释放。

解决方案:



- (void)eat
{
    self.height += 1 ;
    //声明weakSelf弱指针(解决方案)
    __weak typeof(self) weakSelf = self;
    _block = ^{
        NSLog(@"吃完饭后的体重是:%d",weakSelf.height);
    };
    _block();
}

更为复杂的情况:🏁 延迟操作或者异步任务 🏁


- (void)viewDidLoad 
    // 声明weakSelf弱指针   
 __weak typeof(self) weakSelf = self;       
_block = ^{
            
           //因为这里如果不用强指针的话,延时后,可能访问的这个对象就会销毁了,那么这个block的内部就没办法访问这个对象了
           //这样用强指针引着,就保证了只要block还在,那么这个对象就不会销毁
            __strong typeof(weakSelf) strongSelf = weakSelf; 
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                      NSLog(@"%@",strongSelf);                
                     });           
          };      

 _block();
   
}

相关文章

  • 从应用的角度看block(待续)

    一、什么是block? 按照苹果官方文档的说法,block是一个oc对象。(原文:Blocks are Objec...

  • 从应用角度看ReativeX

    这篇从我个人的角度聊聊ReactiveX这种思想的应用场景。 首先不论MVVM的使用场景,我也没有特别丰富的MVV...

  • iOS开发 runLoop

    从应用的角度来看,runLoop的作用是保证应用能够一直进行下去,不退出;从程序的角度看,runLoop是保证其所...

  • 关于Block的总结

    为什么block会造成循环应用呢? 如果没有__weak修饰,block会把对象从栈copy到堆区,block结束...

  • 从源码看 Block

    这篇文章是自己看源代码以及一些文章总结出来的,如有错误希望有大神指正。 需要先知道这些 Block 在底层是以结构...

  • 从生态的角度看

    1| 读中学的时候,看《射雕英雄传》,欧阳锋父子在海上遇险,漂泊了很多天之后,遇到了洪七公和郭靖、黄蓉。 这时的欧...

  • 企业应用软件和个人应用软件的区别

    摘要:从软件的应用对象、目标及用户角度去探讨,而不是软件开发者或技术特征的角度分析企业应用与个人应用的区别。从多用...

  • Block的应用

    Block的应用 1.在不同语言中的叫法 1.block是 iOS4.0 之后推出的2.在C/Smalltalk ...

  • mysql进阶-行级锁、表级锁、乐观锁、悲观锁

    从应用的角度来看数据库锁可分为悲观锁、乐观锁从数据库(InnoDB)的角度看,数据库锁可以分为行级锁和表级锁 1....

  • 从写手角度看网文写作/ 写作探索

    从写手角度看网文写作 / 写作探索 上一章 从读者角度看网文写作 / 写作探索 昨日写了从读者角度看网文写作,今...

网友评论

    本文标题:从应用的角度看block(待续)

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