ios - swift:解除监听器的绑定(bind),这些监听器是监听器数组中的闭包

标签 ios swift binding

我正在尝试开发一个主题引擎,它从json加载主题。 。我有一个Thememanager这是 singleton类并持有 currentTheme多变的。 然后我有一个 baseViewController它监听 currentTheme 中的任何变化在Boxing的帮助下技术,并且所有 viewController 都需要是 base并且需要override observer应用他们的风格的方法。在 box类我有一个数组 listeners这样多个 View Controller 可以同时观察主题变化,现在效果很好 我的问题是,每当 View Controller 获取 deallocated ,我也想从监听器的框类数组中删除该监听器,但我无法弄清楚,因为监听器正在堆积起来。

我尝试写一个unbind viewController 的 deint 中的方法并尝试像下面一样传递闭包,但它不起作用

func unbind(listener: Listener?) {

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

}

主题管理器

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)
    }
}

盒子

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 }

    }

}

基础 View Controller

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
}

最佳答案

问题在于 unbind 方法中闭包的比较,因为它不适用于闭包和 function()。请参阅this 。我想你可以维护一个 HashMap ,其中监听器是值,唯一标识符是键。解除绑定(bind)也会更快。

但是,我觉得通知方式要好得多,因为它为您提供相同的行为(发布者-订阅者),而无需管理监听器。

关于ios - swift:解除监听器的绑定(bind),这些监听器是监听器数组中的闭包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48719228/

相关文章:

ios - Firebase 查询不起作用

SwiftUI:可以从任何 View 触发的全局覆盖

visual-studio - Team Foundation Server - 解决方案绑定(bind)丢失

c# - 如果元素来自 ItemSsource,如何在 WPF TreeView 中聚焦元素?

ios - ionicplatform.ready 不会在加载时被调用

ios - CoreData NSPredicate 按日期获取数据

ios - 防止页脚与 UITableView 中的 tableViewCell 重叠 - Swift

ios - 一次显示 2 个 CPTXYPlotSpace

iOS 快速拉动刷新混合与桌面 View

objective-c - 绑定(bind)到 NSTreeController SelectionIndexPaths