【问题标题】:How to call method in ViewController from viewmodel in swift?如何在 swift 中从 viewmodel 调用 ViewController 中的方法?
【发布时间】:2020-06-02 06:22:02
【问题描述】:

我在 iOS 项目中使用 MVVM 设计模式。我正在尝试从 viewmodel 调用 viewcontroller 中的方法。

import Foundation

class NotificationViewModel {

    var onCompletion: ((_ success: Bool) -> ())?

    func saveNotification(notification: Dictionary<String, Any>) {
        print("notification save")
        //other logic
        onCompletion?(true)
    }
   }

收到通知时从appdelegate调用“saveNotification”方法

func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
        let userInfo = response.notification.request.content.userInfo

        guard
            let aps = userInfo[AnyHashable("aps")] as? NSDictionary,
            let alert = aps["alert"] as? NSMutableDictionary
            else {
                // handle any error here
                return
            }   

        NotificationViewModel().saveNotification(notification: alert as! Dictionary<String, Any>)
        }

在“saveNotification”触发时尝试调用视图控制器中的方法

     class AlertViewController: BaseViewController{


            var viewModel = NotificationViewModel()

            override func viewDidLoad() {
                super.viewDidLoad()

                self.viewModel.onCompletion = { success in
                    // this should be executed when `saveNotification()` will be called
// **** this is never getting called ******
                    print("calling from viewmodel")
                    methodToCall()
                }
            }

          func methodToCall(){
            //logic
          }
      }

但是 viewdidload 中的方法不会随时被调用。

请建议是否可能或任何其他方式来实现这一目标? 感谢您的帮助

【问题讨论】:

  • 从您的代码中,它将是func someButtonTapped () { ... viewModel.saveNotificationnotification: ...) }
  • @Larme 对不起,它只是错字..更正
  • 这不会破坏 MVVM 吗?
  • @JoakimDanielson 在 vi​​ewcontroller 的那个方法中我想重新加载 tableview.. 我不知道如何通过 viewmodel 实现这一点
  • 您面临的问题是什么?你没有提到那个。没有打印“从视图模型调用”吗?

标签: ios swift mvvm


【解决方案1】:

没有 Rx 框架(RxSwift、ReactiveCocoa 或 Apple Combine)的 MVVM 很痛苦。 以下是我在 MVVM + RxSwift 中的解决方案。希望对您有所启发。

import Foundation
import RxSwift
import RxCocoa

final class NotificationViewModel: ViewModel, ViewModelType {

    struct Input { }

    struct Output {
        let compelete: PublishSubject<Bool>
    }

    let input: Input = Input()

    let output: Output = Output(compelete: PublishSubject<Bool>())
}

import UIKit
import RxSwift
import RxCocoa
import Rswift

final class NotificationViewController: ViewController<LoginViewModel> {

    override func bindViewModel() {

        vm.output.compelete
            .subscribe(onNext: { [unowned self] _ in
                // this will be executed when `saveNotification()` will be called
                print("calling from viewmodel")
                methodToCall()
            })
            .disposed(by: disposeBag)

    }

    private func methodToCall(){
        //logic
    }

}

每当您想要求视图控制器调用 methodToCall 函数时。只需在您的视图模型中调用 output.complete.onNext(true)

【讨论】:

  • 感谢您的出色解决方案
  • 不客气,没有 Rx 的 MVVM 就像没有盐的汤。现在,我们可以选择 Apple Combine 作为原生响应式功能框架。祝你成为 Rx 大师的旅程好运。
  • 谢谢亲爱的。我在您的帮助下解决了我的问题!我找不到 viewModel 输出函数。
【解决方案2】:

不需要NotificationViewModel

您只需要直接在应用程序委托中显示警报

func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
        
    let userInfo = response.notification.request.content.userInfo

    guard let aps = userInfo[AnyHashable("aps")] as? NSDictionary,
        let alertDict = aps["alert"] as? NSMutableDictionary else {
            // handle any error here
            return
        }   

    let alert = AlertViewController()

    alert.showAlert(dict: alertDict)
}

您的警报类:

class AlertViewController: BaseViewController{

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    func showAlert(dict: Dictionary<String, Any>){
        // do show alert
    }      
}

【讨论】:

    【解决方案3】:

    参见 Appdelegate 中的 NotificationViewModel() 和 AlertViewController 中的 viewModel 变量,它们不一样,都是 NotificationViewModel 类的 2 个不同实例。您需要回到基础知识并理解类、结构、实例等的概念。完全解释这一点超出了本答案的范围。例如,您可以启动from here

    现在我建议,由于你还没有掌握这些概念,你最好坚持使用 MVC 并使用 NotificationCenter 将消息从 AppDelegate 直接传递到 AlertViewController。以下是一些关于 NotificationCenter 的有用教程:-

    1. https://learnappmaking.com/notification-center-how-to-swift/
    2. https://www.hackingwithswift.com/example-code/system/how-to-post-messages-using-notificationcenter

    PS。感谢您从一开始就尝试 MVVM 架构,但请确保您在整个过程中保持基础/基础也很强大,最好是从一开始就开始。一切顺利:)

    【讨论】:

    • 谢谢,我一定会看看
    猜你喜欢
    • 1970-01-01
    • 2015-05-19
    • 1970-01-01
    • 2014-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-10
    相关资源
    最近更新 更多