16

在我的代码中,我有这一行,但我想知道是否有办法在将@"SomeController"与“ instanceViewControllerWithIdentifier ”方法一起使用之前检查它是否存在。如果标识符不存在,则应用程序崩溃。

如果没有好的方法,这不是一个大问题,我可以更加小心,不要让标识符名称变胖,但我希望我能更优雅地处理它。

UIViewController *newTopViewController = [self.storyboard    instantiateViewControllerWithIdentifier:@"SomeController"];
4

6 回答 6

7

正如汤姆所说,这个问题的最佳解决方案是 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];
    }

我希望它有帮助!即使答案真的很晚。

于 2013-08-27T07:24:51.303 回答
7

你可以valueForKey:UIStoryboards 上使用。UIStoryboards 有一个名为“identifierToNibNameMap”的键,它的值是那个故事板NSDictionary中的UIViewControllers。此内部NSDictionary使用视图控制器的名称作为键,因此您可以使用以下代码实际检查情节提要中是否存在视图控制器:

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 会拒绝使用valueForKey:. 这些基础属性可能会在未来的任何时候发生变化,从而在没有警告的情况下破坏应用程序的功能。这些东西没有弃用过程。

于 2016-01-07T08:34:33.800 回答
6

@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")
}
于 2017-03-24T20:30:15.770 回答
3

不,没有检查。但是,您不需要这样做。nil如果标识符不存在,此方法将返回,因此只需使用NSAssert.

编辑实际上这是错误的!这很奇怪......文档的返回值部分与另一部分相矛盾......但答案最终是否定的(没有方法来检查标识符是否存在)

于 2012-11-20T02:23:25.130 回答
1

您可以使用 try-catch 异常处理来包装代码,并决定在发生此类异常时如何做出反应。我使用这种方法来动态实例化视图控制器,而不必知道它们是在 Storyboard 中还是在 nib 文件中表示的。

于 2012-12-31T22:06:59.450 回答
1

斯威夫特 4.2。

在下面声明一个扩展。

extension UIStoryboard {
    func instantiateVC(withIdentifier identifier: String) -> UIViewController? {
        // "identifierToNibNameMap" – dont change it. It is a key for searching IDs 
        if let identifiersList = self.value(forKey: "identifierToNibNameMap") as? [String: Any] {
            if identifiersList[identifier] != nil {
                return self.instantiateViewController(withIdentifier: identifier)
            }
        }
        return nil
    }
}

在任何地方使用这样的方法:

if let viewController = self.storyboard?.instantiateVC(withIdentifier: "yourControllerID") {
            // Use viewController here
            viewController.view.tag = 0; // for example
        }

或者

    if let viewController = UIStoryboard(name: "yourStoryboardID", bundle: nil).instantiateVC(withIdentifier: "yourControllerID") {
        // Use viewController here
        viewController.view.tag = 0; // for example
    }

将“yourControllerID”替换为您的控制器 ID。

于 2019-03-15T09:04:32.837 回答