简体   繁体   English

swift:取消绑定监听器数组的关闭监听器

[英]swift:Unbind listeners which are closures from array of listeners

I am trying to develop a theme engine, which loads themes from a json . 我正在尝试开发一个主题引擎,该引擎从json加载主题。 I have a Thememanager which is a singleton class and holds a currentTheme variable. 我有一个Thememanager ,它是一个singleton类,并具有currentTheme变量。 I then have a baseViewController which listens to any change in the currentTheme with the help of Boxing technique, and all the viewControllers need to be subclass of base and need to override the observer method to apply their styles. 然后,我有一个baseViewController ,它通过Boxing技术来侦听currentTheme任何更改,并且所有viewControllers都必须是base子类,并且需要override observer方法以应用其样式。 In the box class I have an array of listeners so that multiple view controllers can observer theme change simultaneously, it works well and now my problem is that whenever a view controller gets deallocated , I want to remove that listener also from the box class array of listeners, which I am unable to figure out, because of which listeners are getting piled up. box类中,我有一个listeners器数组,以便多个视图控制器可以同时更改观察者主题,它运行良好,现在我的问题是,每当一个视图控制器被deallocated ,我也想从的box类数组中删除该侦听器。听众,我无法弄清,因为这些听众越来越多。

I tried to write an unbind method in the deint of the viewController and tried to pass the closure like the below but it didnt work 我试图在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 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)
    }
}

Theme 主题

struct Theme {

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

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

The issue is with the comparison of closure in unbind method as it snot available for closures and functions(). 问题在于在unbind方法中比较闭包,因为它不适用于闭包和functions()。 See this . 看到这个 I guess you could maintain a hashmap where listeners be the value and a unique identifier be the key. 我猜您可以维护一个哈希表,其中侦听器为值,唯一标识符为键。 It is going to be much faster to unbind it as well. 解除绑定的速度也会更快。

But, I feel Notifications way is much better as it gives you the same behaviour(Publisher-Subscriber) without you having to manage the listeners. 但是,我觉得Notifications方法更好,因为它可以为您提供相同的行为(Publisher-Subscriber),而您无需管理侦听器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM