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

一、什么是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();
   
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容