[英]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.