博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS - OC Block 代码块
阅读量:6292 次
发布时间:2019-06-22

本文共 5104 字,大约阅读时间需要 17 分钟。

前言

  • 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

转载于:https://www.cnblogs.com/QianChia/p/5782876.html

你可能感兴趣的文章
索引失效 ORA-01502
查看>>
Oracle取月份,不带前面的0
查看>>
Linux Network Device Name issue
查看>>
IP地址的划分实例解答
查看>>
如何查看Linux命令源码
查看>>
运维基础命令
查看>>
入门到进阶React
查看>>
SVN 命令笔记
查看>>
检验手机号码
查看>>
重叠(Overlapped)IO模型
查看>>
Git使用教程
查看>>
使用shell脚本自动监控后台进程,并能自动重启
查看>>
Flex&Bison手册
查看>>
solrCloud+tomcat+zookeeper集群配置
查看>>
/etc/fstab,/etc/mtab,和 /proc/mounts
查看>>
Apache kafka 简介
查看>>
socket通信Demo
查看>>
技术人员的焦虑
查看>>
js 判断整数
查看>>
mongodb $exists
查看>>