簡體   English   中英

Swift 將項目重構為 MVVM-C

[英]Swift refactor project to MVVM-C

所以我試圖從 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, animation: true) if succsess { self.collectionView.reloadData() } else { let action = UIAlertAction(title: "Try again ", style: .default, handler: { (action) in self.getData() }) Alerts.showAlert(vc: self, action: action) } } }

extension 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 時為零。

使用相同的代碼,我設法讓它工作, 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構造函數問題或覆蓋。

我可以在您的ViewController看到一個@IBOutlet ,這讓我認為您正在使用故事板/xib 文件。 但是, BaseCoordinator只使用init() ,這可能是問題嗎? 如果使用 Storyboard,您應該嘗試使用instantiateViewController(...)

另一方面,您應該考慮保留所有協調器堆棧以處理完整導航,並在需要時避免在協調器中保留viewModel或其他屬性。 如果UINavigationController保留子 UIViewController,你也不需要。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM