web-dev-qa-db-ja.com

iOS loadNibNamedの混乱、ベストプラクティスは何ですか?

私は自分のUIViewサブクラスのXIBを作成するプロセスのほとんどに精通していますが、すべてが私にとって適切に機能しているわけではありません。ほとんどの場合、IBOutletsがリンクしているためです。私は彼らに回り道のように見えるように働かせることができます。

私のセットアップはこれです:

  • MyClass.hとMyClass.mがあります。これらには、UIView(ビューと呼ばれる)とUILabel(myLabelと呼ばれる)用のIBOutletsがあります。オンラインでいくつかの例でこれが必要であると示唆されているように見えたので「view」プロパティを追加しましたが、ビュープロパティが見つからなかったためにクラッシュしていた問題を実際に解決しました。 。
  • MyClass.xibというXIBファイルがあり、そのファイルの所有者カスタムクラスはMyClassです。これは、そのクラスの.hと.mが存在した後に正しく入力されています。

私のinitメソッドは私が問題を抱えているところです。

NSBundle mainBundleの 'loadNibNamed'メソッドを使用して所有者を 'self'に設定しようとしましたが、ビューのインスタンスを作成し、そのアウトレットがクラス内のアウトレットに自動的に一致することを期待していました(わかっています)これを行う方法と私はそれに注意しています)。次に、「自己」を、そのニブのインデックス0のサブビューに等しくしたいのではなく、

self = [super init];

またはそのような何か。

私はここで間違っていると感じていますが、オンラインの例ではinitメソッドで同様のことが行われていますが、サブビュー0をビュープロパティに割り当て、それを子として追加していますが、それは合計ではありません2つのMyClassインスタンス? loadNibNamedを介してインスタンス化された子MyClassを含む、本質的にIBOutletsにリンクされていないもの?あるいは、せいぜい、最初にMyClassの直接の子として必要なすべてのIBOutletを含む追加の中間UIViewを持つMyClassインスタンスではないのですか?導入された子UIViewが私が探していた実際のフレームサイズを返すとき、それは0を返すので、instanceOfMyClass.frame.size.widthのようなことをすることになると、それはわずかな不快感をもたらします。

私が間違っているのは、initメソッド内でloadNibNamedをいじっていることですか?私はもっ​​とこのようなことをするべきですか?

MyClass *instance = [[MyClass alloc] init];
[[NSBundle mainBundle] loadNibNamed:@"MyClass" owner:instance options:nil];  

またはこのように?

MyClass *instance = [[[NSBundle mainBundle] loadNibNamed:@"MyClass" owner:nil options:nil] objectAtIndex:0]; 

ご協力をよろしくお願いいたします。

22
Cloov

2番目のオプションは正しいものです。あなたができる最も防御的なコードは次のようなものです:

+ (id)loadNibNamed:(NSString *)nibName ofClass:(Class)objClass {
    if (nibName && objClass) {
        NSArray *objects = [[NSBundle mainBundle] loadNibNamed:nibName 
                                                         owner:nil 
                                                       options:nil];            
        for (id currentObject in objects ){
            if ([currentObject isKindOfClass:objClass])
                return currentObject;
        }
    }

    return nil;
}

そして、このように呼び出します:

MyClass *myClassInstance = [Utility loadNibNamed:@"the_nib_name" 
                                         ofClass:[MyClass class]]; 
// In my case, the code is in a Utility class, you should 
// put it wherever it fits best

MyClassがUIViewのサブクラスであると想定していますか?その場合は、.xibのUIViewが実際にMyClassクラスのものであることを確認する必要があります。これは、ビューを選択した後、インターフェイスビルダーの右側の3番目のタブで定義されます

23
Ismael

必要なのは、loadNibNamedを介してサブビューを作成し、フレームを設定して、それをサブビューに追加することだけです。たとえば、私はMyViewクラスを使用して3つのサブビューを追加しています。これは、NIBで定義されているUIViewサブクラスであるMyView.xib

したがって、initWithFrameサブクラスにUIViewを定義します。

- (id)initWithFrame:(CGRect)frame
{
    NSLog(@"%s", __FUNCTION__);

    self = [super initWithFrame:frame];
    if (self)
    {
        NSArray *nibContents = 
          [[NSBundle mainBundle] loadNibNamed:@"MyView" 
                                        owner:self 
                                      options:nil];
        [self addSubview:nibContents[0]];
    }
    return self;
}

したがって、たとえば、私のUIViewControllerでは、これらのサブクラス化されたUIViewオブジェクトをいくつかロードできます。

for (NSInteger i = 0; i < 3; i++)
{
    CGRect frame = CGRectMake(0.0, i * 100.0 + 75.0, 320.0, 100.0);
    MyView *myView = [[MyView alloc] initWithFrame:frame];
    [self.view addSubview:myView];

    // if you want, do something with it: 
    // Here I'm initializing a text field and label

    myView.textField.text = [NSString stringWithFormat:@"MyView textfield #%d",
                              i + 1];
    myView.label.text = [NSString stringWithFormat:@"MyView label #%d", 
                          i + 1];
}

私は最初に使用コントローラーに助言しました、そして私は歴史的な参照のためにその答えを下に保ちます。


元の答え:

ここにはビューコントローラへの参照はありません。通常、UIViewControllerのサブクラスがあり、それを使用してインスタンス化します

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

// then you can do stuff like
//
// [self presentViewController:controller animated:YES completion:nil];

NIBファイル、MyClass.xibは、必要に応じて、ビューに関連するすべてのコードがあるUIViewの基本クラスを指定できます(たとえば、MyClassがUIViewのサブクラスであると想定しています)。

7
Rob

ここに私が使用する1つの方法があります:

  1. UIViewのサブクラスを作成します。これはMyClassと呼ばれます
  2. ビューxibファイルを作成します。インターフェイスビルダーで開き、[ファイルの所有者]をクリックして、IDインスペクターでクラスを親のビューコントローラーのクラスに変更します。 ParentViewController
  3. オブジェクトのリストに既にあるビューをクリックし、Identity InspectorでそのクラスをMyClassに変更します。
  4. MyClassで宣言したアウトレット/アクションは、ビューからクリックしてドラッグすることで接続されます(ファイルの所有者ではありません)。それらをParentViewControllerの変数に接続する場合は、ファイルの所有者からクリックアンドドラッグします。
  5. 次に、ParentViewControllerMyClassのインスタンス変数を宣言する必要があります。

ParentViewController.h以下を追加します。

@class MyClass

@interface ParentViewController : UIViewController {
    MyClass *myClass;
}

@property (strong, nonatomic) MyClass *myClass;

これを実装で合成し、viewDidLoadメソッドに以下を追加します。

- (void)viewDidLoad {
    [super viewDidLoad];

    [[NSBundle mainBundle] loadNibNamed:@"MyClass" owner:self options:nil];
    self.myClass.frame = CGRectMake(X,Y,W,H); //put your values in.
    [self.view addSubview:self.myClass];
}
2
sooper