04.实战技术 block深入研究,UICollectionView的使用

@(iOS Study)[实战技术]


目录

  • 04.实战技术 block深入研究,UICollectionView的使用
  • 1.block的深入研究
    • block基本使用
    • block开发使用场景(保存代码)
    • block开发使用场景(传值)
    • block内存管理(MRC)
    • block内存管理(ARC)
    • block循环引用
    • block循环引用(复杂)
    • block变量传递
    • block开发使用场景(参数使用)
    • block开发中使用场景(返回值)
  • 2.UICollectionView的使用
    • UICollectionView注意点


1.block的深入研究

block的作用: 可以用来保存一段代码段,也可以用来传递参数.block如果存放代码段,该代码段并不会马上执行,需用手动调用.

  • 快速生成block代码
    • 输入'inlineBlock'快速生成block代码
      -block类型是对象,不是普通数据类型

block基本使用

  • block的格式
// block的完整格式
block返回类型(^block变量名)(block参数) = ^(block返回类型,一般情况都省略)(block参数>) {
    // block代码段
}
  • block的声明方式
// block声明:返回值(^Block变量名)(block参数类型),参数变量名可以省略
void(^block)();
void(^block1)(int);
  • block的定义方式
    // block定义: 等号右边 ^(参数类型 参数变量名){};
    void(^block2)(int a) = ^(int a){
        
    };
    
    // block定义二: 等号右边 ^返回值(参数类型 参数变量名){};,返回值(=号后面第一个int)可以省略,但是也有不省略
    int(^block3)(int a) = ^int(int a){
        return 2;
    };
    
    // block定义三: 当没有返回值,没有参数,可以省略
    void(^block4)() = ^{
        
    };

block开发使用场景(保存代码)

  • 模型中block类型属性的使用
    • 给模型添加一个block类型的成员属性,用来存放代码段.
    • 参考代码
// 声明block类型的成员属性
@interface CellItem : NSObject
// 声明一个block类型的成员属性
@property (nonatomic, strong) void(^block)();
@property (nonatomic, strong) NSString *title;
+ (instancetype)itemWithTitle:(NSString *)title;
@end

// 给block添加代码段
CellItem *item = [CellItem itemWithTitle:@"打电话"];
item.block = ^{
    NSLog(@"打电话");
};

// 执行block,需判断block是否为空,如果为空,调用时会导致程序奔溃
if (item.block) {
    item.block();
}

block开发使用场景(传值)

顺传:定义属性
逆传:代理,block,block可以用来替代代理

  • block逆传值步骤(控制器B由控制器A Modal出来的, 控制器B逆传值给控制器A)

    • 1.在控制器B添加一个block属性
    // 控制器B
    @property (nonatomic, strong) void(^blockValue)(NSString *value);
    
    • 2.在控制器A中给控制器B的block添加代码段
      // 控制器A
      // REMARKS: block传值(逆传)
      - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
      {
          ModalViewController *modalVc = [[ModalViewController alloc] init];
          // 给modalVc的block属性添加代码段
          modalVc.blockValue = ^(NSString *value){
              NSLog(@"%@", value);
          };
          [self presentViewController:modalVc animated:YES completion:nil];
      }
    
    • 3.在控制器B点击时调用block
      - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
      {
          // block逆传
          if (self.blockValue) {
              self.blockValue(@"123");
          }
          
          [self dismissViewControllerAnimated:YES completion:nil];
      }
    
    • 4.控制器B调用block时,会将@"123"传递给控制器A中的
    // 控制器B调用block会调用以下代码段,并将value传递过来
    modalVc.blockValue = ^(NSString *value){
        NSLog(@"%@", value);
    };
    

block内存管理(MRC)

  • 内存5个区:堆,栈,方法区,常量区,全局区

    • 堆:手动管理内存
    • 栈:自动管理,代码块一过,就会自动释放.
  • 在MRC中的存储

    • 如果block没有访问外部的局部变量或者访问被static修饰局部变量,block默认存放在全局区.
    • 如果block访问外部的局部变量,block存放在"栈"里面
      // REMARKS: 测试block访问外部局部变量,block的存储
      - (void)test2 {
          
          // 1.验证block的存储区域
          int a = 10;
          void(^block)() = ^{
              NSLog(@"%d", a);
          };
          
          self.block = block;
          // ARC打印结果: <__NSMallocBlock__: 0x7fc433d0fab0> (block存储在堆区)
          // MRC打印结果: <__NSStackBlock__: 0x7fff51e24a18>  (block存储在栈区)
          NSLog(@"%@", block);
      }
    
    // REMARKS: 验证block的方法static修饰的局部变量,block的存储
    - (void)test1 {
        
        // 1.验证block的存储区域
        static int a = 10;
        void(^block)() = ^{
            NSLog(@"%d", a);
        };
        // ARC和MRC打印结果一样: <__NSGlobalBlock__: 0x10e1d9090>
        NSLog(@"%@", block);
    }
    
  • MRC使用block的注意点

    • MRC:不能使用retain声明block,block依然放在栈里面,会自动销毁.如果用retain声明的属性引用block,则程序奔溃.
    • MRC:使用copy声明block,才会放在堆里面
  • MRC开发习惯:访问属性或者设置属性,MRC必须使用点语法,不要使用下划线.因为点语法会调用get方法,get方法会做引用计数器+1操作.而用下划线没有对引用计数器+1.

  • MRC:没有strong,和weak, 只有assign, retain, copy

  • 区分MRC代码:

    • 1.看能否调用release retain retainCount
    • 2.ARC不能调用[super dealloc]

block内存管理(ARC)

  • ARC环境block的存储区
    如果block访问外部的局部变量,block存放在"堆"里面

  • block原则

    • 如果block没有访问外部的局部变量或者局部变量被static修饰,block默认存放在"全局区"
    • ARC:使用strong声明block,不要使用weak.
  • ARC管理原则:默认一个局部变量对象,都是强指针,存放堆里面

block循环引用

block会对外部所有强指针对象给强引用,block不会对外部弱指针对象给强引用.

  • block代码段内部使用self

    • 正确用法: 使用__weak typeof(self) weakSelf = self;将self转换成弱指针.对象能正常被销毁
    // 使用__weak typeof(self) weakSelf = self;将self转换成弱指针.
    __weak typeof(self) weakSelf = self;
    _block = ^{
        NSLog(@"%@", weakSelf);
    };
    
    • 错误用法: 直接在block内部使用self,造成循环引用,对象不会被销毁.
    _block = ^{
        NSLog(@"%@", self);
    };
    

block循环引用(复杂)

  • block在多线程中的应用

    • block内部执行延迟操作或者异步任务需要在block内部对weakSelf做一次__strong的引用,让对象延迟释放,以确保在执行延迟操作或异步任务时,对象还没被释放.
    • 以下block内部执行延迟操作,对象会延迟2秒后才释放.
      - (void)blockTest
      {
          // SINGLE: block内部执行延迟操作或者异步任务需要在block内部对weakSelf做一次__strong的引用
          
          __weak typeof(self) weakSelf = self;
          _block = ^{
              
              // 需要在block内部对weakSelf做一次__strong的引用,必须用__strong强引用weakSelf,这样才能延迟释放self对象,否则会出现延迟打印结果为null,在执行延迟任务前,对象已经被释放了.
              __strong typeof(weakSelf) strongSelf = weakSelf;
              
              // 执行延迟操作或异步任务,
              dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                  NSLog(@"%@", strongSelf);
              });
              
          };
          
          // 执行block
          _block();
      }
    

block变量传递

  • block访问外部局部变量没有被任何关键字修饰,都是值传递.值传递表示block中的value不会随外部的改变而改变.
- (void)test
{
    // block访问外部局部变量没有被任何关键字修饰,都是值传递.值传递表示外部的value值改变不会影响block内部的值.
    int value = 10;
    
    void(^block)() = ^{
        
        NSLog(@"%d", value);
    };
    
    value = 20;
    
    block();
    
    // 打印结果: 10
}
  • block访问外部变量是全局变量或者被__block,static修饰,都是指针传递,block中的value会随外部的改变而变.
- (void)test1
{
    //  block访问外部变量是全局变量或者被__block,static修饰,都是指针传递,block中的value会随外部的改变而改变.
    static int value = 10;
    
    void(^block)() = ^{
        NSLog(@"%d", value);
    };
    
    value = 20;
    
    block();
    
    // 打印结果: 20
}

block开发使用场景(参数使用)

  • block作为方法参数使用
// block当参数使用 caculatorBlock带有一个参数result,并且返回值为int类型
- (void)caculator:(int(^)(int result))caculatorBlock;

block开发中使用场景(返回值)

  • 链式编程思想:把方法调用通过点语法链接,可读性非常好 (Masonry框架使用)

  • 链式编程思想的简单使用,block当返回值

- (void)test1
{
    // self.add()相当于调用 add的get方法,get方法返回值是block类型的,再用返回值调用
//    void(^block)() = self.add;
//    block();
    
    self.add();
}

- (void(^)())add
{
    return ^{
        NSLog(@"add");
    };
}

  • 使用block当做返回值, 实现manager.add(10).add(5)链式编程

    • 1.先分析manager.minus(3)操作,相当于先调用get方法,返回block类型的值,再通过返回值调用block.
    // manager.minus(3)相当于执行以下两个操作
    // void(^block)(int) = manager.minus;
    // block(3);
    
    • 2.由以上可推出manager的方法声明
      - (void(^block)(int))minus;
      
      // 实现- (void(^block)(int))minus方法
      - (void(^block)(int))minus
      {
          return ^(int value){
              _result -= value;
          };
      }
    
    • 3.分析manager.minus(3).minus(10),如果想再调用.minus(10)执行操作,manager.minus(3)返回值必须是CalculatorManager类型对象,由此可以分析出,block的返回值不是void,而是CalculatorManager类型.
      - (CalculatorManager *(^)(int)) minus;
      
      // 实现- (CalculatorManager *(^)(int)) minus方法
      - (CalculatorManager *(^)(int)) minus
      {
          return ^(int value){
              _result -= value;
              // 下面的return表示block的返回值,返回当前对象
              return self;
          };
      }
    
    • 4.以上操作完成,外部就能用manager.minus(3).minus(10)链式编程.

2.UICollectionView的使用

UICollectionView注意点

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

推荐阅读更多精彩内容