講述Sagit.Framework解決:雙向引用導致的IOS記憶體泄漏(上)

来源:https://www.cnblogs.com/cyq1162/archive/2018/01/05/8195220.html
-Advertisement-
Play Games

今天不寫教程,和大伙分享一下IOS在記憶體泄漏方面的文章..... ...


前言:

好久沒寫文章了,最近先是重構IT戀、又重寫IT戀中。

Sagit框架也不斷的更新,調整,現在感覺已完美了了相當的多。

今天不寫教程,先簡單分享一下技術內容。

1:見Block必有:#define WeakSelf __weak typeof(self) this = self;

 故事要從這這裡說起:

當初番完這代碼後,發現到處都有這個鬼東西,然後就去百度了一下,然後大意是為了:

解決雙向引用導致的記憶體無法釋放問題

簡單的表述如下:

self   強引用指向=》block;

block 也強引用批向=>self;

這時候就出事了,解決的方法是,把其中一個改成弱指向。

而WeakSelf的定義,就是讓block改成弱引用,這樣無論self是不是強引用的指向block都無關緊要了。

當然,更精緻的做法是:先預判self有沒有強引用指向block,沒有,就不用WeakSelf定義了。

不過,一般新手搞不明白內涵,無法做出有效的預判,所以見block就有WeakSelf也就相隨相生了。

2:其它場景的雙向引用:UIViewController與UIView的糾纏

 首先,預設UIViewController有一個強引用指向了UIView,這是系統定義的,我們改不了:

所以,如果UIView里再出現strong或retain指回UIController,就會導致UIViewController和UIView雙雙無法釋放問題。

這個問題,在我剛寫Sagit框架時,只在意功能,沒在意這些,就犯了這個錯誤:

錯誤的寫法是這樣的:

現在改正後的寫法是這樣的:

3:事情沒有這麼簡單:UIView子控制項綁定事件指向Controller

看一行Sagit的代碼,關註後面的addClick:

[[[[sagit addButton:@"Login" title:@"登錄" font:40] width:450 height:80] onBottom:@"pwdLine" y:149] addClick:@"loginClick"];

對於事件流程關於Sagit的前面幾篇有說了,這裡說一下框架的流程代碼:

1:系統自動添加了一個UITapGestureRecognizer,並指定到一個固定的click方法;

2:將方法名稱和target存到自身的NSDictionary的字典中(框架為每個UIView都擴展了一個Dictionary)(就是這裡造成強引用了Controller).

3:事件點擊時:先觸發系統預設的click,然後click事件:從字典里取出方法名和target,找到SEL並動態執行。

PS:設計成動態執行的好處:可以在執行前處理一些其它事情:比如將addClick參數:loginClick改成AgeButton.click,這樣可以分解參數後,去執行AgeButton上的事件

執行的代碼是這樣的,由於是動態執行,少不了還有一個警告:

接下來,就是怎麼消滅事件里對Controller的強引用:

1:找了資料,發現有個NSMapTable,是弱引用的字典,於是把NSDictionary換成它,結果:參不忍睹,界面錯亂。【大概是弱引用特別容易丟失數據】 
2:嘗試用一個全局的第三方的字典來存,結果也悲哀了! 3:最後想到了一個方法,不直接存Controller,只存字元串:1和0 ,在最終執行的時候,再去找。

代碼是這樣的:

真難為我這麼聰明,想著大功告成,運行,釋放了,成功了!!!

然後又悲哀了:

然後就動不動就到main含數了,讓我怎麼猜?說好的全局斷點呢?你咋不斷呢?

搜了搜百度,想想要調度記憶體,那就一個蛋騰,還是靠猜吧。

後來,根據釋放的順序,和最後的關鍵字,大概是這樣猜的:

控制器被釋放了,這時候UIView還沒釋放,然後系統又給UIView綁字的事件發消息,結果遇到野指針,悲傷的故事發生了。

於是,我做了一個艱難的決定,在UIController的deallow中寫了這樣的代碼:

-(void)dealloc
{
    [self.view removeAllsubViews];//處理記憶體釋放後的異常。
    NSLog(@"%@ ->UIViewControlelr relase", [self class]);
}

這執行dealloc前,畢竟Controller還是活著的,這時候趕緊把UIView的東西給清了,然後,發現完美,運行起來很6!

總結:

當我很6的解決完上述問題後,就開始寫文章了想分享一下了,然後寫了開頭,發現:

咦,好像UITableView和UITableViewCell,好像也有雙向引用問題。

因為我給Cell加了個屬性,指向Table,運行,果然,Shit,連Controller和父的UIView都釋放了,你UITableView做為子UI居然不釋放!!!!

沒天理,繼續折騰,然後UITableView搞釋放了,又發現UITableViewCell不釋放了(這個Cell通常又會是一大堆UI)。

再然後,發現Push兩層回來,又掛Crash了。

現在正在全力搶救!!!解決完再來寫下篇!!!

 

操,發現為了釋放那點記憶體的代價,折騰起來真慘過不釋放算了〜〜〜〜


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Linux下簡單好用的工具rinetd,實現埠映射/轉發/重定向官網地址http://www.boutell.com/rinetd 軟體下載wget http://www.boutell.com/rinetd/http/rinetd.tar.gz 解壓安裝tar zxvf rinetd.tar.g ...
  • 1、伺服器Git安裝配置 相關鏈接 相關鏈接 註意ssh-keygen 、修改許可權 許可權: 相關鏈接 2、本地獲取 git clone name@ip:伺服器項目位置 相關鏈接 3、創建本地分支推送到遠程 git branch name git push origin name 3.1 伺服器許可權配 ...
  • linker文件是在鏈接階段所要用到的文件,source文件在編譯過程完成之後,需要再經過鏈接器從而將二進位數據有序組織起來形成最終的二進位可執行文件,linker文件就是用來指示鏈接器如何組織編譯生成的二進位數據。 ...
  • 知識點: 1-MongoDB 安裝,啟動和卸載 2-基本概念 3-基本的增刪改查操作(CURD) 來回顧總結一把學習的mongodb,如果有javascript基礎,學習"芒果DB"還是很好理解的,如果會使用mysql,那就更容易了。 mongodb是一個介於nosql資料庫和mysql資料庫之間的 ...
  • 最近在處理一個分表的問題時,需要為程式創建一個自動分表的存儲過程,需要保證所有表結構,約束,索引等等一致,此外視圖,存儲過程,許可權等等問題暫不用考慮。 在Mysql中,創建分表的存儲過程,相當簡單:create table if not exists <new_table_name> like <o ...
  • 本博文介紹了Group Replication的兩種工作模式的架構。 並詳細介紹了Single-Master Mode的部署過程,以及如何切換到Multi-Master Mode。 當然,文末給出了Group Replication的配置要求和一些限制。 〇 結構介紹 在2016年12月發佈的5.7 ...
  • 背景 假如我們有關鍵數據存儲在一個表裡面,比如人員表中包含員工、部門和薪水信息。只允許用戶訪問各自部門的信息,但是不能訪問其他部門。一般我們都是在程式端實現這個功能,而在sqlserver2016以後也可以直接在資料庫端實現這個功能。 解決 安全已經是一個數據方面的核心問題,每一代的MS資料庫都有關 ...
  • 智慧城市時空大數據與雲平臺建設技術大綱(2017年8月版) ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...