【问题标题】:iOS - MVVM Data BindingiOS - MVVM 数据绑定
【发布时间】:2022-07-17 13:01:51
【问题描述】:

我正在使用 MVVM 设计架构,我已经阅读了多篇关于数据绑定的文章。我们可以通过协议、闭包和第三方(如 RxSwift)来实现数据绑定。 所以,如果我错了,请纠正我,否则让我知道“在 iOS(Swift) MVVM 设计架构中绑定数据的方法有多少?”

【问题讨论】:

  • 除了你提到的你还可以使用组合框架和“装箱” - 可观察对象
  • 您可以在此处查看带有数据绑定的 MVVM 示例github.com/alemarcon/MVVM-iOS-Clean

标签: ios swift xcode mvvm


【解决方案1】:

最简单的方法是使用称为 Boxing 的 Observable 类绑定。 创建一个 Observable 类:

class Observable<T> {

var value: T? {
    didSet {
        DispatchQueue.main.async {
            self.listener?(self.value)
        }
    }
}

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

private var listener: ((T?) -> Void)?

func bind(_ listener: @escaping (T?) -> Void) {
    listener(value)
    self.listener = listener
}
}

在您的 viewModel 中以这种方式定义它: (这是在视图控制器中显示加载器的示例)

var isLoadingData: Observable<Bool> = Observable(false)

因为 Observable 类是泛型类型,所以可以将其他类型传递给它。

在您的视图模型中,您可以设置值:

isLoadingData.value = true

然后在你的视图控制器中使用这样的东西:

   viewModel.isLoadingData.bind { [weak self] loading in
        guard let loading = loading, let self = self else {
            return
        }
        DispatchQueue.main.async {
            if loading {
                //Show a loader
            } else {
                //Hide a loader
            }
        }
    }

一旦为 isLoadingData 对象分配了一个值,它就会触发您的视图控制器。我们必须使用 [Weak self] 来避免强引用。

【讨论】:

    【解决方案2】:

    由于我需要多个观察者,并且当 ViewController 消失时我不希望闭包仍然存在。 我对Sajjad Sarkoobi 代码做了一些更改。

    typealias ListenerClosure = @convention(block) (_ T: AnyObject?) -> ()
    
    class Observable<T: AnyObject> {
    
        var value: T? {
        
            didSet {
            
                self.listeners.forEach({ unsafeBitCast($0, to: ListenerClosure.self)(value) })
            
            }
        
        }
    
        private var listeners: [AnyObject] = []
    
        init(_ value: T?) {
        
            self.value = value
        
        }
    
        func bind(_ listener: @escaping ListenerClosure) {
        
            listener(value)
        
            let anyObject = unsafeBitCast(listener, to: AnyObject.self)
        
            self.listeners.append(anyObject)
        
        }
    
        func unbind(_ listener: @escaping ListenerClosure) {
    
            let anyObject = unsafeBitCast(listener, to: AnyObject.self)
                
            self.listeners.removeAll(where: { $0 === anyObject })
        
        }
    
    }
    

    在您的 viewModel 中以这种方式定义它

    var currentUUID: Observable<NSUUID> = Observable(nil)
    

    在 ViewModel 中设置值

    self.currentUUID.value = NSUUID()
    

    在你的 ViewController 中使用 bind 和 unbind。我想从 Observable listeners 数组中移除闭包,所以我在 viewController deinit 时解绑它。

    如果使用 self 则需要捕获列表 [weak self] 闭包中的引用,否则此 viewController 将不会取消初始化。

    class ViewController: NSViewController {
    
        var viewModel: ViewModel?
    
        private var listener: ListenerClosure!
    
        override func viewDidLoad() {
            super.viewDidLoad()
        
            self.listener = { [weak self] uuid in
                
                //self?.doSomething()
    
                print("observed ViewModel currentUUID \(uuid)")
            
            }
        
            self.viewModel?.currentUUID.bind(self.listener)
        }
    
        deinit {
        
            print("ViewController deinit")
        
            self.viewModel?.currentUUID.unbind(self.listener)
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-01-07
      • 1970-01-01
      • 2015-07-15
      • 2015-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-29
      相关资源
      最近更新 更多