4

xib ファイルで継承を実装しようとしています。はい、少し奇妙ですが、その理由をお話ししましょう。

多くのビュー コントローラーが継承する SLBaseViewController クラスがあります。子ビュー コントローラーが必要な場合は、通常の方法で作成します。

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

これはうまくいきます。SLHomeViewController は SLBaseViewController (UIViewController) です。

SLBaseViewControllerの動作を継承したい他のView Controllerがあるため、これを行っています。私の場合、アプリ全体で共通のナビゲーション UI ウィジェットがあるため、SLSceneViewControll は SLBaseViewController からも継承され、SLHomeViewController と SLSceneViewController の両方がカスタム ナビゲーション ウィジェットの動作を取得します。

カスタム ナビゲーション ウィジェットには、SLBaseViewController 間で共通の位置情報もあります。そこで私は、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 のみのソリューションで問題ありません。)

4

1 に答える 1

5

UIViewController の遅延初期化が原因で発生します。

UIViewController のビューは、誰かがビュー プロパティを呼び出した後にのみロードされます。

そのように:

controller.view

したがって、あなたの場合、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);
}

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
于 2013-04-11T19:16:44.300 に答える