swift:取消绑定侦听器,这些侦听器是侦听器数组的闭包

时间:2018-02-10 09:27:46

标签: ios swift binding

我正在尝试开发一个主题引擎,它从json加载主题。我有Thememanager这是singleton类,并且拥有currentTheme变量。 然后我有baseViewControllercurrentTheme技术的帮助下监听Boxing中的任何更改,并且所有viewControllers都需要是子类的 base需要override observer方法来应用他们的样式。在box类中,我有一个listeners数组,以便多个视图控制器可以同时观察主题更改,它运行良好,现在 我的问题是,每当一个视图控制器获得deallocated时,我想从侦听器的盒子类数组中删除该侦听器,我无法弄清楚,因为哪些侦听器被堆积起来。

我尝试在viewController的deint中编写一个unbind方法,并试图像下面那样传递闭包,但它没有工作

func unbind(listener: Listener?) {

    self.listeners = self.listeners.filter { $0 as AnyObject !== listener as AnyObject }

}

Thememanager

class Thememanager {

    // Hold a list of themes
    var themes = [Theme]()
    // Private Init
    private init() {

        fetchMenuItemsFromJSON()
        // You can provide a default theme here.
        //change(theme: defaultTheme)
    }

    // MARK: Shared Instance

    private static let _shared = Thememanager()

    // MARK: - Accessors
    class func shared() -> Thememanager {
        return _shared
    }

    var currentTheme: Box<Theme?> = Box(nil)

    func change(theme: Theme) {

        currentTheme.value = theme
    }

    private func fetchMenuItemsFromJSON() {

        // TRIAL
        let theme = Theme()
        themes.append(theme)
    }
}

BOX

class Box<T> {

    typealias Listener = (T) -> Void
    var listeners = [Listener?]()

    var value: T {

        didSet {
            for listener in listeners{
                listener?(value)
            }
        }
    }

    init(_ value: T) {
        self.value = value
    }

    func bind(listener: Listener?) {

        self.listeners.append(listener)
        for listener in listeners{
            listener?(value)
        }
    }

    func unbind(listener: Listener?) {

        self.listeners = self.listeners.filter { $0 as AnyObject !== listener as AnyObject }

    }

}

BaseViewController

class BaseViewController: UIViewController {

    private var themeManager = Thememanager.shared()
    typealias Listener = (Theme?) -> Void
    var currentListener: Listener?
    override func viewDidLoad() {
        super.viewDidLoad()
        observeThemeChange()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // Bind the theme variable so that changes are immediately effective
    func observeThemeChange() {
        currentListener = {[weak self] (theme) in
            guard let currtheme = theme else {
                return
            }
            self?.loadWith(theme: currtheme)
        }
        themeManager.currentTheme.bind(listener: currentListener)
    }

    // This method will be implemented by the Child classes
    func loadWith(theme: Theme) {

        self.navigationController?.navigationBar.tintColor = theme.navigationBarTextColor
        self.navigationController?.navigationBar.titleTextAttributes  = [NSAttributedStringKey.foregroundColor : theme.navigationBarTextColor]
        // Need to be implemented by child classes
        print("theme changed")
    }


    deinit {

        themeManager.currentTheme.unbind(listener: currentListener)
    }
}

主题

struct Theme {

    // Define all the theme properties you want to control.

    var navigationBarBgColor: UIColor = UIColor.darkGray
    var navigationBarTextColor: UIColor = UIColor.black
}

1 个答案:

答案 0 :(得分:0)

问题在于unbind方法中闭包的比较,因为它可用于闭包和函数()。见this。我猜你可以维护一个hashmap,其中侦听器是值,唯一标识符是键。解除绑定也会快得多。

但是,我觉得Notifications的方式要好得多,因为它可以为您提供相同的行为(Publisher-Subscriber),而无需管理听众。