什么时候设置XIB插座属性?

时间:2013-04-11 14:37:55

标签: ios ios6 xib

我正在尝试使用xib文件实现继承。是的,有点奇怪,但让我告诉你为什么。

我有一个类,我的许多视图控制器继承的SLBaseViewController。当我想要一个子视图控制器时,我会以通常的方式创建它:

    SLHomeViewController *controller = [[SLHomeViewController  alloc] initWithNibName:@"SLHomeViewController" bundle:nil];

这很好用。 SLHomeViewController是一个SLBaseViewController(它是一个UIViewController)。

我这样做是因为我有其他视图控制器,我想继承SLBaseViewController行为。在我的例子中,我有一个在我的应用程序中常见的导航UI小部件,因此SLSceneViewControll也继承自SLBaseViewController,SLHomeViewController和SLSceneViewController都获得自定义导航小部件行为。

自定义导航窗口小部件还具有在SLBaseViewControllers中通用的位置信息。所以我实现了一个穷人做xib继承的方法。

@interface SLBaseViewController : UIViewController <SLNavBarViewControllerDelegate>
@property (strong, nonatomic) IBOutlet UIView *navBarExtendedFPO;

并且继承在initWithNibName

中完成
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        Class callingClass = [self class];
        Class slBaseViewControllerClass = NSClassFromString (SL_BASE_VC_CLASS_NAME);
        if (callingClass !=  slBaseViewControllerClass) {
            SLBaseViewController *controller = [[SLBaseViewController  alloc] initWithNibName:@"SLBaseViewController" bundle:nil];
            // now load all the properties by hand
            self.navBarExtendedFPO = controller.navBarExtendedFPO;
        }
    }
    return self;
}

如果我创建SLHomeViewController,则加载SLBaseViewController的xib,然后从中复制有趣的属性。如果initWithNibName检测到它正在加载SLBaseViewController,它就什么都不做,阻止了无限循环。

问题是,当然还没有设置插座属性。所以它只是复制nil。

那么这些插座属性何时设定?

或者 - 是否有更好的方法来做我想做的事情?在我手工复制属性之前,这一切看起来都很美好。这对我来说似乎很脆弱。

(注意,我只使用iOS6解决方案。)

1 个答案:

答案 0 :(得分:5)

这是因为UIViewController的延迟初始化。

UIViewController的视图只会在一些之后加载 一个人调用view属性。

像那样:

controller.view

因此,在您的情况下,您可以在controller.view

之前致电self.navBarExtendedFPO = controller.navBarExtendedFPO;

为了更清楚地解释视图生命周期,有一个例子:

SLBaseViewController中有重写的方法,self.label是模拟的 在XIB文件中定义的navBarExtendedFPO

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        NSLog(@"initWithNibName: view loaded - %d , IBOuttlet loaded - %d", [self isViewLoaded], self.label != nil);
    }
    return self;
}

- (void)loadView {
    NSLog(@"loadView1: view loaded - %d , IBOuttlet loaded - %d", [self isViewLoaded], self.label != nil);
    [super loadView];
     NSLog(@"loadView2: view loaded - %d , IBOuttlet loaded - %d", [self isViewLoaded], self.label != nil);
}

- (void)viewDidLoad
{
    NSLog(@"viewDidLoad1: view loaded - %d , IBOuttlet loaded - %d", [self isViewLoaded], self.label != nil);
    [super viewDidLoad];
    NSLog(@"viewDidLoad2: view loaded - %d , IBOuttlet loaded - %d", [self isViewLoaded], self.label != nil);
}

并且有创建SLBaseViewController的方法

SLBaseViewController *testController = [[SLBaseViewController alloc] initWithNibName:@"SLBaseViewController" bundle:nil];
NSLog(@"after initialization: view loaded - %d , IBOuttlet loaded - %d", [testController isViewLoaded], testController.label != nil);
UIView * testView = testController.view;
NSLog(@"after calling testView.view: view loaded - %d , IBOuttlet loaded - %d", [testController isViewLoaded], testController.label != nil);

所以,有我们的日志:

initWithNibName: view loaded - 0 , IBOuttlet loaded - 0
after initialization: view loaded - 0 , IBOuttlet loaded - 0
loadView1: view loaded - 0 , IBOuttlet loaded - 0
loadView2: view loaded - 1 , IBOuttlet loaded - 1
viewDidLoad1: view loaded - 1 , IBOuttlet loaded - 1
viewDidLoad2: view loaded - 1 , IBOuttlet loaded - 1
after calling testView.view: view loaded - 1 , IBOuttlet loaded - 1