1. 程式人生 > >小胖說swift07-------- swift協議代理的使用以及解決迴圈引用問題

小胖說swift07-------- swift協議代理的使用以及解決迴圈引用問題

這兩天看了一下Swift的協議代理, 大體思路和OC沒什麼區別, 但是按照官方的書本寫出的協議代理, 發現會有記憶體洩露問題, 找了半天沒有發現問題, 突然想起看系統類的協議代理的寫法, 瞬間發現了問題, 不多廢話了, 下面是程式碼. 

我建了一個single View application, 為了驗證記憶體洩露, 我保留了xcode所給的viewController.swift,在storyboard中viewController前添加了一個navigationController, 並且自己建了兩個檢視控制器: VC1.swift 和 VC2.swift, 由viewController 跳轉至 VC1, 在VC1中設定delegate, 再跳轉到VC2, 讓VC2改變VC1的背景顏色, 然後一直返回到viewController, 看VC1 和 VC2 是否釋放了記憶體; 

下面是我的viewController裡的程式碼:

//
//  ViewController.swift
//  protocolTest
//
//  Created by XXX on 16/8/26.
//  Copyright © 2015年 V1. All rights reserved.
//

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.title = "viewController"

        //例項化一個button, 新增點選事件
        let button = UIButton(type: UIButtonType.Custom)
        button.backgroundColor = UIColor.redColor()
        button.setTitle("點選跳轉到VC1", forState: UIControlState.Normal)
        button.frame = CGRectMake(100, 100, 150, 100)
        button.addTarget(self, action: "buttonClicked", forControlEvents: UIControlEvents.TouchUpInside)
        self.view.addSubview(button)
    }

    //跳轉到VC1
    func buttonClicked(){
        let vc_1 = VC1()
        self.navigationController?.pushViewController(vc_1, animated: true)
    }
}

這下面是VC1 中的程式碼:
//
//  VC1.swift
//  protocolTest
//
//  Created by XXX on 16/8/26.
//  Copyright © 2015年 V1. All rights reserved.
//

import UIKit

// VC1 遵守changeColor協議, 並且實現協議中的方法
class VC1: UIViewController, changeColor{

    var vc_2: VC2?   //定義一個VC2變數

    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = UIColor.orangeColor()
        self.title = "VC1"

        //例項化VC2, 並且設定delegate
        vc_2 = VC2()
        vc_2?.delegate = self

        let button = UIButton(type: UIButtonType.Custom)
        button.backgroundColor = UIColor.whiteColor()
        button.setTitle("點選跳轉到VC2", forState: UIControlState.Normal)
        button.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal)
        button.frame = CGRectMake(100, 100, 150, 100)
        button.addTarget(self, action: "VC1buttonClicked", forControlEvents: UIControlEvents.TouchUpInside)
        self.view.addSubview(button)
    }

    //跳轉到VC2
    func VC1buttonClicked(){
        self.navigationController?.pushViewController(vc_2!, animated: true)
    }

    //實現協議中的方法
    func changeColorWithColor(color color: UIColor) {
        self.view.backgroundColor = color
    }

    deinit{
        print("vc_1 的記憶體已釋放 !")
    }
}

下面是我的VC2中的程式碼:
//
//  VC2.swift
//  protocolTest
//
//  Created by XXXX on 16/8/26.
//  Copyright © 2015年 V1. All rights reserved.
//

import UIKit

//宣告一個協議, 讓其繼承(我也不知道該不該叫繼承, 然而在這裡並不重要) NSObjectProtocol, 只有這樣才能在設定代理的時候前面新增weak
protocol changeColor: NSObjectProtocol {
    func changeColorWithColor(color color: UIColor)
}

class VC2: UIViewController {

    //注意這裡: changeColor為協議名, delegate前面必須有weak修飾, 如果沒有weak修飾就會造成記憶體洩露, 而可以加weak的前提是, 這個協議必須繼承 NSObjectProtocol, 這是我試驗出來的, 目前來看, 應該是這樣的
    weak var delegate: changeColor?

    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = UIColor.whiteColor()
        self.title = "VC2"

        let button = UIButton(type: UIButtonType.Custom)
        button.backgroundColor = UIColor.redColor()
        button.setTitle("點選改變VC1的背景顏色", forState: UIControlState.Normal)
        button.frame = CGRectMake(100, 100, 200, 100)
        button.addTarget(self, action: "VC1buttonClicked", forControlEvents: UIControlEvents.TouchUpInside)
        self.view.addSubview(button)
    }

    func VC1buttonClicked(){
        //使用代理呼叫協議宣告並且VC1已經實現的方法
        self.delegate?.changeColorWithColor(color: UIColor.cyanColor())
    }

    deinit{
        print("vc_2的記憶體已經釋放 !")
    }
}

下面是返回至viewController後的列印資訊:
/*
vc_1 的記憶體已釋放 !
vc_2的記憶體已釋放 !
*/

最重要的程式碼片段為:

//注意這裡: changeColor為協議名, delegate前面必須有weak修飾, 如果沒有weak修飾就會造成記憶體洩露, 而可以加weak的前提是, 這個協議必須繼承 NSObjectProtocol, 這是我試驗出來的, 目前來看, 應該是這樣的

weak var delegate: changeColor?