Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 亚洲在线一区二区三区,九九99国产精品视频,毛片在线视频观看

          整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          Block中嵌套block需要注意的事項

          Block中嵌套block需要注意的事項

          近在看[Blocks Programming Topics](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Blocks/Articles/00_Introduction.html#//apple_ref/doc/uid/TP40007502-CH1-SW1)中[Blocks](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW7)有如下的這段話:

          When you copy a block, any references to other blocks from within that block are copied if necessary—an entire tree may be copied (from the top). If you have block variables and you reference a block from within the block, that block will be copied.

          大致翻譯如下:

          當你復制一個block的時候,在這個block里的其他block任何引用也會被復制,如果有必要的話,一顆完整的樹也許被復制(從頂部開始)。如果你有block變量并且你在這個block引用了另一個block,另一個block也會被復制。

          測試對象:`RXBlockBlockObject`

          @interface RXBlockBlockObject : NSObject
          - (void)test;
          @end
          

          `RXBlockBlockObject.m`文件中:

          @interface RXBlockBlockObject()
          @property (nonatomic, copy) int(^block)(int);
          @property (nonatomic, assign) int tmpValue;
          @end
          @implementation RXBlockBlockObject
          - (void)test
          {
           [self _test_block_normal];
          // [self _test_block_nested_retain_cycle];
          // [self _test_block_nested];
          }
          - (void)dealloc
          {
           NSLog(@"RXBlockBlockObject dellloc");
          }
          @end
          

          測試類中:

          - (void)_test_block
          {
           RXBlockBlockObject *tmp=[RXBlockBlockObject new];
           [tmp test];
           // tmp 會被釋放的
          }
          

          `_test_block_normal` method

          - (void)_test_block_normal
          {
           self.tmpValue=10;
           self.block=^(int m) {
           return m + 4;
           };
           void (^block1)(void)=^{
           NSLog(@"%zd", self.block(5));
           };
           dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), block1);
          }
          

          持有關系如下描述:

          `self(viewController)`持有了`block`,`dispatch_after`的一個全局管理器持有了`block1`,`block1`持有了`self`,沒有出現循環引用。

          輸出如下:

          9
          RXBlockBlockObject dellloc
          

          `_test_block_nested_retain_cycle` method

          - (void)_test_block_nested_retain_cycle
          {
           self.tmpValue=10;
           
           // A(self)強引用了B(block),B強引用了C(block1),C強引用了A(self)了,導致循環引用
           self.block=^(int m) {
           // inline block
           
           void (^block1)(void)=^{
           // 不會提示warning,但是實際上已經出現了循環引用
           NSLog(@"%zd", self.tmpValue + m);
           // 會提示warning: Capturing 'self' strongly in this block is likely to load to a retain cycle
           // 但是感覺這是無限遞歸調用了~~~~
           // NSLog(@"%zd", self.block(10));
           };
           dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), block1);
           return m + 4;
           };
           
           void (^block2)(void)=^{
           NSLog(@"%zd", self.block(5));
           };
           dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), block2);
          }
          

          持有關系如注釋中的描述:

          A(`self`)強引用了B(`block`),B強引用了C(`block1`),C強引用了A(`self`)了,導致循環引用。

          輸出結果是:

          9
          15
          

          不會調用dealloc,出現循環引用,內存泄漏了

          `_test_block_nested` method 上一個的進化版本,解決循環引用

          - (void)_test_block_nested
          {
           self.tmpValue=10;
           __weak __typeof(self) weakSelf=self;
           self.block=^(int m) {
           // inline block
           __strong __typeof(self) strongSelf=weakSelf;
           void (^block1)(void)=^{
           NSLog(@"%zd", strongSelf.tmpValue + m);
           };
           dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), block1);
           return m + 4;
           };
           dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
           NSLog(@"%zd", self.block(5));
           });
          }
          

          使用`__weak`和`__strong`解決,`block2`延長了`self`的生命周期

          輸出結果:

          近在看[Blocks Programming Topics](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Blocks/Articles/00_Introduction.html#//apple_ref/doc/uid/TP40007502-CH1-SW1)中[Creating a Block](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Blocks/Articles/bxDeclaringCreating.html#//apple_ref/doc/uid/TP40007502-CH4-SW4)有如下的這段話:

          If you don’t explicitly declare the return value of a block expression, it can be automatically inferred from the contents of the block. If the return type is inferred and the parameter list is `void`, then you can omit the (`void`) parameter list as well. If or when multiple return statements are present, they must exactly match (using casting if necessary).

          總共有三句話,分別字面上的翻譯如下

          1. 如果你沒有明確的聲明一個block表達式的返回值,他可能會根據block的內容來推斷出返回值。

          2. 如果返回類型是被推斷出的并且參數列表是`void`,那么你同樣可以省略(`void`)參數列表。

          3. 如果或者當多個返回表達式出現的時候,它們必須精確的匹配上(如果有必要的話使用強制轉換)。

          首先我是對block表達式的概念理解有誤,所以做了如下的測試:

          - (void)_incorrect_test
          {
           // 以下的例子都是錯誤的(編譯報錯),因為在定義變量的時候,必須要明確的指定返回類型
           // 是block表達式中省略了返回值類型
          // (^block1)(void)=^(void) {
          // return nil;
          // };
          //
          // (^block2)(void)=id ^(void) {
          // return nil;
          // };
          //
          // (^block3)(void)=(id)^(void) {
          // return nil;
          // };
          }
          

          首先對于如下的一個block聲明:

           void* (^block2)(void)=^(void) {
           return nil;
           };
          

          `=`左邊的是變量聲明,而`=`右邊的才是`block expression`。

          正確的理解了`block expression`,做了如下的測試代碼:

          - (void)_correct_test
          {
           // 這個例子是錯誤的,因為nil在這里被理解為了 void*
          // id (^block1)(void)=^(void) {
          // return nil;
          // };
           // 這樣就可以了,定義變量的時候,讓其返回void*
           void* (^block2)(void)=^(void) {
           return nil;
           };
           // 在block表達式中,省略了返回值類型
           id (^block3)(void)=^(void) {
           return [NSObject new];
           };
           // 在block表達式中,明確的指出了返回值類型
           // 不是明確的指出了,是強制轉為id類型
           id (^block4)(void)=(id)^(void) {
           return [NSObject new];
           };
           // 當參數列表是void的時候,在block表達式中可以省略
           // 返回值類型是推斷的 為void
           void (^block5)(void)=^{
           NSLog(@"1");
           };
           // 當參數列表是void的時候,在block表達式中可以省略
           // 返回值類型是推斷的 為id
           id (^block6)(void)=^{
           return [NSObject new];
           };
           // 當參數列表是void的時候,在block表達式中可以省略
           // 返回值類型是指明的 為id
           id (^block7)(void)=(id)^{
           return [NSObject new];
           };
           id block8=^(int m) {
           switch (m) {
           case 1:
           {
           // 這里推斷出block應該返回int
           return 1;
           }
           break;
          // case 2:
          // {
          // // Error: Return type 'NSObject *' must match previous return type 'int' when block literal has unspecified explicit return type
          // return [NSObject new];
          // }
          // break;
           case 3:
           {
           // 強行把double轉換為整形,也許通常我們的做法是把case 1: 中返回int轉換為返回double
           return (int)(m + 4.0);
           }
           break;
          // case 4:
          // {
          // // Error: Return type 'void *' must match previous return type 'int' when block literal has unspecified explicit return type
          // return nil;
          // }
          // break;
           default:
           {
           return 0;
           }
           break;
           }
           };
           // block是一個對象,所以可以直接定義id block9
           id block9=^(int m) {
           return 5 + m;
           };
           // 正確的方法:顯示的指明返回值類型
           void (^block10)(void)=^void(void) {
           NSLog(@"11");
           };
           int (^block11)(int m)=^int(int m) {
           return m + 4;
           };
           int (^block12)(void)=^int {
           return 4;
           };
           block2();
           block3();
           block4();
           block5();
           block6();
           block7();
           int (^block_transf8)(int)=block8;
           block_transf8(1);
           int (^block_transf9)(int)=block9;
           block_transf9(1);
           block10();
           block11(2);
           block12();
           id block20=^void (void) { printf("hello world\n"); };
           id block21=^(void) { printf("hello world\n"); };
           id block22=^{ printf("hello world\n"); };
           id block23=^void { printf("hello world\n"); };
           
           NSLog(@"%@, %@, %@, %@", block20, block21, block22, block23);
          }
          

          可以得知如下幾個結論:

          1. `block1`和`block2`可以得知,`block`會把`nil`推斷為`void *`而不是`id`

          2. `block3`和`block4`可以得知,第一時間推斷出可以在`block expression`中指明返回類型,實際這個說法是錯誤的,前面的`(id)`是把`^{}`強制轉換為`id`的意思,而不是顯式的說這個block(`^{}`)的返回類型是`id`。

          3. `block5`,`block6`,`block7`,`block12`可以得知,只要是參數列表為`void`的時候,都可以省略,而不是文檔中描述的,還需要是推斷的返回類型(也許跟文檔一直沒有更新有關)。`block20`,`block21`,`block22`,`block23`。

          4. `block8`是驗證第三句話的。

          5. `block9`是驗證 `block`是一個對象這個結論的。

          6. `block10`和`block11`是顯式的指明一個block的返回值類型

          所以原文應該需要做如下的修改:

          第一句話,應該是把返回值(`return value`)改成返回類型(`return type`)

          第二句話,可以把`the return type is inferred and`刪除

          有一個這樣的網站:http://goshdarnblocksyntax.com/ 介紹了大部分的寫法

          現在列出如下:

          As a local variable:(Demo1)

          returnType (^blockName)(parameterTypes)=^returnType(parameters) {...};

          As a property:(Demo2)

          @property (nonatomic, copy, nullability) returnType (^blockName)(parameterTypes);

          As a method parameter:(Demo3)

          - (void)someMethodThatTakesABlock:(returnType (^nullability)(parameterTypes))blockName;

          As an argument to a method call:(Demo4)

          [someObject someMethodThatTakesABlock:^returnType (parameters) {...}];

          As a typedef:(Demo5)

          typedef returnType (^TypeName)(parameterTypes);

          TypeName blockName=^returnType(parameters) {...};

          首先我感覺還是缺少了一個例子:

          As a Type:(Demo6)

          returnType(^blockName)(parameterTypes)=(returnType(^)(parameterTypes))variable;

          即對于上面的例子例子`block8`來說就是:

          int (^block_transf8)(int)=(int(^)(int))block8;
          

          總結

          可以根據如下兩點:

          block的各種寫法樣例

          把block想象成一個函數:`returnType functionName(paramTypes) {...}`

          可以上述所有的例子歸納成如下兩種:

          在仔細看著兩個`format`就會發現,`block type`的格式跟`returnType functionName(paramTypes)`類似啊,只不過給`^`加了`()`,而`block expression` 是把`returnType`和`^`掉了個位置,去掉了`^`的括號。

          掌握了這些規矩,我覺得以后再寫有關block的時候就不需要再去查相關網站了吧。

          Blockquote 對象

          Blockquote 對象代表著一個 HTML 引用(blockquote)塊元素。

          <blockquote> 標簽定義摘自另一個源的塊引用。

          一個 <blockquote> 元素的內容通常展現為一個左、右兩邊進行縮進的段落。

          在 HTML 文檔中的每一個 <blockquote> 標簽創建時,都會創建一個 Blockquote 對象。

          Blockquote 對象屬

          屬性描述
          cite設置或返回一個引用的cite屬性值

          標準屬性和事件

          Blockquote 對象支持標準 屬性 和事件。

          如您還有不明白的可以在下面與我留言或是與我探討QQ群308855039,我們一起飛!


          主站蜘蛛池模板: www一区二区三区| 无码少妇丰满熟妇一区二区| 中文精品一区二区三区四区| 在线观看国产一区亚洲bd| 男女久久久国产一区二区三区| 日韩少妇无码一区二区三区| 精品动漫一区二区无遮挡| 国产色综合一区二区三区 | 亚洲国产成人久久一区久久| 国产高清一区二区三区| 国产丝袜美女一区二区三区| 一区二区三区亚洲视频| 精品视频一区二区| 午夜性色一区二区三区不卡视频 | 一夲道无码人妻精品一区二区| 国产在线一区二区三区av| 伊人久久大香线蕉AV一区二区| 久久精品无码一区二区WWW| 色国产精品一区在线观看| 日本一区二区免费看| 日韩一区精品视频一区二区| 国产人妖视频一区二区| 亚洲av午夜福利精品一区| 亚洲乱码一区二区三区在线观看| 在线观看国产区亚洲一区成人| 国产无套精品一区二区| 国产无线乱码一区二三区| 日韩在线不卡免费视频一区| 亚洲国产精品一区二区久| 亚洲一区二区三区亚瑟| 精品人妻无码一区二区三区蜜桃一| 久久久久人妻一区精品色| 无码人妻一区二区三区一| 亚洲AV一区二区三区四区| 婷婷亚洲综合一区二区| 久久国产精品免费一区| 激情综合丝袜美女一区二区| 亚洲av福利无码无一区二区 | 国产在线一区二区综合免费视频| 免费一区二区三区| 国产精品无码一区二区在线 |