2013-04-11 52 views
4

我想用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; 

,如果我創建一個SLHomeViewController是加載SLBaseViewController的廈門國際銀行,然後將複製它有趣的屬性繼承在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; 
} 

完成。如果initWithNibName檢測到它正在加載一個SLBaseViewController,它什麼都不做,從而防止了無限循環。

問題是,當然,出口屬性尚未設置。所以它只是複製零。

那麼這些出口屬性何時設置?

或者 - 有沒有更好的方法來做我想做的事情?這一切似乎都是美好的,直到我手工複製這些屬性。這對我來說似乎很脆弱。

(請注意,我很好iOS6的,唯一的解決辦法。)

+0

好了,所以你有兩個'UIViewControllers'從第三'UIViewController'繼承,正確?這裏的問題是,你想在所有'UIViewController's' + UIViewController's' XIB中使用一個小部件,通常從你的子類中使用它?是嗎? – Peres 2013-04-11 14:45:58

+0

在視圖控制器中存在惰性初始化。所以,只有在調用屬性controller.view之後纔會加載視圖 - 在viewController中將調用loadView方法和viewDidLoad方法。 – BergP 2013-04-11 14:46:04

+0

是的,傑基男孩,除了可能會有超過2的方式。 – 2013-04-11 14:48:15

回答

5

這是因爲UIViewController的懶惰初始化。

UIViewController的視圖只有在調用某個視圖屬性的某個 後纔會加載。

這樣的:

controller.view 

所以,你的情況,你可以前self.navBarExtendedFPO = controller.navBarExtendedFPO;

調用controller.view爲了說明觀點的生命週期更清晰,有一個例子:

有在您的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