【问题标题】:Can multiple container scenes use a common view controller?多个容器场景可以使用一个通用的视图控制器吗?
【发布时间】:2015-03-20 17:28:25
【问题描述】:

我的故事板中有四个场景。一个场景通过容器视图充当所有其他场景的父级。一切都是这样安排的:

如果你眯着眼睛,你会注意到所有四个都是同一个视图控制器的子类。我这样做是为了可以将每个场景的元素连接到单个通用视图控制器,并避免将 UIViewController 子类化四次。 ProductDetailViewController 实现如下所示:

@implementation ProductDetailViewController {
    // Scene 1
    __weak IBOutlet UINavigationBar *_navigationBar;

    // Scene 2
    __weak IBOutlet UILabel *_productName;

    // Scene 3
    __weak IBOutlet UILabel *_typeNameLabel;
    __weak IBOutlet UILabel *_categoryNameLabel;
    __weak IBOutlet UIImageView *_richImage;

    // Scene 4
    __weak IBOutlet UIImageView *_productImageView;
}

问题是viewDidLoad 触发了四次(显然)并且事情显示为空白。当我单步调试调试器时,我传递的产品对象是nil 三个周期,然后在第四个周期初始化。也许视图控制器加载不正常?

无论如何,这种设置是否可行?我认为必须有一种更好的方法来避免每个情节提要场景都使用子类视图控制器。

【问题讨论】:

  • 从您的图像和描述中根本不清楚为什么您需要 3 个视图控制器,而不是 3 个视图,它们都是您的一个控制器的子视图。你想在这 3 个子控制器中做什么?

标签: ios uiviewcontroller uicontainerview


【解决方案1】:

将多个 .xib 设置为同一个类是很常见的。不想将 UIViewController 子类化四次也很常见。

一个问题是,通过使用嵌入在父视图容器中的子视图控制器和所有相同的视图控制器类来执行此操作,您将创建四个完全不同的类实例,并且在编写时您不能假设任何关于你是哪一个。难怪产品对象会丢失。

这个结构是可以挽救的,有很多值得推荐的地方,但是需要一些安排。一个好方法是让家长代表做出所有决定。

  1. 给类一个委托属性,它自己的类型,当然是弱的(弱是因为孩子不能让父母活着)。在整个过程中,您可以检查它是否为nil,因为如果它有一个代表它是一个孩子,但如果它没有代表它是一个父母。不过,您通常不需要知道。

  2. 使用 Segue 标识符。在 IB 中,给每个嵌入 segues 一个标识符。然后,在您的 View Controller 类中,使用正文实现 prepareForSegue:sender:

    if ([segue.identifier isEqualToString:@"ProductNameIdentiferInStoryboard"]) {
        /*...*/ } 
    else if ([segue.identifier isEqualToString:@"typeBarIdentiferInStoryboard"]) { 
        /*...*/  } 
    else if ([segue.identifier isEqualToString:@"productImageIdentifierInStoryboard"]) {  /*...*/ }
    
  3. 实现三个属性,同样类型,每个代表一个childViewController,

    @property ProductDetailViewController *productNameViewController; 
    @property ProductDetailViewController *productTypeBarViewController;
    @property ProductDetailViewController *productImageBarViewController;`
    
  4. 在第 2 步的prepareForSegue 中,填写图案:

    self.productNameViewController = segue.destinationViewController;
    self.productNameViewController.delegate = self;
    
  5. 注意 prepareForSeque:sender: 在任何 viewDidLoad 之前触发,因此您有参考:从父级的角度进行所有设置。 self.productNameViewController.titleLabel.text = @"Product Name"; 孩子们会先开火,不管给 nil 发消息什么都不做,所以他们可以和他们想象中的孩子们一起玩。如果他们需要发送信息或询问一些重要的事情,他们会有一名代表。

这可能看起来很麻烦,标识符的东西肯定是。然而,在 IB 中处理分散布局的同时在代码中保持集中控制的好处作为处理视图控制器的一种方式是显而易见的。

【讨论】:

    【解决方案2】:

    这四个场景肯定可以共享一个视图控制器类,但该视图控制器类将有四个实例,而不是一个。

    话虽如此,我建议不要使用这种方法,我会建议:

    • 保留您拥有的故事板布局,但为每个子场景使用唯一的视图控制器类,每个子场景都有自己唯一的 IBOutlet 引用。

      如果您希望父视图控制器能够访问在子视图控制器中输入的数据,您显然可以让子视图控制器更新父视图控制器(例如,使用委托协议模式)。但我不会亲自将孩子的 UIKit 属性暴露给父视图控制器(视图控制器没有业务访问另一个控制器视图的 UIKit 对象),而是将模型数据传回。

    • 如果您不想要单独的控制器,请不要将这些子视图放在单独的场景中。无论如何,您的示例似乎并不是对视图控制器包含的非常引人注目的使用。在我看来,这些子场景必须具有一定程度的复杂性才能证明使用单独的场景是合理的(从而证明单独的视图控制器是合理的)。如果它们不是那么复杂,您只需将子视图添加到父视图控制器,这要容易得多,而不是使用容器视图和所需的视图控制器包含。

    【讨论】:

      猜你喜欢
      • 2016-02-13
      • 1970-01-01
      • 2023-03-17
      • 2023-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多