亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

Block的引用循環問題(ARC&non-ARC)

2019-11-14 19:32:15
字體:
來源:轉載
供稿:網友

 

2010年WWDC發布iOS4時Apple對Objective-C進行了一次重要的升級:支持Block。說到底這東西就是閉包,其他高級語音例如java和C++已有支持,第一次使用Block感覺滿簡單好用的,但是慢慢也遇到很多坑。本文聊聊ARC和non-ARC下Block使用中的引用循環問題,最近遇到了好幾次這種問題,還是深入記錄下。先來套題目熱熱身,貌似能夠全部答對的人蠻少的

Block實現原理

首先探究下Block的實現原理,由于Objective-C是C語言的超集,既然OC中的NSObject對象其實是由C語言的struct+isa指針實現的,那么Block的內部實現估計也一樣,以下三篇Blog對Block的實現機制做了詳細研究:

雖然實現細節看著頭痛,不過發現Block果然是和OC中的NSObject類似,也是用struct實現出來的東西。這個是LLVM項目compiler-rt分析的block頭文Block_PRivate.h頭文件中關于Block的struct聲明:

123456789101112131415
struct Block_descriptor {    unsigned long int reserved;    unsigned long int size;    void (*copy)(void *dst, void *src);    void (*dispose)(void *);};struct Block_layout {    void *isa;    int flags;    int reserved;    void (*invoke)(void *, ...);    struct Block_descriptor *descriptor;    /* Imported variables. */};

我們發現Block_layout中也有一個isa指針,像極了NSobject內部實現struct中的isa指針。這里的isa可能指向三種類型之一的Block:

  • _NSConcreteGlobalBlock:全局類型Block,在編譯器就已經確定,直接放在代碼段__TEXT上。直接在NSLog中打印的類型為__NSGlobalBlock__。
  • _NSConcreteStackBlock:位于棧上分配的Block,即__NSStackBlock__。
  • _NSConcreteMallocBlock:位于堆上分配的Block,即__NSMallocBlock__。

為什么會有這么多種類呢?首先來看全局類型Block,看例子:

123456789101112
void addBlock(NSMutableArray *array) {  [array addObject:^{    printf("global block/n");  }];} void example() {  NSMutableArray *array = [NSMutableArray array];  addBlock(array);  void (^block)() = [array objectAtIndex:0];  block();}

為什么addBlock中添加到array中的Block屬于全局Block呢?因為它不需要運行時(Runtime)任何的狀態來改變行為,不需要放在堆上或者棧上,直接編譯后在代碼段中即可,就像個c函數一樣。這種類型的Block在ARC和non-ARC情況下沒有差別。

這個Block訪問了作用域外的變量d,在實現上就是這個block會多一個成員變量對應這個d,在賦值block時會將方法exmpale中的d變量值復制到成員變量中,從而實現訪問。

1234567
void example() {  int d = 5;  void (^block)() = ^() {      printf("%d/n", d);  };  block();}

如果要修改d呢?:

123456789
void example() {  int d = 5;  void (^block)() = ^() {      d++;      printf("%d/n", d);  };  block();  printf("%d/n", d);}

由于局部變量d和這個block的實現不在同一作用域,僅僅在調用過程中用到了值傳遞,所以不能直接修改,而需要加一個標識符__block int d = 5;,那么block就可以實現對這個局部變量的修改了。如果是這種block標識的變量,在Block實現中不再是簡單的一個成員變量,而是對應一個新的結構體表示這個block變量。block的本質是引入了一個新的Block_byref{$var_name}{$index}結構體,被block關鍵字修飾的變量就被放到這個結構體中。另外,block結構體通過引入Block_byref{$var_name}{$index}指針類型的成員,得以間接訪問到Block的外部變量。這樣對Block外的變量訪問從值傳遞轉變為引用,從而有了修改內容的能力。

正常我們使用Block是在棧上生成的,離開了棧作用域便釋放了,如果copy一個Block,那么會將這個Block copy到堆上分配,這樣就不再受棧的限制,可以隨意使用啦。例如:

1234567891011121314
typedef void (^TestBlock)(); TestBlock getBlock() {  char e = 'E';  void (^returnedBlock)() = ^{    printf("%c/n", e);  };  return returnedBlock;} void example() {  TestBlock block = getBlock();  block();}

函數getBlock中聲明并賦值的returnedBlock,一開始是在棧上分配的,屬于NSStackBlock,如果是non-ARC情況下return這個NSStackBlock,那么其實已經被銷毀了,在函數中example()使用時就會crash。如果是ARC情況下,getBlock返回的block會自動copy到堆上,那么block的類型就是NSMallocBlock,可以在example()中繼續使用。要在Non-ARC情況下正常運行,那么就應該修改為:

1234567
TestBlock getBlock() {  char e = 'E';  void (^returnedBlock)() = ^{    printf("%c/n", e);  };  return [[returnedBlock copy] autorelease];}

Block中的循環引用問題

扯了這么多,回到Block的循環引用問題,由于我們很多行為會導致Block的copy,而當Block被copy時,會對block中用到的對象產生強引用(ARC下)或者引用計數加一(non-ARC下)。

如果遇到這種情況:

123456789
@property(nonatomic, readwrite, copy) completionBlock completionBlock;//========================================self.completionBlock = ^ {        if (self.success) {            self.success(self.responseData);        }    }};

對象有一個Block屬性,然而這個Block屬性中又引用了對象的其他成員變量,那么就會對這個變量本身產生強應用,那么變量本身和他自己的Block屬性就形成了循環引用。在ARC下需要修改成這樣:

123456789
@property(nonatomic, readwrite, copy) completionBlock completionBlock;//========================================__weak typeof(self) weakSelf = self;self.completionBlock = ^ {    if (weakSelf.success) {        weakSelf.success(weakSelf.responseData);    }};

也就是生成一個對自身對象的弱引用,如果是倒霉催的項目還需要支持iOS4.3,就用__unsafe_unretained替代__weak。如果是non-ARC環境下就將__weak替換為__block即可。non-ARC情況下,__block變量的含義是在Block中引入一個新的結構體成員變量指向這個__block變量,那么__block typeof(self) weakSelf = self;就表示Block別再對self對象retain啦,這就打破了循環引用。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩黄在线观看| 日韩在线播放视频| 国产91在线播放| 亚洲国产精品福利| 亚洲精品动漫100p| 亚洲影视九九影院在线观看| 亚洲国产毛片完整版| 亚洲国产欧美自拍| 亚洲成av人影院在线观看| 欧美激情在线观看| 国产日韩精品在线| 2019最新中文字幕| 成人午夜一级二级三级| 国产精品永久免费| 国产精品爽黄69天堂a| 国产精品视频色| 欧美亚洲国产另类| 亚洲欧洲日产国产网站| 欧美大成色www永久网站婷| 亚洲欧洲偷拍精品| 欧美激情极品视频| 国产精品成熟老女人| 日韩欧美a级成人黄色| 韩国日本不卡在线| 91精品久久久久| 国产精品99久久久久久久久| 欧美寡妇偷汉性猛交| 国产精品91久久久久久| 亚洲香蕉成人av网站在线观看| 国内精品视频在线| 在线视频一区二区| 国产在线98福利播放视频| 国产精品99一区| 亚洲欧美激情视频| 欧美精品在线观看91| 国产精品一区二区三区免费视频| 亚州成人av在线| 欧美午夜丰满在线18影院| 欧美日韩国产第一页| 国产精品免费久久久久影院| 综合av色偷偷网| 国精产品一区一区三区有限在线| 国产精品久久久久免费a∨| 日韩美女免费线视频| 美女视频黄免费的亚洲男人天堂| 在线视频欧美日韩精品| 亚洲精品一区二区久| 亚洲人成人99网站| 91在线观看免费高清完整版在线观看| 久久久在线视频| 欧美日韩福利视频| 亚洲二区在线播放视频| 日韩高清有码在线| 91麻豆国产精品| 亚洲国产97在线精品一区| 久久视频这里只有精品| 丝袜亚洲欧美日韩综合| 国产精品福利网站| 91九色视频导航| 最近2019中文字幕mv免费看| 亚洲日韩中文字幕| 日韩成人高清在线| 欧美成人精品在线视频| 日韩av在线免费观看| 青青草国产精品一区二区| 中文字幕国产精品| 91免费福利视频| 精品亚洲男同gayvideo网站| 精品久久久久久久久久久久| 欧美大片在线影院| 91精品国产九九九久久久亚洲| 亚洲人av在线影院| 亚洲网在线观看| 日韩成人av在线播放| 久久久久久久激情视频| 97色在线观看| 91精品久久久久久| 亚洲字幕一区二区| 国产精品99久久久久久久久| 久久国产天堂福利天堂| 欧美视频一二三| 亚洲乱码国产乱码精品精天堂| 欧美精品免费在线| 欧美最猛黑人xxxx黑人猛叫黄| 久久国产精品99国产精| 国产精品亚洲自拍| 国产精品第三页| 国产精品h在线观看| 伦伦影院午夜日韩欧美限制| 日韩在线视频中文字幕| 亚洲影院污污.| 中文字幕亚洲字幕| 国产91精品网站| 97久久精品人人澡人人爽缅北| 91国产视频在线| 国产一区二区三区直播精品电影| 久99久在线视频| 疯狂蹂躏欧美一区二区精品| 亚洲欧美视频在线| 亚洲欧洲自拍偷拍| 亚洲国产91精品在线观看| 国产精品户外野外| 伊是香蕉大人久久| 国产拍精品一二三| 国产精品色视频| 国产精品精品久久久久久| 久久视频中文字幕| 亚洲最大的免费| 成人黄色免费网站在线观看| 亚洲色图狂野欧美| 一本一本久久a久久精品牛牛影视| 日韩电视剧在线观看免费网站| 日产日韩在线亚洲欧美| 久久深夜福利免费观看| 久久久精品电影| 国产日韩在线观看av| 国产精品入口日韩视频大尺度| 精品国产视频在线| 中文字幕亚洲一区二区三区| 亚洲国产欧美精品| 亚洲www在线观看| 中文字幕自拍vr一区二区三区| 精品欧美国产一区二区三区| 在线精品91av| 久久精品在线播放| 成人黄色生活片| 国产不卡在线观看| 日韩av影片在线观看| 亚洲福利在线看| 97在线免费观看| 国内精品久久久久久久| 国产成人精品在线观看| 久久久久久久网站| 久久综合国产精品台湾中文娱乐网| 国产美女久久精品香蕉69| 国产精品黄色影片导航在线观看| 丝袜情趣国产精品| 精品久久中文字幕| 午夜精品久久久久久99热| 成人妇女免费播放久久久| 欧美国产日本高清在线| 一区二区亚洲精品国产| 91老司机精品视频| 精品日韩视频在线观看| 日韩精品免费观看| 日韩欧美亚洲成人| 久久综合电影一区| 91av免费观看91av精品在线| 亚洲欧美国产精品| 日韩毛片在线观看| 国产亚洲人成网站在线观看| 亚洲国产97在线精品一区| 午夜精品久久久久久久99热| 欧美高清激情视频| 欧美成人在线影院| 中文字幕日韩免费视频| 国产精品一区二区三| 欧美日韩亚洲一区二| 国产91在线高潮白浆在线观看| 国产精品香蕉在线观看| 国产91久久婷婷一区二区| 中文字幕欧美日韩va免费视频| 国产精品一区二区久久精品| 亚洲精品国产精品久久清纯直播|