Можно ли проверить, существует ли идентификатор в раскадровке перед созданием объекта?
В моем коде у меня есть эта строка, но мне было интересно, существует ли способ проверить, существует ли @SomeController, прежде чем использовать его с методом "instantiateViewControllerWithIdentifier". Если идентификатор не существует, приложение отключается.
Это не огромная проблема, если нет хорошего способа сделать это, я могу быть немного осторожнее, чтобы не толкнуть имена идентификаторов, но я надеялся, что смогу обработать его более изящно.
UIViewController *newTopViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"SomeController"];
Ответы
Ответ 1
Нет, для этого нет никакой проверки. Однако вам это не нужно. Этот метод вернет nil
, если идентификатор не существует, поэтому просто проверьте его с помощью NSAssert
.
EDIT На самом деле это неправильно! Это странно... раздел возвращаемого значения документации противоречит другой части... но все же ответ в конечном счете отсутствует (нет способа проверить наличие идентификатора)
Ответ 2
Как сказал Том, лучшим решением этой проблемы является блок try-catch:
@try {
UIViewController *newViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"identifier"];
}
@catch (NSException *exception) {
UIAlertView *catchView;
catchView = [[UIAlertView alloc]
initWithTitle: NSLocalizedString(@"Error", @"Error")
message: NSLocalizedString(@"Identifier not found on SB".", @"Error")
delegate: self
cancelButtonTitle: NSLocalizedString(@"OK", @"Error") otherButtonTitles: nil];
[catchView show];
}
Надеюсь, это поможет! хотя ответ действительно задерживается.
Ответ 3
Вы можете использовать valueForKey:
на UIStoryboard
s. UIStoryboard
имеет ключ с именем "identifierToNibNameMap", его значение равно NSDictionary
с UIViewController
в этой раскадровке. Этот внутренний NSDictionary
использует имена viewcontroller как ключи, поэтому вы можете проверить, существует ли viewcontroller в раскадровке со следующим кодом:
if ([[storyboard valueForKey:@"identifierToNibNameMap"] objectForKey:myViewControllerName]) {
// the view controller exists, instantiate it here
UIViewController* myViewController = [storyboard instantiateViewControllerWithIdentifier:myViewControllerName];
} else {
//the view controller doesn't exist, do fallback here
}
Примечание. Apple, как известно, отклоняет приложения, которые запрашивают базовые свойства классов cocoa, используя valueForKey:
. Эти базовые свойства могут измениться в любое время в будущем, нарушая функциональность приложения без предупреждения. Для этих вещей нет процесса устаревания.
Ответ 4
Вы можете обернуть код обработкой исключений try-catch и решить, как реагировать, если возникает такое исключение.
Я использую этот метод для динамического создания экземпляров контроллеров представлений без необходимости знать, представлены ли они в раскадровке или файле nib.
Ответ 5
Решение @Kevin работает. Вот такой же кусок кода для Swift 3 как функция, которую я использую в своем коде:
func instantiateViewController(fromStoryboardName storyboardName: String, withIdentifier identifier: String) -> UIViewController? {
let mainStoryboard = UIStoryboard(name: storyboardName, bundle: nil)
if let availableIdentifiers = mainStoryboard.value(forKey: "identifierToNibNameMap") as? [String: Any] {
if availableIdentifiers[identifier] != nil {
if let poiInformationViewController = mainStoryboard.instantiateViewController(withIdentifier: identifier) as? UIViewController {
return viewController
}
}
}
return nil
}
Используйте эту функцию следующим образом:
if let viewController = self.instantiateViewController(fromStoryboardName: "YourStoryboardName", withIdentifier: "YourViewControllerStoryboardID") {
// Here you are sure your viewController is available in the Storyboard
} else {
print("Error: The Storyboard with the name YourStoryboardName or the Storyboard identifier YourViewControllerStoryboardID is not available")
}