【问题标题】:Instantiate View Controller from Storyboard vs. Creating New Instance从 Storyboard 实例化视图控制器与创建新实例
【发布时间】:2023-03-25 21:40:01
【问题描述】:

从故事板实例化视图控制器和创建它的新实例之间的功能区别是什么?例如:

#import "SomeViewController.h"

...

SomeViewController *someViewController = [SomeViewController new];

#import "SomeViewController.h"

...

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle: nil];

SomeViewController *someViewController = [storyboard instantiateViewControllerWithIdentifier:@"SomeViewController"];

在任何一种情况下,someViewController 实际上是同一件事吗?

【问题讨论】:

    标签: ios objective-c uiviewcontroller uistoryboard


    【解决方案1】:
    simple swift 3 extension   
     fileprivate enum Storyboard : String {
            case main = "Main"
        }
    
        fileprivate extension UIStoryboard {
            static func loadFromMain(_ identifier: String) -> UIViewController {
                return load(from: .main, identifier: identifier)
            }
    
            static func load(from storyboard: Storyboard, identifier: String) -> UIViewController {
                let uiStoryboard = UIStoryboard(name: storyboard.rawValue, bundle: nil)
                return uiStoryboard.instantiateViewController(withIdentifier: identifier)
            }
        }
    
        // MARK: App View Controllers
    
        extension UIStoryboard {
            class func loadHomeViewController() ->  HomeViewController {
                return loadFromMain("HomeViewController") as! HomeViewController
            }
        }
    

    【讨论】:

      【解决方案2】:

      主要区别在于UIViewController 的子视图如何被实例化。

      在第二种情况下,您在情节提要中创建的所有视图都将自动为您实例化,并且所有出口和动作都将按照您在情节提要中指定的方式进行设置。

      在第一种情况下,这一切都没有发生;你只得到原始对象。您需要分配和实例化所有子视图,使用约束或其他方式布置它们,并自己连接所有出口和操作。 Apple recommends 通过覆盖 UIViewControllerloadView 方法来做到这一点。

      【讨论】:

        【解决方案3】:

        在 Swift 中你也可以这样做,

        var someVC = self.storyboard?.instantiateViewControllerWithIdentifier("SomeViewController") as! SomeViewController
        

        您需要将 Storyboard 中的 Identifier 提供给 SomeViewController 并勾选 Use Storyboard ID

        【讨论】:

          【解决方案4】:

          要检查的另一件事是,如果抛出错误的视图控制器有故事板标识符,您可以检查故事板 xib 文件。

          在我的情况下,标识符丢失,添加后错误停止

          【讨论】:

            【解决方案5】:

            如果您不想使用instantiateViewControllerWithIdentifier 实例化一个新的 VC,而是从 AppDelegate 访问由情节提要创建的实例:

            1. 在 AppDelegate.h 中创建一个属性,以便可以从使用它的类中访问它 @property (nonatomic, strong) myViewControllerClass*vC;
            2. viewDidLoad myViewControllerClass.m 中,我访问 AppDelegate 的共享实例并使用 self:[AppDelegate sharedInstance].vC = self; 提供属性

            我不得不在一个复杂的故事板中使用这个解决方案,但我仍然无法克服这样一个事实,即我无法找到一种简单的方法来访问 所有(或至少是我需要的) 对象故事板只需解决他们的标识符。

            【讨论】:

              【解决方案6】:

              在第二种情况下,视图控制器将从情节提要中加载其视图,您会很高兴。

              在第一种情况下,它不会。除非您采取了其他步骤(例如覆盖 loadViewviewDidLoad 或创建名为 SomeViewController.xib 的 xib),否则您只会得到一个空白的视图并感到难过。

              【讨论】:

              • 当我使用第二种情况时,我在实例化和实际控制器加载之间有很大的延迟,我想知道为什么它这么糟糕?这是来自 iPhone 4S 的日志:2015-03-03 20:42:39.692 App[5652:986462] Instantiate 2015-03-03 20:42:43.506 App[5652:986462] ViewDidLoad 几乎 4 秒。不要尝试其他方式,但也许你会遇到这种情况?
              • 视图控制器按需加载它的视图,因为有东西要求它的view 属性。这通常不会发生,直到系统真正想要将视图放在屏幕上。在实例化 VC 和加载视图之间发生了什么?你是否在做一些缓慢的操作,比如网络请求?
              • 不,我什么都不做,只是等待加载。我还尝试对这个 VC 执行 segue,但加载时间相同 =/ 认为 VC 有问题。我会尝试解决这个问题,如果您不介意,我会再次在这里写信。
              • 如果您有兴趣,这个问题是由设置为文本字段的自定义字体引起的,但该字体没有复制到设备上,这导致了这种延迟。 rdar://20028250
              【解决方案7】:

              这不是一回事。在情节提要中,您可能已经布置了一些 UI 元素。他们可能通过情节提要设置了约束和属性。当您通过情节提要实例化视图控制器时,您将获得有关这些子视图在哪里以及它们的属性是什么的所有说明。如果你只是说[SomeViewController new],你并没有得到故事板对视图控制器的所有指令。

              一个不错的测试是将 UIViewController 添加到情节提要中并将红色视图拖到上面。使用这两种方法实例化它,看看有什么区别。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2015-10-20
                • 2023-03-30
                • 1970-01-01
                • 2016-08-23
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多