2012-02-10 17 views
0

このinitメソッドが対象を範囲外に戻すのはなぜですか?nibをロードするときにこのinitメソッドがオブジェクトを範囲外に戻すのはなぜですか?

XCode 4.2、基本SDK 4.3、およびARCを使用して、UIViewをnib(UIViewControllerではなく)からロードしようとしています。私は、そのプロセスでUIViewControllerを使わないでください。

この回答をS.O.

@interface MyView : UIView 
@property (unsafe_unretained, nonatomic) IBOutlet UILabel *textLabel; 
@end 

: はHow to load a UIView using a nib file created with Interface Builder

私は、単一のラベルでのUIViewのサブクラスを作成した(ユーザー「MusiGenesis」によって答えはプロセスを説明):ここでの質問は、それはそれを行うことができるようになります。実装では、私はinitWithFrameをオーバーライドします:

- (id)initWithFrame:(CGRect)frame 
{ 
    //self = [super initWithFrame:frame]; 
    self = [JVUIKitUtils initWithNibName:@"MyView" withOwner:self]; 
    if(self) 
    { 
     NSLog(@"Created"); 
    } 
    return self; 
} 

IB 1つのビューで「MyView.xib」という名前のファイルを作成しました。それはサブビューとしてラベルを持っていて、ラベルプロパティをhファイルにドラッグして作成しました。

+ (id)initWithNibName:(NSString*)nibName withOwner:(id)uiView 
{ 
    id object = nil; 
    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:nibName owner:uiView options:nil]; // 1 object, out of scope 
    for(id tempObject in bundle) 
    { 
     if([tempObject isKindOfClass:[uiView class]]) object = tempObject; 
     break; 
    } 
    return object; 
} 

次のスクリーンショットで見ることができるように、バンドルは1つのオブジェクト参照を持っているが、それはスコープの外にあります:MyView nib file setup

、別のファイルに は、私はこの再利用可能な静的メソッドを作成しました。

とデバッグ: MyView is out of scope

これは、インスタンス化のために私のコードです:

subView = [[MyView alloc] initWithFrame:CGRectZero]; // ok 
NSAssert(subView != nil, @"MyView was nil"); // fail 

なぜ他のS.O.上の任意のアイデアポスターは働くことができましたが、これはありませんか?

+0

あなたは 'self = [JVUIKitUtils initWithNibName:@" MyView "withOwner:self]'で何をしようとしているのか分かりませんが、それは絶対に*間違いです*。 –

+0

静的クラスからnibをロードしようとしています。なぜこれは間違っていますか? – TigerCoding

+0

また、基本SDKが4.3のARCを使用することはできません。 – hwaxxer

答えて

3

所有者の使用は、ペン先をロードする方法が少し混乱しているようです。ペン先の所有者とその中の最初のオブジェクトの両方としてビューを使用しようとしているようです。

nibからMyViewをロードしようとしていますか(つまり、MyViewとして定義されたnibファイル内のビューのクラス)、またはNibからMyViewのサブビューをロードしようとしていますか?

ペン先のビューがMyViewの場合、ロードする方法は次のとおりです。

@implementation UIView (NibLoading) 

+ (id)viewWithNibName:(NSString*)nibName 
{ 
    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:nibName owner:nil options:nil]; 
    if ([bundle count]) 
    { 
     UIView *view = [bundle objectAtIndex:0]; 
     if ([view isKindOfClass:self]) 
     { 
      return view; 
     } 
     NSLog(@"The object in the nib %@ is a %@, not a %@", nibName, [view class], self); 
    } 
    return nil; 
} 

@end 

あなたが(ビューがペン先に定義された最初の項目にする必要がある)のnibファイルからビューのいずれかの種類をロードできるようになる:UIViewの上のカテゴリーとして、この静的メソッドを作成します。 、nibファイル内のファイルの所有者として定義されMYVIEWで、ペン先の内部ビューがMYVIEWされていない場合

MyView *view = [MyView viewWithNibName:@"MyView"]; 

をしますが、MYVIEWのサブビューとして、それをロードしたい:あなたはこのようなあなたのビューを作成しますこのようにそれを実行します。

@implementation UIView (NibLoading) 

- (void)loadContentsFromNibName:(NSString*)nibName 
{ 
    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:nil]; 
    if ([bundle count]) 
    { 
     UIView *view = [bundle objectAtIndex:0]; 
     if ([view isKindOfClass:[UIView class]]) 
     { 
      //resize view to fit 
      view.frame = self.bounds; 

      //add as subview 
      [self addSubview:view]; 
     } 
     NSLog(@"The object in the nib %@ is a %@, not a UIView", nibName, [view class]); 
    } 
} 

@end 

そのアプローチを使用して、ちょうどinitWithFrameを使用して、通常のように、あなたのビューを作成し、その後、ペン先から内容をLOAするloadContentsFromNibNameを呼び出します。あなたはこのようなあなたのビューをロードします:

MyView *view = [[MyView alloc] initWithFrame:CGRect(0,0,100,100)]; 
[view loadContentsFromNibName:@"MyView"]; 
+0

これをclairwareの答えと組み合わせることで、すぐに試してみましょう。 – TigerCoding

+0

それらを組み合わせる必要はありません。それらは、同じアプローチの両方のわずかに異なるバリエーションです。いずれか動作する必要があります(私は実装するコードは少ないですが;-)) –

+0

2番目の実装は私が後にしている、瞬間に応答します。 – TigerCoding

0

あなた[JVUIKitUtils initWithNibName:@"MyView" withOwner:self]アプローチは、すべて間違っています。 initメソッドが呼び出されると、オブジェクトはすでに[MyView alloc]の呼び出しによって割り当てられています。あなたがスーパーinitメソッドに呼び出しを連鎖させる理由は、これがデイジーチェーンでNSObjectのinitメソッドにつながり、単純にインスタンスを返すからです。

JVUIKitUtilsから返された(自動解放された)インスタンス値に "self"を設定すると、有効範囲外エラーを生成する[MyView alloc]への呼び出しによって割り当てられたメモリアドレス以外のメモリアドレスに設定されます。

代わりに、作成しようとしているinitメソッドを作成しないでください。状態メソッドでペン先のビューを作成して初期化する方法はすでにあります。私は名前を変更してのようなものだろう:

+ (UIView)newViewWithNibName:(NSString*)nibName withClassType:(Class)uiView 
{ 
    id object = nil; 

    // you need some object to assign nib file owner to. use an NSObject. 
    NSObject* owner = [[NSObject alloc] init]; 
    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:nibName owner:owner options:nil]; // 1 object, out of scope 
    for(id tempObject in bundle) 
    { 
     if([tempObject isKindOfClass:]) object = [tempObject retain]; 
     break; 
    } 
    [owner release]; 
    return object; 
} 

をして、それが好き呼び出す:

MyView* subView = [JVUIKitUtils viewWithNibName:@"MyView" withClassType:[MyView class]]; 

私はこのコードをテストしていません。あなたの感情は変わるかもしれません。

関連する問題