Я пытаюсь использовать внедрение зависимостей с помощью InstantiateInitialViewController для исходного контроллера представления в раскадровке. Моя цель — внедрить ViewModel в мой ViewController при его создании. Однако мое приложение вылетает с ошибкой Неустранимая ошибка: init(coder:) не реализован. Вот моя установка:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateInitialViewController(creator: { coder in
ViewController(coder: coder, viewModel: ViewModel())
})
window?.rootViewController = viewController
window?.makeKeyAndVisible()
}
Вот контроллер представления
final class ViewController: UIViewController {
private let viewModel: ViewModel
init?(coder: NSCoder, viewModel: ViewModel) {
self.viewModel = viewModel
super.init(coder: coder)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
viewModel.fetchUsers { users in
print(users)
}
}
}
Проблема в том, что даже если вы сами извлекаете раскадровку и сами создаете экземпляр исходного контроллера представления...
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateInitialViewController(creator: { coder in
ViewController(coder: coder, viewModel: ViewModel())
})
... тем не менее, вы забыли запретить среде выполнения независимо извлекать раскадровку и создавать экземпляр исходного контроллера представления. Таким образом, ваш первоначальный контроллер представления создается дважды — и в первый раз вызывается переопределение init?(coder:)
, и происходит сбой.
Чтобы решить проблему, просто зайдите в Info.plist и удалите строку, которая устанавливает раскадровку как основную:
Видите ту строку, которую я выделил? Выберите его и нажмите «Удалить».
Теперь ваше приложение будет успешно запущено, и вы выполните внедрение зависимостей, к которому стремились.
Извините, мне потребовалось так много попыток, чтобы понять это!
Сбой происходит из-за того, что вы пытаетесь создать экземпляр контроллера представления из раскадровки с помощью пользовательского инициализатора (init?(coder: NSCoder, viewModel: ViewModel)), но раскадровки ожидают, что контроллеры представления будут инициализированы с помощью init(coder:). Раскадровка не знает, как передать дополнительный параметр viewModel, что приводит к сбою.
Решение:-
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
let viewController = ViewController.instantiate(viewModel: ViewModel())
window?.rootViewController = viewController
window?.makeKeyAndVisible()
}
final class ViewController: UIViewController {
private let viewModel: ViewModel
init?(coder: NSCoder, viewModel: ViewModel) {
self.viewModel = viewModel
super.init(coder: coder)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
static func instantiate(viewModel: ViewModel) -> ViewController? {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
return storyboard.instantiateInitialViewController { coder in
ViewController(coder: coder, viewModel: viewModel)
}
}
override func viewDidLoad() {
super.viewDidLoad()
viewModel.fetchUsers { users in
print(users)
}
}
}
Хотите верьте, хотите нет, но это проблема с вашим Info.plist. Смотрите мой ответ для простого решения.