Предупреждение "Expression of type UIViewController? is unused" в Xcode 8/Swift 3
Причина предупреждения
В Swift 3 метод instantiateViewController(withIdentifier:) начал возвращать UIViewController? (опциональный тип) вместо UIViewController (неопционального). Предупреждение возникает, потому что вы присваиваете результат переменной secondVC, но компилятор видит, что это опциональное значение не используется напрямую — оно просто передаётся в present. Фактически, вы могли бы написать present(storyboard.instantiateViewController(...), ...) без промежуточной переменной, и предупреждение исчезло бы. Однако правильное решение — безопасно развернуть опционал.
Основное решение: использование guard let или if let
Лучший способ избавиться от предупреждения и сделать код безопасным — использовать опциональное связывание:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
guard let secondVC = storyboard.instantiateViewController(withIdentifier: "SecondViewController") else {
fatalError("Не удалось загрузить SecondViewController из storyboard")
}
self.present(secondVC, animated: true, completion: nil)
Если вы уверены, что контроллер точно существует, можно использовать принудительное развёртывание с !:
let secondVC = storyboard.instantiateViewController(withIdentifier: "SecondViewController")!
self.present(secondVC, animated: true, completion: nil)
Но это опасно — если идентификатор указан неверно, приложение упадёт. Лучше использовать guard.
Почему это работает?
- Опциональное связывание — компилятор видит, что вы обработали случай
nil, и предупреждение исчезает. - Принудительное развёртывание — вы явно говорите: "я знаю, что это не nil", и компилятор перестаёт беспокоиться.
- В Swift 2 метод возвращал
AnyObject, поэтому предупреждения не было. В Swift 3 тип стал строже.
Дополнительный совет: используйте обобщённые методы
Для удобства можно создать расширение:
extension UIStoryboard {
func instantiateViewController<T: UIViewController>(ofType type: T.Type, identifier: String) -> T? {
return instantiateViewController(withIdentifier: identifier) as? T
}
}
// Использование:
guard let secondVC = storyboard.instantiateViewController(ofType: SecondViewController.self, identifier: "SecondViewController") else {
return
}
self.present(secondVC, animated: true, completion: nil)
Этот подход гарантирует, что вы получите контроллер правильного типа, и полностью устраняет предупреждение.
<<Альтернативный подход: использование as? с приведением типа
Если вы точно знаете тип контроллера, можно сделать приведение прямо в строке с презентацией, что также убирает предупреждение:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let secondVC = storyboard.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController {
self.present(secondVC, animated: true, completion: nil)
} else {
print("Не удалось получить SecondViewController")
}
Этот вариант решает две проблемы сразу: убирает предупреждение о неиспользуемом выражении и даёт типобезопасный доступ к свойствам контроллера (например, secondVC.someProperty).
Важно: Если вам не нужен специфический тип, а достаточно общего UIViewController, используйте guard let из первого ответа. Если же вы хотите сразу работать с конкретным подклассом — as? будет лучшим выбором.
Также можно подавить предупреждение явно, присвоив результат _:
let _ = storyboard.instantiateViewController(withIdentifier: "SecondViewController")
Но это плохая практика — вы теряете контроль над опциональностью и не обрабатываете возможную ошибку.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги