我的故事板中有四个场景。一个场景通过容器视图充当所有其他场景的父节点。一切都安排如下:
如果您眯着眼睛,您会注意到所有四个都是从同一个视图控制器进行子类化。我这样做是为了能够将每个场景的元素连接到一个公共视图控制器,并避免将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
三个周期,然后在第四个周期初始化。也许视图控制器无法正常加载?
在任何情况下,这个设置都可以吗?我认为必须有更好的方法来避免每个故事板场景的子视图控制器。
答案 0 :(得分:0)
你肯定可以拥有这四个场景共享的单个视图控制器类,但是该视图控制器类将有四个实例,而不是一个。
话虽如此,我建议反对这种做法,我建议:
保留您的故事板布局,但为每个子场景使用唯一的视图控制器类,每个子场景都有自己唯一的IBOutlet
引用。
如果您希望父视图控制器能够访问在子视图控制器中输入的数据,您显然可以让子视图控制器更新父视图控制器(例如,使用委托协议模式)。但我不会亲自将子UIKit属性暴露给父视图控制器(视图控制器没有业务访问另一个控制器视图的UIKit对象),而是传回模型数据。
如果您不想要单独的控制器,请不要将这些子视图放在不同的场景中。无论如何,您的示例似乎并不是对视图控制器包含的非常引人注目的使用。在我看来,那些儿童场景必须具有一定程度的复杂性来证明使用单独的场景是合理的(因此证明了单独的视图控制器的合理性)。如果它们不那么复杂,您只需将子视图添加到父视图控制器,这更容易,而不是使用容器视图和需要的视图控制器包含。
答案 1 :(得分:0)
将多个.xibs设置为同一个类很常见。不想将UIViewController子类化四次也很常见。
一个问题是,通过嵌入在父视图容器中的子视图控制器和所有相同的View Controller类来执行此操作,您将创建四个类的实例,这些实例都是不同的,在编写时您不能假设任何关于你是哪一个。难怪产品对象迷失了。
这种结构可以被抢救,它有很多值得推荐的,但需要一些安排。一个好方法是让父母代表做出所有决定。
为类赋予其自身类型的委托属性,当然是弱的(弱因为孩子不能让父亲保持活着)。在整个过程中,您可以检查它是否为nil
,因为如果它有一个委托,那么它就是一个孩子,但如果它没有委托就是父亲。不过,你通常不需要知道。
使用Segue标识符。在IB中,给每个嵌入segue一个标识符。然后,在View Controller类中,使用正文
实现prepareForSegue:sender:
if ([segue.identifier isEqualToString:@"ProductNameIdentiferInStoryboard"]) {
/*...*/ }
else if ([segue.identifier isEqualToString:@"typeBarIdentiferInStoryboard"]) {
/*...*/ }
else if ([segue.identifier isEqualToString:@"productImageIdentifierInStoryboard"]) { /*...*/ }
实现三个同样属性的属性,每个属性代表一个childViewController,
@property ProductDetailViewController *productNameViewController;
@property ProductDetailViewController *productTypeBarViewController;
@property ProductDetailViewController *productImageBarViewController;`
在步骤2的prepareForSegue
中,填写以下模式:
self.productNameViewController = segue.destinationViewController;
self.productNameViewController.delegate = self;
注意prepareForSeque:sender:
在任何viewDidLoad之前触发,因此你有引用:从父母的角度来做所有的设置。 self.productNameViewController.titleLabel.text = @"Product Name";
孩子们会先开火,不管向nil发送信息什么都不做,所以他们和想象中的孩子一起玩很好。如果他们需要发送信息或询问重要信息,他们会有代表。
这可能看起来很麻烦,标识符肯定是。但是,在处理IB中的布局时,在代码中保持集中控制的好处显而易见,作为处理视图控制器的一种方式。