0

所以我正在尝试从 MMVM 重构现有项目并添加协调器。我有以下课程:

protocol Coordinator {

 func start()

}

class BaseCoordinator: Coordinator {

private var presenter: UINavigationController
private var genreViewController: ViewController?
private var viewModel = GenreViewModel()

init(presenter: UINavigationController) {
    self.presenter = presenter
}

func start() {
    let genreViewController = ViewController()
    genreViewController.viewModel = viewModel
    self.genreViewController = genreViewController
    presenter.pushViewController(genreViewController, animated: true)
}
}
 

class AppCoordinator: Coordinator {

private let window: UIWindow
private let rootViewController: UINavigationController
private var genereListCoordinator: BaseCoordinator?

init(window: UIWindow) {
    self.window = window
    rootViewController = UINavigationController()
    rootViewController.navigationBar.prefersLargeTitles = true
    
    genereListCoordinator = BaseCoordinator(presenter: rootViewController)
}

func start() {
    window.rootViewController = rootViewController
    genereListCoordinator?.start()
    window.makeKeyAndVisible()
}

}

在 appDelegate 我做如下:

      var window: UIWindow?
var applicationCoordinator: AppCoordinator?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    let window = UIWindow(frame: UIScreen.main.bounds)
    let appCordinator = AppCoordinator(window: window)
    self.window = window
    self.applicationCoordinator = appCordinator
    
    appCordinator.start()
    return true
}

VC是:

  class ViewController: UIViewController {

@IBOutlet weak var collectionView: UICollectionView!

var viewModel: GenreViewModel!

override func viewDidLoad() {
    super.viewDidLoad()
    
    
    if let flowLayout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
        flowLayout.itemSize = CGSize(width: self.collectionView.bounds.width, height: 50)
    }
    self.collectionView.delegate = self
    self.collectionView.dataSource = self
    collectionView.backgroundView = UIImageView(image: UIImage(named: "131249-dark-grey-low-poly-abstract-background-design-vector.jpg"))
    self.viewModel.delegate = self
    self.getData()
}

func getData() {
    MBProgressHUD.showAdded(to: self.view, animated: true)
    viewModel.getGenres()
}

}

扩展 ViewController: GenreViewModelDelegate { func didfinish(succsess: Bool) { MBProgressHUD.hide(for: self.view, animated: true) if succsess { self.collectionView.reloadData() } else { let action = UIAlertAction(title: "再试一次",样式:.default,处理程序:{ (action) in self.getData() }) Alerts.showAlert(vc: self, action: action) } } }

扩展 ViewController: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: 100, height: 100) } }

扩展视图控制器:UICollectionViewDataSource {

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return viewModel.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: GenreCollectionViewCell.reuseIdentifier, for: indexPath) as? GenreCollectionViewCell else {
        return UICollectionViewCell()
    }
    let cellViewModel = viewModel.cellViewModel(index: indexPath.row)
    cell.viewModel = cellViewModel
    return cell
}

func numberOfSections(in collectionView: UICollectionView) -> Int {
    return 1
}

}

 extension ViewController: UICollectionViewDelegate {

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let cellViewModel = viewModel.cellViewModel(index: indexPath.row)
    viewModel.didSelectGenre(index: (cellViewModel?.id)!)
}
}

虚拟机是:

protocol GenreViewModelDelegate: class {
func didfinish(succsess: Bool)
}

protocol GenreListCoordinatorDelegate: class {
func movieListDidGenre(id: String)
 }

class GenreViewModel {

weak var coordinatorDelegate: GenreListCoordinatorDelegate?

var networking =  Networking()

var genresModels = [Genres]()

weak var delegate: GenreViewModelDelegate?

func getGenres() {
    self.networking.preformNetwokTask(endPoint: TheMoviedbApi.genre, type: Genre.self, success: { [weak self] (response) in
        print(response)
        if let genres = response.genres {
            self?.genresModels = genres
            self?.delegate?.didfinish(succsess: true)
        } else {
            self?.delegate?.didfinish(succsess: false)
        }
    }) {
        self.delegate?.didfinish(succsess: false)
    }
}

var count: Int {
    return genresModels.count
}

public func cellViewModel(index: Int) -> GenreCollectionViewCellModel? {
    
    let genreCollectionViewCellModel = GenreCollectionViewCellModel(genre: genresModels[index])
    return genreCollectionViewCellModel
    
}

public func didSelectGenre(index: String) {
    coordinatorDelegate?.movieListDidGenre(id: index)
}
}

问题是,当我试图将 viewModel 注入 ViewController 并在 start 函数中将其推送时,它将不起作用——当 viewDidLoad 在 VC 中调用 viewModel 时为零。

4

1 回答 1

0

使用相同的代码,我设法使它工作,该viewModel属性填充在我身边。


// Coordinator
protocol Coordinator {
    func start()
}

class BaseCoordinator: Coordinator {

    private var presenter: UINavigationController
    private var genreViewController: ViewController?
    private var viewModel = ViewModel()

    init(presenter: UINavigationController) {
        self.presenter = presenter
    }

    func start() {
        let genreViewController = ViewController()
        genreViewController.viewModel = viewModel
        self.genreViewController = genreViewController
        presenter.pushViewController(genreViewController, animated: true)
    }
}

// ViewController + ViewModel
struct ViewModel { }

class ViewController: UIViewController {

    var viewModel: ViewModel!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        view.backgroundColor = .white
    }
}

class AppCoordinator: Coordinator {

    private let window: UIWindow
    private let rootViewController: UINavigationController
    private var genereListCoordinator: BaseCoordinator?

    init(window: UIWindow) {
        self.window = window
        rootViewController = UINavigationController()
        rootViewController.navigationBar.prefersLargeTitles = true

        genereListCoordinator = BaseCoordinator(presenter: rootViewController)
    }

    func start() {
        window.rootViewController = rootViewController
        window.makeKeyAndVisible()
        genereListCoordinator?.start()
    }
}

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var applicationCoordinator: AppCoordinator?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        let window = UIWindow()
        let appCordinator = AppCoordinator(window: window)
        self.window = window
        self.applicationCoordinator = appCordinator

        appCordinator.start()

        return true
    }
}

协调器模式的问题通常是保留导航堆栈,它不会触发viewDidLoad或根本不显示屏幕。在您的情况下,如果只是viewModel丢失,我相信它来自ViewController构造函数问题或覆盖。

我可以@IBOutlet在您的文件中看到一个,ViewController这让我认为您正在使用情节提要/ xib 文件。但是,BaseCoordinator唯一使用 a init(),可能是问题吗?如果使用 Storyboard,您应该尝试使用instantiateViewController(...).

另一方面,您应该考虑保留所有协调器堆栈以处理完整的导航,并viewModel在需要时避免在协调器中保留或其他属性。如果UINavigationController保留子 UIViewController,你也不需要。

于 2020-10-21T09:50:19.783 回答