iOS - OC Block 代码块

前言

  • Block 是一段预先准备好的代码,可以在需要的时候执行,可以当作参数传递。Block 可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或返回值。Block 是 C 语言的,类似于一个匿名函数,它和传统的函数指针很类似,但是 Block 是 inline(内联函数)的,并且默认情况下它对局部变量是只读的。
  • 苹果官方建议尽量多用 Block。在多线程、异步任务、集合遍历、集合排序、动画转场用的很多。
  • Block 语法
        // Block as a local variable
        returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...};
    
        // Block as a property
        @property (nonatomic, copy) returnType (^blockName)(parameterTypes);
    
        // Block as a method parameter
        - (void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName;
    
        // Block as an argument to a method call
        [someObject someMethodThatTakesABlock: ^returnType (parameters) {...}];
    
        // Block as typedef
        typedef returnType (^TypeName)(parameterTypes);
        TypeName blockName = ^returnType(parameters) {...};

1、Block 的使用

1.1 Block 的定义

  • Block 的简单定义

        // 定义 Block
        /*
            定义了一个名叫 MySum 的 Block 对象,它带有两个 int 型参数,返回 int 型。等式右边就是 Block 的具体实现,大括号后需加分号
        */
        int (^MySum)(int, int) = ^(int a, int b){
    
            return a + b;
        };
    
        // 调用 Block
        int sum = MySum(10, 12);
  • Block 数据类型的定义
        // 定义 block 数据类型 MyBlock
        typedef int (^MyBlock)(int, int);
    
        // 定义 MyBlock 的变量
        MyBlock myblock;
    
        // 实现 MyBlock 的变量 1
        myblock = ^(int a, int b){
    
            return a + b;
        };
    
        // 调用 MyBlock 的变量 1
        int sum = myblock(10, 12);
    
        // 实现 MyBlock 的变量 2
        myblock = ^(int a, int b){
    
            return a - b;
        };
    
        // 调用 MyBlock 的变量 2
        int minus = myblock(13, 2);

1.2 Block 访问局部变量

  • Block 可以访问局部变量,但是不能修改,如果要修改需加关键字 __block(双下划线)。

        // 这样定义时,局部变量 sum 只能读取值不能修改,编译时会报错
        // int sum = 10;
    
        // 这样定义时,局部变量 sum 既可以读取值又能修改
        __block int sum = 10;
    
        int (^MyBlock)(int) = ^(int a){
    
            // 对局部变量值修改
            sum ++;
    
            // 读取局部变量的值
            return a * sum;
        };
    
        int result = MyBlock(5);

2、Block 的回调

2.1 Block 回调使用

    // Block1.h

        // block 属性变量定义
        /*
            要使用 copy 类型,格式:@property (nonatomic, copy) 返回值类型 (^变量名) (参数类型列表);
        */
        @property (nonatomic, copy) void (^completion) (NSString *);

        // 调用 block 代码段声明
        - (void)useBlock;

    // Block1.m

        // 调用 block 代码段
        - (void)useBlock {

            // 设置 block 的回调值

            // 判断是否设置了 block
            if (self.completion != nil) {

                // 设置回调值
                self.completion(@"hello world");
            }
        }

    // Block.m

        #import "Block1.h"

        Block1 *block = [[Block1 alloc] init];

        // 设置 block 代码段
        block.completion = ^(NSString *str) {

            // 结果:string = @"hello world"
            NSString *string = str;
        };

        // 调用 block 代码段
        [block useBlock];

2.2 Block 回调封装

    // Block2.h

        // block 方法参数定义

        // 类方法定义
        + (Block2 *)blockWithCompletion:(void (^) (NSString *)) completion;

        // 调用 block 代码段声明
        - (void)useBlock;

    // Block2.m

        // block 属性变量定义

        // 要使用 copy 类型,格式:@property (nonatomic, copy) 返回值类型 (^变量名) (参数类型列表);
        @property (nonatomic, copy) void (^completion) (NSString *);

        // 调用 block 代码段
        - (void)useBlock {

            // 设置 block 的回调值

            // 判断是否设置了 block
            if (self.completion != nil) {

                // 设置回调值
                self.completion(@"hello world");
            }
        }

        // 类方法实现
        + (Block2 *)blockWithCompletion:(void (^)(NSString *))completion {

            Block2 *bl = [[Block2 alloc] init];

            // 设置属性的值
            bl.completion = completion;

            return bl;
        }

    // Block.m

        #import "Block2.h”

        // 设置 block 代码段
        Block2 *block = [Block2 blockWithCompletion:^(NSString *str) {

            // 结果:string = @"hello world"
            NSString *string = str;
        }];

        // 调用 block 代码段
        [block useBlock];

3、Block 属性定义中为什么使用 copy 修饰

  • ARC 开发的时候,编译器底层对 block 做过一些优化,使用 copy 修饰可以防止出现内存泄漏。
  • 从内存管理的角度而言,程序员需要管理的内存只有堆区的。如果用 strong 修饰,相当于强引用了一个栈区的变量。
  • 而使用 copy 修饰,在设置数值的时候,可以把局部变量从栈区复制到堆区。
        // 用 copy 修饰定义属性
        @property (nonatomic, copy) void (^myTask)();
    
        // 定义,myBlock 是保存在栈区的,出了作用域,就应该被销毁
        void (^myBlock)() = ^ {
    
            NSLog(@"hello");
        };
    
        // 用属性记录
        self.myTask = myBlock;
    
        // 执行
        self.myTask();

4、循环引用

  • 在 Block 中调用 self 容易产生循环引用,无法释放对象,在程序中可以使用析构方法判断是否产生了循环引用。

        @implementation ViewController
    
        // 在 Block 中调用 self 容易产生循环引用
        [[QWebImageManager sharedManager] downloadImage:self.urlStr completion:^(UIImage *image) {
            self.image = image;
        }];
    
        @end
        // 判断是否存在循环引用,无法释放时即存在循环引用
        - (void)dealloc {
            NSLog(@"成功退出");
        }
  • 可以使用关键字 __weak 声明一个弱变量,或者为属性指定 weak 特性。如:
        @implementation ViewController
    
        // 弱引用 self,typeof(self) 等价于 ViewController
        __weak typeof(self) weakSelf = self;
    
        [[QWebImageManager sharedManager] downloadImage:self.urlStr completion:^(UIImage *image) {
            weakSelf.image = image;
        }];
    
        @end
时间: 2024-09-21 00:48:06

iOS - OC Block 代码块的相关文章

iOS - Block 代码块

1.Block Block 是一段预先准备好的代码,可以在需要的时候执行,可以当作参数传递.Block 可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或返回值.Block 是 C 语言的,类似于一个匿名函数,它和传统的函数指针很类似,但是 Block 是 inline(内联函数)的,并且默认情况下它对局部变量是只读的. 苹果官方建议尽量多用 Block.在多线程.异步任务.集合遍历.集合排序.动画转场用的很多. Block 语法 // Block as a local variabl

全面解析Objective-C中的block代码块的使用_IOS

1.相关概念 在这篇笔记开始之前,我们需要对以下概念有所了解. 1.1 操作系统中的栈和堆 注:这里所说的堆和栈与数据结构中的堆和栈不是一回事. 我们先来看看一个由C/C++/OBJC编译的程序占用内存分布的结构: 栈区(stack):由系统自动分配,一般存放函数参数值.局部变量的值等.由编译器自动创建与释放.其操作方式类似于数据结构中的栈,即后进先出.先进后出的原则. 例如:在函数中申明一个局部变量int b;系统自动在栈中为b开辟空间. 堆区(heap):一般由程序员申请并指明大小,最终也由

值得收藏的iOS开发常用代码块_IOS

遍历可变数组的同时删除数组元素 NSMutableArray *copyArray = [NSMutableArray arrayWithArray:array]; NSString *str1 = @"zhangsan"; for (AddressPerson *perName in copyArray) { if ([[perName name] isEqualToString:str1]) { [array removeObject:perName]; } } 获取系统当前语言

Ruby中的block代码块学习教程_ruby专题

1.什么是代码块在Ruby中,{}或do...end之间的代码是一个代码块.代码块只能出现在一个方法的后边,它紧接在方法最后一个参数的同一行上,由yield关键字调用.例如: [1,2,3,4,5].each { |i| puts i } [1,2,3,4,5].each do |i| puts i end 块变量:以yield关键字调用block也可以传递参数,block中竖线(|)之间给出的参数名用于接收来自yield的参数.  竖线之间(如上例中的 | i |)的变量被称作块变量,作用和一

iOS中Block的回调使用和解析详解_IOS

Block 回调实现 先跟着我实现最简单的 Block 回调传参的使用,如果你能举一反三,基本上可以满足了 OC 中的开发需求.已经实现的同学可以跳到下一节. 首先解释一下我们例子要实现什么功能(其实是烂大街又最形象的例子): 有两个视图控制器 A 和 B,现在点击 A 上的按钮跳转到视图 B ,并在 B 中的textfield 输入字符串,点击 B 中的跳转按钮跳转回 A ,并将之前输入的字符串 显示在 A 中的 label 上.也就是说 A 视图中需要回调 B 视图中的数据. 想不明白的同学

ios block 逆传-纯代码写block逆传值,代码块应该写在哪个方法里

问题描述 纯代码写block逆传值,代码块应该写在哪个方法里 如果是用纯代码写block逆传值,Apush到B,从B中传值到A,在B中定义block,调用block. 在A中准备代码块,这个准备的代码块在哪个方法里写? 如果是用storyBoard创建的话,在prepareForSegue方法里写,但是纯代码不知道在哪儿. 也就是B中调用[self.navigationController popViewControllerAnimated:YES]这个方法之后 ,A中该调用哪个方法 解决方案

Objective-C语法之代码块(block)的使用

代码块本质上是和其他变量类似.不同的是,代码块存储的数据是一个函数体.使用代码块是,你可以像调用其他标准函数一样,传入参数数,并得到返回值. 脱字符(^)是块的语法标记.按照我们熟悉的参数语法规约所定义的返回值以及块的主体(也就是可以执行的代码).下图是如何把块变量赋值给一个变量的语法讲解: 按照调用函数的方式调用块对象变量就可以了: int result = myBlock(4); // result是 28 1.参数是NSString*的代码块 [cpp] view plaincopy vo

iOS开发之 :块代码

转自:http://blog.sina.com.cn/s/blog_71715bf8010167tl.html 代码块的基本概念     一个代码块可以简单看作是一组可执行的代码.例如,下面是一个打印当前日期和时间的代码块:^ {    NSDate *date = [NSDate date];    NSLog(@"The date and time is %@", date);};    插入符号(^)声明一个代码块的开始,一对大括号{}构成了代码块的体部.你可以认为代码块与一个匿

iOS开发系列--Objective-C之协议、代码块、分类

概述 ObjC的语法主要基于smalltalk进行设计的,除了提供常规的面向对象特性外,还增加了很多其他特性,这一节将重点介绍ObjC中一些常用的语法特性.当然这些内容虽然和其他高级语言命名不一样,但是我们都可以在其中找到他们的影子,在文章中我也会对比其他语言进行介绍,这一节的重点内容如下: 协议protocol 代码块block 分类category 协议protocol 在ObjC中使用@protocol定义一组方法规范,实现此协议的类必须实现对应的方法.熟悉面向对象的童鞋都知道接口本身是对