iOS - Block 代码块

作者:操作系统

,请留神11、22大约是同时打字与印刷的,因为//XXJFrame不是堵塞的可能说模态的;不囿于于此例子,举个例子XXFrame替换为其它意气风发段供给奉行非常久的线程;//怎么剖断代码已实践实现?小编索要的是依附进度树查找之类的代码,并非给XXJFrame加关闭事件或重写起dispose方法之类或在鲜明知晓程序要终结的地方通告主函数它结束了!

OC参预代码块的效果,能够将一块代码当作三个对象同样对待,並且传递给任何艺术或函数.代码块支持在代码中定义四个函数对象,那几个函数对象能够经过守旧的变量来援引,也能够将其传播到其它函数,那就代表,你能够定义可复用的代码段,何况能够向目的形似四处传递从而动态地在任何对象内部试行.那听起来或然让你有一点点吸引,然则未有关联,通过此处的多少个例证,你能够轻巧的驾驭并能够利用代码块,它远未有您想像的那么难

         onNext:{print($0)},

3.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];

风流浪漫段代码,譬喻

提醒:在列出参数时,无需提供参数的变量名,是或不是提供变量名由你来支配,但那不是必需的.只怕那样驾驭相比好:近日还尚无证明函数体,所以提供参数的变量名没有此外意义,因为有的时候不会用到它.你仅需告诉编写翻译器参数的体系就可以,八个参数类型要以逗号隔绝.非常多代码块的文书档案在宣称时都简短了参数名,但自身不会这么做,因为自个儿认为这样的代码会使初读书人吸引.

       onDisposed:{print("释放")}

3.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];
while(true){//我需要在这里判断一下以下的代码进程全部已结束(newThread(){publicvoidrun(){System.out.println("11");newXXJFrame().show();System.out.println("22");}}).start();}

扬言和贯彻:

我们仍然是能够够在外面创造错误音讯

6.3 单 for 循环中异步 Block

  • 使用

        NSLog(@"Hello World 1");
    
        // 需要在子线程中执行,否则会阻塞主线程
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
    
            NSLog(@"Hello World 2");
    
            // 创建 semaphore
            dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
            // block 完成回调计数
            __block NSInteger count = 0;
    
            __weak typeof(self) weakSelf = self;
    
            int loopCount = 10;
            for (int i = 0; i < loopCount; i  ) {
    
                [self dlownloadCompletion:^(NSString *str) {
    
                    NSLog(@"%@ 3 -  %li, %@", str, count, [NSThread currentThread]);
    
                    @synchronized (weakSelf) {
    
                        // 完成回调计数加 1
                        count  ;
    
                        if (count == loopCount) {
    
                            [NSThread sleepForTimeInterval:5];
    
                            // 发出已完成的信号
                            dispatch_semaphore_signal(semaphore);
                        }
                    }
                }];
            }
    
            // 等待执行,阻塞线程
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
            NSLog(@"Hello World 4");
        });
    
        NSLog(@"Hello World 6");
    
  • 实践遵守

        22:54:27.550 OCTest[64721:2187151] Hello World 1
        22:54:27.551 OCTest[64721:2187151] Hello World 6
        22:54:27.551 OCTest[64721:2187249] Hello World 2
        22:54:29.615 OCTest[64721:2187248] Hello World 3 -  2, <NSThread: 0x60000026e600>{number = 4, name = (null)}
        22:54:29.615 OCTest[64721:2187276] Hello World 3 -  4, <NSThread: 0x608000266980>{number = 6, name = (null)}
        22:54:29.615 OCTest[64721:2187280] Hello World 3 -  7, <NSThread: 0x608000265c80>{number = 8, name = (null)}
        22:54:29.615 OCTest[64721:2187278] Hello World 3 -  5, <NSThread: 0x608000266740>{number = 7, name = (null)}
        22:54:29.615 OCTest[64721:2187251] Hello World 3 -  1, <NSThread: 0x60000007e200>{number = 3, name = (null)}
        22:54:29.615 OCTest[64721:2187277] Hello World 3 -  3, <NSThread: 0x608000266800>{number = 5, name = (null)}
        22:54:29.615 OCTest[64721:2187281] Hello World 3 -  8, <NSThread: 0x60000026e540>{number = 9, name = (null)}
        22:54:29.615 OCTest[64721:2187279] Hello World 3 -  6, <NSThread: 0x608000266a40>{number = 10, name = (null)}
        22:54:29.615 OCTest[64721:2187282] Hello World 3 -  9, <NSThread: 0x608000266bc0>{number = 11, name = (null)}
        22:54:29.615 OCTest[64721:2187283] Hello World 3 -  10, <NSThread: 0x60000026e800>{number = 12, name = (null)}
        22:54:34.676 OCTest[64721:2187249] Hello World 4
    

代码块本质上相符任何变量相同.差别的是,代码块存款和储蓄的多少是三个函数体,脱字符(^State of Qatar是代码块的语法标识,依照大家熟练的语准绳则定义重回值、参数以致代码块的着珍视(也便是足以履行的代码卡塔尔国.首先大家来看壹个最最轻便易行的代码块的演示:

create是什么样,正是制造。

2.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);
    

//代码块的扬言

double(^getArea)(double width,double height);

//代码块的兑现

getArea = ^(double width,double height){

double area = width * height;

return area;

};

double area = getArea(5,10);

NSLog(@"area = %.2f",area);

     )

6.4 嵌套 for 循环中异步 Block

  • 使用

        NSLog(@"Hello World 1");
    
        // 需要在子线程中执行,否则会阻塞主线程
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
    
            NSLog(@"Hello World 2");
    
            // 创建 semaphore
            dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
            // block 完成回调计数
            __block NSInteger count = 0;
    
            __weak typeof(self) weakSelf = self;
    
            int loopCount1 = 4;
            int loopCount2 = 5;
            for (int i = 0; i < loopCount1; i  ) {
    
                for (int j = 0; j < loopCount2; j  ) {
    
                    [self dlownloadCompletion:^(NSString *str) {
    
                        NSLog(@"%@ 3 - %li, %@", str, count, [NSThread currentThread]);
    
                        @synchronized (weakSelf) {
    
                            // 完成回调计数加 1
                            count  ;
    
                            if (count == loopCount1 * loopCount2) {
    
                                [NSThread sleepForTimeInterval:5];
    
                                // 发出已完成的信号
                                dispatch_semaphore_signal(semaphore);
                            }
                        }
                    }];
                }
            }
    
            // 等待执行,阻塞线程
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
            NSLog(@"Hello World 4");
        });
    
        NSLog(@"Hello World 6");
    
  • 推行成效

        23:01:09.926 OCTest[64907:2192862] Hello World 1
        23:01:09.928 OCTest[64907:2192862] Hello World 6
        23:01:09.928 OCTest[64907:2193485] Hello World 2
        23:01:11.931 OCTest[64907:2192981] Hello World 3 - 1, <NSThread: 0x608000260680>{number = 3, name = (null)}
        23:01:11.931 OCTest[64907:2193486] Hello World 3 - 2, <NSThread: 0x600000073080>{number = 23, name = (null)}
        23:01:11.932 OCTest[64907:2193487] Hello World 3 - 3, <NSThread: 0x60000007c880>{number = 24, name = (null)}
        23:01:11.932 OCTest[64907:2193488] Hello World 3 - 4, <NSThread: 0x60000007c8c0>{number = 25, name = (null)}
        23:01:11.933 OCTest[64907:2193489] Hello World 3 - 5, <NSThread: 0x60000007c900>{number = 26, name = (null)}
        23:01:11.933 OCTest[64907:2193490] Hello World 3 - 6, <NSThread: 0x60000007c940>{number = 27, name = (null)}
        23:01:11.933 OCTest[64907:2193491] Hello World 3 - 7, <NSThread: 0x60000007c980>{number = 28, name = (null)}
        23:01:11.933 OCTest[64907:2193492] Hello World 3 - 8, <NSThread: 0x60000007c9c0>{number = 29, name = (null)}
        23:01:11.934 OCTest[64907:2193493] Hello World 3 - 9, <NSThread: 0x60000007ca00>{number = 30, name = (null)}
        23:01:11.934 OCTest[64907:2193494] Hello World 3 - 10, <NSThread: 0x60000007ca40>{number = 31, name = (null)}
        23:01:11.935 OCTest[64907:2193495] Hello World 3 - 11, <NSThread: 0x60000007ca80>{number = 32, name = (null)}
        23:01:11.936 OCTest[64907:2193496] Hello World 3 - 12, <NSThread: 0x608000073f80>{number = 33, name = (null)}
        23:01:11.937 OCTest[64907:2193497] Hello World 3 - 13, <NSThread: 0x60000007cac0>{number = 34, name = (null)}
        23:01:11.938 OCTest[64907:2193498] Hello World 3 - 14, <NSThread: 0x60000007cb00>{number = 35, name = (null)}
        23:01:11.938 OCTest[64907:2193499] Hello World 3 - 15, <NSThread: 0x60000007cb40>{number = 36, name = (null)}
        23:01:11.938 OCTest[64907:2193500] Hello World 3 - 16, <NSThread: 0x60000007cb80>{number = 37, name = (null)}
        23:01:11.939 OCTest[64907:2193501] Hello World 3 - 17, <NSThread: 0x60000007cbc0>{number = 38, name = (null)}
        23:01:11.939 OCTest[64907:2193502] Hello World 3 - 18, <NSThread: 0x60000007cc00>{number = 39, name = (null)}
        23:01:11.940 OCTest[64907:2193503] Hello World 3 - 19, <NSThread: 0x60000007cc40>{number = 40, name = (null)}
        23:01:11.940 OCTest[64907:2193504] Hello World 3 - 20, <NSThread: 0x60000007cc80>{number = 41, name = (null)}
        23:01:17.006 OCTest[64907:2193485] Hello World 4
    

深入分析下边的代码,注意第8行代码,注明了一个封存代码块的变量aBlock,最前方的void 说西魏码块试行时未有重回值.紧跟着回来值类型定义的是三个例外操作符,它报告编写翻译器所定义的是代码块并不是任何品种的变量,这么些操作字符就是多字符(^卡塔尔.

//        }

5、循环援引

  • 1、在 Block 中调用 self 轻巧产生循环援用,风姿浪漫旦现身循环援用的话内部存款和储蓄器就得不到释放,因而必须要小心内部存款和储蓄器管理难点。

        @implementation ViewController
    
        // 在 Block 中调用 self 容易产生循环引用
        [[QWebImageManager sharedManager] downloadImage:self.urlStr completion:^(UIImage *image) {
            self.image = image;
        }];
    
        @end
    
    • 1卡塔尔(قطر‎ 查询内部存款和储蓄器管理难点消除办法:

      • 1> 打印法

        • 最佳在基类 controller 下重写 dealloc,加一句打印日志,表示类能够赢得释放。假使出现无打字与印刷新闻,表明那个类一贯得不到释放,证明很有超大可能率是利用 block 的地点现身循环引用了。对于 block 中供给援引外部controller 的习性可能成员变量时,必须求选取弱引用,特别是成员变量像 _testId 那样的,很五个人都不曾采纳弱援引,引致内部存款和储蓄器得不到自由。

              // 判断是否存在循环引用,无法释放时即存在循环引用
              - (void)dealloc {
                  NSLog(@"成功退出");
              }
          
      • 2> 利用 instrument 检验内部存款和储蓄器败露

        • 在 Xcode 的 instrument 工具集能够很有益的检查实验循环引用。Product => profile => 选取 Leaks,之后点击运转,要是现身暗红,点击 Details => Cycles&Roots

          操作系统 1

          操作系统 2

    • 2卡塔尔 化解循环援用方法

      • 能够接收重要字 __weak 声多美滋(Dumex卡塔尔国个弱变量,大概为属性内定 weak 特性。如:

            @implementation ViewController
        
            // 弱引用 self,typeof(self) 等价于 ViewController
            __weak typeof(self) weakSelf = self;
        
            [[QWebImageManager sharedManager] downloadImage:self.urlStr completion:^(UIImage *image) {
                weakSelf.image = image;
            }];
        
            @end
        
  • 2、当 block 自个儿不被 self 持有,而被别的对象具有,同不经常间不发生循环援引的时候,就没有须要接受 weak self 了。最不足为道的代码就是 UIView 的卡通片代码,我们在运用 UIView 的 animateWithDuration:animations 方法 做动漫的时候,并无需使用 weak self,因为引用持有关系是:

    • UIView 的某部担当动漫的目标具有了 block
    • block 持有了 self

    • 因为 self 并不有所 block,所以就从不循环援用发生,所以就无需运用 weak self 了。

          [UIView animateWithDuration:0.2 animations:^{
              self.alpha = 1;
          }];
      
    • 当动漫甘休时,UIView 会结束全数那几个 block,若无其他对象具有block 的话,block 对象就能够自由掉,进而 block 会释放掉对于 self 的兼具。整个内部存款和储蓄器引用关系被撤消。

  • 3、为啥 weakSelf 须求相配 strong self 使用

    • 咱俩理解,在选用 block 的时候,为了幸免发生循环引用,平日须要运用 weakSelf 与 strongSelf,写下边那样的代码。那么请问:为何 block 里面还亟需写叁个 strong self。

          __weak typeof(self) weakSelf = self;
          [self doSomeBackgroundJob:^{
      
              __strong typeof(weakSelf) strongSelf = weakSelf;
              if (strongSelf) {
                  ...
              }
          }];
      
    • 在 block 中先写多个 strong self,其实是为了幸免在 block 的进行进程中,忽然出现 self 被假释的狼狈意况。日常状态下,借使不那样做的话,依然超级轻便并发有的不敢相信 无法相信的逻辑,以至闪退。我们以 AFNetworking 中 AFNetworkReachabilityManager.m 的朝气蓬勃段代码譬喻:

          __weak __typeof(self)weakSelf = self;
          AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
      
              __strong __typeof(weakSelf)strongSelf = weakSelf;
      
              strongSelf.networkReachabilityStatus = status;
              if (strongSelf.networkReachabilityStatusBlock) {
                  strongSelf.networkReachabilityStatusBlock(status);
              }
          };
      
      • 倘若未有 strongSelf 的那行代码,那么后边的每意气风发行代码施行时,self 都只怕被假释掉了,那样很只怕招致逻辑至极。特别是当我们正在施行strongSelf.networkReachabilityStatusBlock(status卡塔尔国; 这一个block 闭包时,若是这么些 block 实施到一半时 self 释放,那么多半景况下会 Crash。

      • 这里有风度翩翩篇文章详细分解了这些标题:

唯独,仅仅申明变量是非常不够的.大家须要给这几个代码块变量赋值,那么给代码块赋值的时候,能够这么做:

看了下是因为源代码是public static funccreate(_subscribe: @escaping(AnyObserver) -> Disposable) -> Observable

2、Block 的使用

语法:
     代码块名字 = ^(参数列表卡塔尔国 {代码块的行为主体};

有个特意对应的观测对象debug

2.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);
    

代码块变量的扬言要比平时变量注脚复杂,普通变量证明不须求传入参数,並且未有回去值.也因为代码块变量存款和储蓄的数目是多少个函数体,所以声南梁码块变量时须要注明参数和重返类型,对于一个代码块变量的扬言,能够这么做:
   语法:
       再次来到值类型(^代码块名字State of Qatar(参数列表卡塔尔(قطر‎;

本次讲rxSwift里的create机制

6.2 八个异步 Block

  • 使用

        NSLog(@"Hello World 1");
    
        // 需要在子线程中执行,否则会阻塞主线程
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
    
            NSLog(@"Hello World 2");
    
            // 创建 semaphore
            dispatch_semaphore_t semaphore1 = dispatch_semaphore_create(0);
    
            [self dlownloadCompletion:^(NSString *str) {
    
                NSLog(@"%@ 3, %@", str, [NSThread currentThread]);
    
                // 发出已完成的信号
                dispatch_semaphore_signal(semaphore1);
            }];
    
            // 等待执行,阻塞线程
            dispatch_semaphore_wait(semaphore1, DISPATCH_TIME_FOREVER);
    
            // 创建 semaphore
            dispatch_semaphore_t semaphore2 = dispatch_semaphore_create(0);
    
            [self dlownloadCompletion:^(NSString *str) {
    
                NSLog(@"%@ 4, %@", str, [NSThread currentThread]);
    
                // 发出已完成的信号
                dispatch_semaphore_signal(semaphore2);
            }];
    
            // 等待执行,阻塞线程
            dispatch_semaphore_wait(semaphore2, DISPATCH_TIME_FOREVER);
    
            NSLog(@"Hello World 5");
        });
    
        NSLog(@"Hello World 6");
    
  • 实施效果

        22:15:24.288 OCTest[63748:2156048] Hello World 1
        22:15:24.289 OCTest[63748:2156048] Hello World 6
        22:15:24.289 OCTest[63748:2156165] Hello World 2
        22:15:26.361 OCTest[63748:2156450] Hello World 3, <NSThread: 0x608000266700>{number = 3, name = (null)}
        22:15:28.429 OCTest[63748:2156450] Hello World 4, <NSThread: 0x608000266700>{number = 3, name = (null)}
        22:15:28.429 OCTest[63748:2156165] Hello World 5
    

纪念最终要以分号截至语句.到近年来截至,大家注明了多个变量aBlock,用于存款和储蓄代码块.它选拔钦命参数并赶回钦命的值类型.

    enum MyError:Error{

6、五个异步 Block 遵照顺序实行

  • 异步 Block 的推行种种日常为先施行 Block 前的代码,再实践 Block 之后的代码,最终实施 Block 中的代码,如下代码。

    • 创建

          @property (nonatomic, copy) void (^completion) (NSString *);
      
          - (void)dlownloadCompletion:(void (^)(NSString *str))completion {
      
              self.completion = completion;
      
              if (self.completion) {
                  dispatch_async(dispatch_get_global_queue(0, 0), ^{
      
                      [NSThread sleepForTimeInterval:2];
      
                      self.completion(@"Hello World");
                  });
              }
          }
      
    • 使用

          NSLog(@"Hello World 1");
      
          [self dlownloadCompletion:^(NSString *str) {
      
              NSLog(@"%@ 2, %@", str, [NSThread currentThread]);
          }];
      
          NSLog(@"Hello World 3");
      
    • 实施服从

          22:07:12.520 OCTest[79089:3232021] Hello World 1
          22:07:12.521 OCTest[79089:3232021] Hello World 3
          22:07:14.521 OCTest[79089:3232160] Hello World 2, <NSThread: 0x60000006a500>{number = 3, name = (null)}
      
  • 那么怎么样贯彻先施行 Block 中的代码,再实施 Block 之后的代码呢?使用线程窒碍的点子。

在^字符之后,给出了仓库储存代码块的变量名 aBlock,这几个变量名同脱字符(^卡塔尔一同行使小括号同其后的参数隔断.

         return Disposables.create()

6.1 单个异步 Block

  • 操作系统,使用

        NSLog(@"Hello World 1");
    
        // 需要在子线程中执行,否则会阻塞主线程
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
    
            NSLog(@"Hello World 2");
    
            // 创建 semaphore
            dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
            [self dlownloadCompletion:^(NSString *str) {
    
                NSLog(@"%@ 3, %@", str, [NSThread currentThread]);
    
                // 发出已完成的信号
                dispatch_semaphore_signal(semaphore);
            }];
    
            // 等待执行,阻塞线程
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    
            NSLog(@"Hello World 4");
        });
    
        NSLog(@"Hello World 5");
    
  • 实行效果

        22:13:40.457 OCTest[63696:2154201] Hello World 1
        22:13:40.458 OCTest[63696:2154201] Hello World 5
        22:13:40.458 OCTest[63696:2154254] Hello World 2
        22:13:42.460 OCTest[63696:2154404] Hello World 3, <NSThread: 0x60000007b840>{number = 3, name = (null)}
        22:13:42.461 OCTest[63696:2154254] Hello World 4
    

本文由ca88发布,转载请注明来源

关键词: iO 日记本 代码 结束 线程