14

私はUIViewControllerいくつかのコントローラーといくつかのビューを持っています。これらのビューのうちの 2 つ (グリッド セル) は他のニブです。Grid Cells から File's Owner へのアウトレットがありますが、それらは自動的にロードされません。

GridCell.mだから私はのをオーバーライドしようとしますinitWithCoder。これにより、無限ループが開始されます。

initWithFrameコードからサブビューをオーバーライドして追加することは可能ですが、これは私が望むものではありません。Interface Builder でビューを移動し、Xcode で正しいフレームでビューを初期化できるようにしたいと考えています。

これを達成するにはどうすればよいですか?

編集1

アレクサンダーの助けを借りてそれを機能させようとしています。これが私が今セットアップした方法です: MainView には、GridCell として設定された Custom クラスを持つ UIView があります。MainView/File's Owner にアウトレットがありました。

写真1

GridCell.m からすべての init-code を削除し、カスタム クラスへのアウトレットを設定しました

写真2

写真3

ただし、MainView にはまだ GridCell が表示されません。エラーはありません。赤いスイッチがあるはずの場所が寂しいだけです。私は何を間違っていますか?

私はこれをプログラムで行うことに非常に近づいています。私はペン先でこれを行う方法を学びたいと思っています。

4

5 に答える 5

45

nib をロードすると、initWithCoder が再度呼び出されるため、サブクラスに現在サブビューがない場合にのみ呼び出します。

-(id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        if (self.subviews.count == 0) {
            UINib *nib = [UINib nibWithNibName:NSStringFromClass([self class]) bundle:nil];
            UIView *subview = [[nib instantiateWithOwner:self options:nil] objectAtIndex:0];
            subview.frame = self.bounds;
            [self addSubview:subview];
        }
    }
    return self;
}
于 2012-07-31T15:33:12.090 に答える
11

nib をロードすると、対応する所有者が

  -(id) initWithCoder:(NSCoder *) coder;  

電話

したがって、この方法であなたのクーデ:

self = [[[NSBundle mainBundle] loadNibNamed: @"GridCell"
owner: self
options: nil] objectAtIndex:0];

initWithCoder メソッドの呼び出しが再び発生します。これは、ペン先を再度ロードしようとするためです。カスタムUIViewを定義し、そのサブビューをレイアウトするためにnibファイルを作成する場合、UIViewを別のnibファイルに追加するだけではなく、IBのクラス名をカスタムクラスに変更し、nibローディングシステムがそれを理解することを期待します. あなたができることは次のとおりです。

カスタム ビューの nib ファイルには、「ファイルの所有者」クラスをカスタム ビュー クラスに設定する必要があります。すべてのサブビューのコンテナー。ビュー クラスにアウトレットを追加し、サブビューを「ファイルの所有者」(カスタム UIView) に接続します。( https://stackoverflow.com/a/7589220/925622を参照)

編集 さて、編集した質問に答えるには、次のようにします。

カスタムビューを含めたいnibファイルに移動し、nibファイルをレイアウトします。カスタム ビュー (GridCell) 自体にしないでください。代わりに、グリッド セルを含むビューを作成します (たとえば、gridCellContainer ですが、UIView にする必要があります)。initWithCoder で行ったように、カスタム ビュー内で initWithFrame メソッドをカスタマイズします。

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"GridCell" owner:self options:nil];    
        self = [nib objectAtIndex:0];
        self.frame = frame;
    }
    return self;
}

そして、カスタム ビュー (gridCellContainer ビューを持つビュー) を含めるビューの fileOwner である viewController で、viewDidLoad などでこれを行います。

//...
GridCell *gridCell = [[GridCell alloc] initWithFrame:self.viewGridCellContainer.bounds];
[self.viewGridCellContainer addSubview:gridCell];

これで、すべてが期待どおりに機能するはずです

于 2012-07-12T11:22:54.870 に答える
2

ファイルの所有者は呼び出しを受けません

  -(id) initWithCoder:(NSCoder *) coder;  

xibをロードするとき。

ただし、その xib で定義されたすべてのビューは、への呼び出しを取得します。

-(id) initWithCoder:(NSCoder *) coder;  

xibをロードするとき。

UIView (つまり GridCell) のサブクラスが xib で定義されていて、サブクラスの initWithCoder で同じ xib をロードしようとすると、無限ループが発生します。ただし、ユースケースがどうなるかわかりません。

通常、UIView のサブクラス (つまり GridCell) を 1 つの xib で設計し、そのサブクラスをビュー コントローラーの xib などで使用します。

また、カスタム ビューの initWithCoder にサブビューがあるユース ケースも見られません。

-(id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        if (self.subviews.count == 0) {
            UINib *nib = [UINib nibWithNibName:NSStringFromClass([self class]) bundle:nil];
            UIView *subview = [[nib instantiateWithOwner:self options:nil] objectAtIndex:0];
            subview.frame = self.bounds;
            [self addSubview:subview];
        }
    }
    return self;
}

他のxibでオンデマンドでビュー階層をオーバーライドできるようにしたい場合を除きます。どの IMO が外部依存関係 (つまり、別の xib で定義された階層) を想定しており、そもそも再利用可能な UIView を持つという目的を無効にします。

xib をロードするときに、ファイルの所有者としてインスタンスを渡すと、すべての IBOutlet が設定されることに注意してください。その場合、self (つまり GridCell) をその GridCell.xib のルート ビューに置き換えることになり、その過程ですべての IBOutlet 接続が失われます。

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"GridCell" owner:self options:nil];    
        self = [nib objectAtIndex:0];
        self.frame = frame;
    }
    return self;
}

「再利用可能な UIView を実装する方法」に関するより詳細な投稿があり、これももう少し詳しく説明されており、問題が解決されることを願っています。

于 2014-09-25T00:03:53.740 に答える
1

loadNibNamed:: は initWithCoder を呼び出します:

このパターンに従わないのはなぜですか?

-(id)initWithCoder:(NSCoder *)coder
{

    if (self = [super initWithcoder:coder]) {

       // do stuff here ... 

    }

    return self;                 
}

[super initWithcoder:coder]避けたいことをしますか?

于 2012-07-12T11:07:40.010 に答える
0

initWithsomethingメソッドをオーバーライドしようとしているときに同じ問題が発生しました。

-(id)initWithsomething:(Something *)something
{
    if (self = [super initWithsomething:something]) {
       // do stuff here ... 
    }

    return self; 
}

代わりは

-(id)initWithsomething:(Something *)something
{
    if (self = [super init]) {
       // do stuff here ... 
    }

    return self;
}
于 2012-11-13T11:32:19.070 に答える