iOS:如何用 Swift 實現弱代理
</div>
有一個常見的場景:一個 ViewController 控制多個 View ,并且想在 ViewController 中代理 View 的一些邏輯。
例如,你有一個 View,其中包含一個按鈕(比如在表單中的「注冊」),并且當用戶點擊這個注冊按鈕時,你希望代理其中的邏輯(比如注冊驗證和調用 API)。
你的代碼應該會是這樣的:
// 代理點擊的協議 protocol ButtonDelegate { func onButtonTap(sender: UIButton) } class ViewWithTextAndButton: UIView { // 保存代理,后面使用 var delegate: ButtonDelegate? func onButtonTap(sender: UIButton) { // 按鈕被點擊的時候調用代理 delegate?.onButtonTap(sender) } } class MyViewController: UIViewController, ButtonDelegate { let viewWithTextAndButton = ViewWithTextAndButton(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) override func viewDidLoad() { super.viewDidLoad() // 給代理賦值 viewWithTextAndButton.delegate = self view.addSubview(viewWithTextAndButton) } // MARK: ButtonDelegate // 實現代理邏輯 func onButtonTap(sender: UIButton) { print("This button was clicked in the subview!") } }
</div>
但是這里還有一個很大的問題!因為 View 作為 delegate 對 ViewController 是強引用,同時 ViewController 對 View 也是強引用,這就出現了循環引用。ViewController 引用著 View,并且 View 引用著 ViewController,兩者的引用計數都不會變成 0,所以它們都不會被銷毀,從而造成內存泄露。
解決辦法就是讓其中一個對另一個保持弱引用!在 Swift 中怎么做呢?可以添加 class 關鍵字來約束協議,讓它只能被引用類型的數據(也就是類)使用:
// 協議只能被類使用! protocol ButtonDelegate: class { func onButtonTap(sender: UIButton) }
</div>
接下來,我們可以使得我們的代理被弱引用:
class ViewWithTextAndButton: UIView { // 注意,現在我們可以使用 weak 關鍵字! // 這個變量只能指向引用類型(UIViewController) // 并且是弱引用 weak var delegate: ButtonDelegate? func onButtonTap(sender: UIButton) { delegate?.onButtonTap(sender) } }
</div>
就是這樣!
這個例子很好地說明了為什么應該使用值類型——值類型可以很好的避免循環引用。使用值類型時值會被拷貝,所以不會出現上述的內存泄露問題。不過呢,我們又不得不和包含大量子類(UIView 和 UIViewController 的關系)的 Cocoa 框架打交道,所以你需要約束協議。
本文由 SwiftGG 翻譯組翻譯,已經獲得作者翻譯授權,最新文章請訪問http://swift.gg。
</div> </div>
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!