日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

长路漫漫,唯剑作伴--Automatic Reference Counting

發布時間:2023/12/18 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 长路漫漫,唯剑作伴--Automatic Reference Counting 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、引用計數

  • 在OC中,對象什么時候會被釋放?

    • 答案是當對象沒有被任何變量引用(也可以說是沒有指針指向該對象)的時候,就會被釋放。
  • 怎么知道對象已經沒有被引用了呢?

    • OC采用引用計數(reference counting)的技術來進行管理:

      • 每個對象都有一個關聯的整數,稱為引用計數器

      • 當代碼需要使用該對象時,則將對象的引用計數加1

      • 當代碼結束使用該對象時,則將對象的引用計數減1

      • 當引用計數的值變為0時,表示對象沒有被任何代碼使用,此時對象將被釋放。

    • 內存管理的思考方式:

      • 自己創建的對象自己管理。

      • 不是自己創建的對象,自己也能持有。

      • 不再需要自己持有的對象時,釋放。

      • 不是自己持有的對象,不能釋放。

      • 總結一句話就是:誰創建,誰釋放,誰持有,誰管理

    • 與之對應的消息發送方法如下:

      • 增加引用計數:alloc、new、copy、mutableCopy(此為生成),retain(此為持有對象)

      • 減少引用計數:release(此為釋放對象)

      • 釋放dealloc(此為廢棄對象)

    • 下面通過一個簡單的例子說明:

      • 新建Dog類,重寫其創建和銷毀的方法:

        @implementation Dog- (instancetype)init {if (self = [super init]) {NSLog(@"小狗被派出去啦!初始引用計數為 %ld",self.retainCount);}return self;}- (void)dealloc {NSLog(@"小狗回到寵物中心");[super dealloc];} @end
      • 在main方法中創建dog對象,給dog發送消息:

        //模擬:寵物中心派出小狗 Dog * dog = [[Dog alloc]init]; //模擬:xiaoming需要和小狗玩耍,需要將其引用計數加1 [dog retain]; NSLog(@"小狗的引用計數為 %ld",dog.retainCount); //模擬:xiaoming不和小狗玩耍了,需要將其引用計數減1 [dog release]; NSLog(@"小狗的引用計數為 %ld",dog.retainCount); //沒人需要和小狗玩耍了,將其引用計數減1 [dog release]; //將指針置nil,否則變為野指針 dog = nil;
      • 輸出結果為:

        [34691:7638855] 初始引用計數為 1 [34691:7638855] 小狗的引用計數為 2 [34691:7638855] 小狗的引用計數為 1 [34691:7638855] 銷毀Dog
      • 可以看到,引用計數幫助寵物中心很好的標記了小狗的使用狀態,在完成任務的時候及時收回到寵物中心。

    • 思考幾個問題:

      • NSString引用計數問題:

        NSString * str = @"hello guys"; NSLog(@"%ld", str.retainCount); // 會發現引用計數為-1,這可以理解為NSString實際上是一個字符串常量,是沒有引用計數的(或者它的引用計數是一個很大的值(使用%lu可以打印查看),對它做引用計數操作沒實質上的影響)。
      • 賦值不會擁有某個對象:

        NSString * name = dog.name; // 這里僅僅是指針賦值操作,并不會增加name的引用計數,需要持有對象必須要發送retain消息。
      • dealloc:

        • 由于釋放對象是會調用dealloc方法,因此重寫dealloc方法來查看對象釋放的情況,如果沒有調用則會造成內存泄露。在上面的例子中我們通過重寫dealloc讓小狗被釋放的時候打印日志來告訴我們已經完成釋放。

      • 在上面例子中,如果我們增加這樣一個操作:

        //沒人需要和小狗玩耍了,將其引用計數減1 [dog release]; NSLog(@"%ld",dog.retainCount); // 會發現獲取到的引用計數為1,為什么不是0呢? // 這是因為對引用計數為1的對象release時,系統知道該對象將被回收,就不會再對該對象的引用計數進行減1操作,這樣可以增加對象回收的效率。
  • ?二、自動釋放池

  • 思考

    • 現在已經明確了,當不再使用一個對象時應該將其釋放,但是在某些情況下,我們很難理清一個對象什么時候不再使用(比如xiaoming和小狗玩耍結束的時間不確定),這可怎么辦?

    • ObjC提供autorelease方法來解決這個問題,當給一個對象發送autorelease消息時,方法會在未來某個時間給這個對象發送release消息將其釋放,在這個時間段內,對象還是可以使用的。

  • 那autorelease的原理是什么呢?

    • 原理就是對象接收到autorelease消息時,它會被添加到了當前的自動釋放池中,當自動釋放池被銷毀時,會給池里所有的對象發送release消息。

  • 創建

    • 方法一:使用NSAutoreleasePool來創建

      NSAutoreleasePool * pool = [[NSAutoreleasePool alloc]init]; //這里寫代碼 [pool release];
    • 方法二:使用@autoreleasepool創建

      @autoreleasepool {//這里寫代碼 }
    • 自動釋放池創建后,就會成為活動的池子,釋放池子后,池子將釋放其所包含的所有對象。

    • 以上兩種方法推薦第一種,因為將內存交給ObjC管理更高效。

    • 自動釋放池什么時候創建?

      • app使用過程中,會定期自動生成和銷毀自動釋放池,一般是在程序事件處理之前創建,當然我們也可以自行創建自動釋放池,來達到我們一些特定的目的。

    • 自動釋放池什么時候銷毀?

      • 自動釋放池的銷毀時間是確定的,一般是在程序事件處理之后釋放,或者由我們自己手動釋放。

  • 下面舉例說明自動釋放池的工作流程:

    • 代碼

      //創建一個自動釋放池 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; //模擬:寵物中心派出小狗 Dog * dog = [[Dog alloc]init]; //模擬:xiaoming需要和小狗玩耍,需要將其引用計數加1 [dog retain]; NSLog(@"小狗的引用計數為 %ld",dog.retainCount); //模擬:xiaohong需要和小狗玩耍,需要將其引用計數加1 [dog retain]; NSLog(@"小狗的引用計數為 %ld",dog.retainCount); //模擬:xiaoming確定不想和小狗玩耍了,需要將其引用計數減1 [dog release]; NSLog(@"小狗的引用計數為 %ld",dog.retainCount); //模擬:xiaohong不確定何時不想和小狗玩耍了,將其設置為自動釋放 [dog autorelease]; NSLog(@"小狗的引用計數為 %ld",dog.retainCount); //沒人需要和小狗玩耍了,將其引用計數減1 [dog release]; NSLog(@"釋放池子"); [pool release]; //創建一個自動釋放池 @autoreleasepool {//模擬:寵物中心派出小狗Dog * dog = [[Dog alloc]init];//模擬:xiaoming需要和小狗玩耍,需要將其引用計數加1 [dog retain];NSLog(@"小狗的引用計數為 %ld",dog.retainCount);//模擬:xiaohong需要和小狗玩耍,需要將其引用計數加1 [dog retain];NSLog(@"小狗的引用計數為 %ld",dog.retainCount);//模擬:xiaoming確定不想和小狗玩耍了,需要將其引用計數減1 [dog release];NSLog(@"小狗的引用計數為 %ld",dog.retainCount);//模擬:xiaohong不確定何時不想和小狗玩耍了,將其設置為自動釋放 [dog autorelease];NSLog(@"小狗的引用計數為 %ld",dog.retainCount);//沒人需要和小狗玩耍了,將其引用計數減1 [dog release];NSLog(@"釋放池子"); }
    • 結果

      [34819:7801589] 初始引用計數為 1 [34819:7801589] 小狗的引用計數為 2 [34819:7801589] 小狗的引用計數為 3 [34819:7801589] 小狗的引用計數為 2 [34819:7801589] 小狗的引用計數為 2 [34819:7801589] 釋放池子 [34819:7801589] 銷毀Dog // 可以看到,當池子釋放后,dog對象才被釋放,因此在池子釋放之前,xiaohong都可以盡情地和小狗玩耍。
  • 使用自動釋放池需要注意:

    • 自動釋放池實質上只是在釋放的時候給池中所有對象對象發送release消息,不保證對象一定會銷毀,如果自動釋放池向對象發送release消息后對象的引用計數仍大于1,對象就無法銷毀。

    • 自動釋放池中的對象會集中同一時間釋放,如果操作需要生成的對象較多占用內存空間大,可以使用多個釋放池來進行優化。比如在一個循環中需要創建大量的臨時變量,可以創建內部的池子來降低內存占用峰值。

    • autorelease不會改變對象的引用計數。

  • 自動釋放池的常見問題

    • 在管理對象釋放的問題上,自動幫助我們釋放池節省了大量的時間,但是有時候它卻未必會達到我們期望的效果,比如在一個循環事件中,如果循環次數較大或者事件處理占用內存較大,就會導致內存占用不斷增長,可能會導致不希望看到的后果。

    • 示例代碼:

      for (int i = 0; i < 100000; i ++) {NSString * log = [NSString stringWithFormat:@"%d", i];NSLog(@"%@", log); }
    • 前面講過,自動釋放池的釋放時間是確定的,這個例子中自動釋放池會在循環事件結束時釋放,那問題來了:在這個十萬次的循環中,每次都會生成一個字符串并打印,這些字符串對象都放在池子中并直到循環結束才會釋放,因此在循環期間內存不增長。

    • 這類問題的解決方案是在循環中創建新的自動釋放池,多少個循環釋放一次由我們自行決定。

      for (int i = 0; i < 100000; i ++) {@autoreleasepool {NSString * log = [NSString stringWithFormat:@"%d", i];NSLog(@"%@", log);} }
  • 被autorelease處理過的對象的釋放時機

    • autorelease并不是根據作用域來決定釋放時機的,而是Runloop。當一個runloop結束時系統才會一次性清理掉被autorelease處理過的對象,其實本質上說是在本次runloop迭代結束時清理掉被本次迭代期間被放到autorelease pool中的對象的。至于何時runloop結束并沒有固定的duration!

  • ?

    三、ARC

  • 簡介

    • ARC,自動引用計數,是指iOS的內存管理使用引用計數的技術。

    • 在OC中采用Automatic Reference Counting的機制,讓編譯器進行內存管理。在新一代的Apple LLVM編譯器中設置ARC為有效狀態,就不用再次鍵入retain、release代碼,這在降低程序崩潰、內存泄漏等風險的同時,很大程度上減少了開發程序的工作量。編譯器完全清楚目標對象,并能立刻釋放那些不再被使用的對象(有待斟酌)。如此一來,應用程序將具有可預測性,且運行流暢,速度也將大幅提升。(摘自蘋果官方文檔說明)

  • ARC修飾符

    • __strong:強引用,持有所指向對象的所有權,無修飾符情況下的默認值。如需強制釋放,可置nil。

      • 比如我們常用的定時器:NSTimer?*?timer?=?[NSTimer?timerWith...];

      • 相當于NSTimer?*?__strong?timer?=?[NSTimer?timerWith...];

      • 當不需要使用時,強制銷毀定時器:[timer?invalidate];timer?=?nil;

    • __weak:弱引用,不持有所指向對象的所有權,引用指向的對象內存被回收之后,引用本身會置nil,避免野指針。

      • __weak?__typeof(self)?weakSelf?=?self;

    • __autoreleasing:自動釋放對象的引用,一般用于傳遞參數

    • __unsafe_unretained:為兼容iOS5以下版本的產物,可以理解成MRC下的weak,現在基本用不到,這里不作描述

    • 使用__autoreleasing可能會遇到哪些問題?

    • 使用修飾符的正確姿勢

      NSString * __weak str = @"hehe"; // 正確! __weak NSString *str = @"hehe"; // 錯誤!// 我相信很多人都和我一樣,從開始用ARC就一直用上面那種錯誤的寫法。 // 那這里就有疑問了,既然文檔說是錯誤的,為啥編譯器不報錯呢?好吧,是蘋果考慮到很多人會用錯,所以在編譯器這邊貼心地幫我們忽略并處理掉了這個錯誤:) // 雖然不報錯,但是我們還是應該按照正確的方式去使用這些修飾符 // 如果你以前也常常用錯誤的寫法,那看到這里記得以后不要這么寫了,哪天編譯器怒了,再不支持錯誤的寫法,就要郁悶了。 // (參見蘋果官方文檔)
  • sasf
  • ?

    ?

    ?

    ?

    ?

    ?

    轉載于:https://www.cnblogs.com/zhuyiios/p/6710190.html

    總結

    以上是生活随笔為你收集整理的长路漫漫,唯剑作伴--Automatic Reference Counting的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 国产一级性生活 | 草草影院地址 | 国产精品啪 | 国产成人aaaa | 韩国伦理片在线观看 | 日韩在线三区 | 欧美另类第一页 | 国产精品av免费观看 | caoporn视频在线观看 | 日本不卡一区二区三区视频 | 亚洲一区二区三区四区不卡 | 亚洲精品一品 | 国产探花视频在线观看 | 国产欧美一区二区三区视频在线观看 | 国产成人精品av在线观 | 久久天 | 色久阁 | 国产成人小视频在线观看 | 日韩制服在线 | 丁香综合 | 在线中文字幕日韩 | 国av在线| 婷婷综合精品 | 中国女人一级一次看片 | 亚洲天堂第一区 | 美女被草 | 26uuu国产精品视频 | 这里只有精品在线观看 | 午夜激情福利电影 | 亚洲一区无 | 农村搞破鞋视频大全 | 18国产免费视频 | 欧美日韩麻豆 | 538国产精品一区二区免费视频 | 天天操夜夜添 | 亚洲精品福利在线 | 成人久久av | 日韩高清欧美 | 国产成人无码精品 | 正在播放adn156松下纱荣子 | 国产在线播放一区二区 | 91高跟黑色丝袜呻吟在线观看 | www,av在线| 亚洲情趣 | 色很久| 二区三区av | 久久com | 国产亚洲精品久久久久久打不开 | 黄色小毛片 | av女优天堂网 | 中国少妇做爰全过程毛片 | 精品中文字幕一区二区 | 91精品国产91久久久久久吃药 | 深夜福利影院 | 成人片黄网站色大片免费毛片 | 中文字幕日韩高清 | 国产污污 | 动漫美女被到爽流 | 二区三区在线观看 | 久久黄色av | 日韩毛片在线看 | 大胸美女吻戏 | 精品人伦一区二区三 | 日穴视频 | 亚洲成av人片在www色猫咪 | 看片地址 | 黄色二级视频 | 国产精品影院在线观看 | 黄色日韩视频 | 交做爰xxxⅹ性爽 | 欧美三级一级 | 成人片在线视频 | 亚洲春色av | 一级片av | 男女靠逼视频 | 国产欧美日韩成人 | 中文字幕在线高清 | 91国产视频在线播放 | 国产乱视频 | 日韩人妻一区二区三区蜜桃 | 国产精品福利一区 | www.四色| 美女脱了裤子让男人桶 | 成人av电影在线播放 | 久操国产| 久久精品10 | 色香蕉在线 | 国产成人精品123区免费视频 | 夜夜cao| 国产精品国语对白 | 稀缺呦国内精品呦 | 免费成人在线看 | 国产在线最新 | 久久精品无码一区二区三区毛片 | 国产美女精品视频 | 欧美日韩免费看 | 国产99999| 四虎精品永久在线 | 国产精品久久久av |