是否可以在实例化对象之前检查故事板中是否存在标识符?

时间:2023-02-04 17:02:41

In my code I have this line, but I was wondering if there is way to check whether @"SomeController" exists before I use it with the "instantiateViewControllerWithIdentifier" method. If the identifier doesn't exist then the app crashes.

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

It's not a huge problem if there isn't a good way to do it, I can just be a bit more careful not to fat finger the identifier names, but I was hoping I could handle it more gracefully.

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

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

5 个解决方案

#1


3  

No, there is no check for this. However, you don't need to. This method will return nil if the identifier doesn't exist, so just check for that with an NSAssert.

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

EDIT Actually this is wrong!! That's weird...the return value section of the documentation contradicts another portion...but still the answer is ultimately no (there is no method to check for the existence of an identifier)

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

#2


7  

As Tom said, the best solution to this problem is the try-catch block:

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

I hope it helps! even though the answer is really late.

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

#3


6  

You can use valueForKey: on UIStoryboards. UIStoryboards have a key called "identifierToNibNameMap", its value is an NSDictionary with the UIViewControllers in that storyboard. This inner NSDictionary uses the viewcontroller's names as keys so you can actually check if a viewcontroller exists in a storyboard with the following code:

您可以在UIStoryboards上使用valueForKey :. UIStoryboards有一个名为“identifierToNibNameMap”的键,它的值是一个NSDictionary,其中包含该故事板中的UIViewControllers。这个内部NSDictionary使用视图控制器的名称作为键,因此您可以使用以下代码实际检查故事板中是否存在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
}

Note: Apple has been known to reject apps that query the underlying properties of cocoa classes using valueForKey:. These underlying properties could change at any time in the future, breaking app functionality without warning. There is no deprecation process for these things.

注意:众所周知,Apple拒绝使用valueForKey:查询可可类的基础属性的应用程序。这些底层属性可能在将来的任何时候发生变化,在没有警告的情况下破坏应用功能这些东西没有弃用过程。

#4


1  

You can wrap the code with try-catch exception handling and decide how to react if such an exception occurs. I use this method to dynamically instantiate view controllers without having to know if they are represented in the Storyboard or a nib file.

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

#5


0  

@Kevin's solution works. Here is a pretty the same piece of code for Swift 3 as function, that I am using in my code:

@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
}

Use this function as follows:

使用此功能如下:

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")
}

#1


3  

No, there is no check for this. However, you don't need to. This method will return nil if the identifier doesn't exist, so just check for that with an NSAssert.

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

EDIT Actually this is wrong!! That's weird...the return value section of the documentation contradicts another portion...but still the answer is ultimately no (there is no method to check for the existence of an identifier)

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

#2


7  

As Tom said, the best solution to this problem is the try-catch block:

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

I hope it helps! even though the answer is really late.

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

#3


6  

You can use valueForKey: on UIStoryboards. UIStoryboards have a key called "identifierToNibNameMap", its value is an NSDictionary with the UIViewControllers in that storyboard. This inner NSDictionary uses the viewcontroller's names as keys so you can actually check if a viewcontroller exists in a storyboard with the following code:

您可以在UIStoryboards上使用valueForKey :. UIStoryboards有一个名为“identifierToNibNameMap”的键,它的值是一个NSDictionary,其中包含该故事板中的UIViewControllers。这个内部NSDictionary使用视图控制器的名称作为键,因此您可以使用以下代码实际检查故事板中是否存在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
}

Note: Apple has been known to reject apps that query the underlying properties of cocoa classes using valueForKey:. These underlying properties could change at any time in the future, breaking app functionality without warning. There is no deprecation process for these things.

注意:众所周知,Apple拒绝使用valueForKey:查询可可类的基础属性的应用程序。这些底层属性可能在将来的任何时候发生变化,在没有警告的情况下破坏应用功能这些东西没有弃用过程。

#4


1  

You can wrap the code with try-catch exception handling and decide how to react if such an exception occurs. I use this method to dynamically instantiate view controllers without having to know if they are represented in the Storyboard or a nib file.

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

#5


0  

@Kevin's solution works. Here is a pretty the same piece of code for Swift 3 as function, that I am using in my code:

@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
}

Use this function as follows:

使用此功能如下:

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")
}