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

Pau*_*nne 4 xib ios ios6

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

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

    SLHomeViewController *controller = [[SLHomeViewController  alloc] initWithNibName:@"SLHomeViewController" bundle:nil];
Run Code Online (Sandbox Code Playgroud)

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

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

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

@interface SLBaseViewController : UIViewController <SLNavBarViewControllerDelegate>
@property (strong, nonatomic) IBOutlet UIView *navBarExtendedFPO;
Run Code Online (Sandbox Code Playgroud)

并且继承在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;
}
Run Code Online (Sandbox Code Playgroud)

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

当然,问题是出口属性尚未设定.所以它只是复制零.

那么这些出口属性何时设定?

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

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

Ber*_*rgP 5

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

只有在调用view属性之后才会加载UIViewController的视图.

像那样:

controller.view
Run Code Online (Sandbox Code Playgroud)

所以,在你的情况下,你可以controller.view先打电话self.navBarExtendedFPO = controller.navBarExtendedFPO;

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

SLBaseViewController中有重写的方法,类似于XIB文件self.labelnavBarExtendedFPO定义的方法

- (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);
}
Run Code Online (Sandbox Code Playgroud)

并且有创建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);
Run Code Online (Sandbox Code Playgroud)

所以,有我们的日志:

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
Run Code Online (Sandbox Code Playgroud)