カスタムuiview(MyCustomView)がNIB(MyCustomView.xib)からビューをロードする際に問題が発生しました。
問題は、MyCustomViewが他のXIBで再利用されるため、awakeFromNibが呼び出されることです。CustomView.xibにはMyCustomViewのインスタンスも含まれているため、MyCustomView.awakeFromNibのloadNibNamedは無限ループに入ります
imは次のように無限ループを取得します:
SomeVC.xib
+ calls MyCustomView awakeFromNib
++ which calls loadNibNamed: MyCustomView.nib
+++++ but top level View is also instance of MyCustomView
....so awakeFromNib: goes into infinite loop
カスタムビューがペン先から自分自身をロードするときに、トップレベルのUIViewをMyCustomViewのインスタンスにすべきではないかと思っていますか?もしそうなら、どのようにアウトレット/アクションを接続しますか(代わりにMyCustomViewをファイル所有者にしますか?)
とにかく乾杯
LONG EXPLANATION:
いくつかの画面で再利用したいボタンの列があります。そこで、カスタムビューを作成しました
@interface ScreenMenuButtonsView : UIView
@property (retain, nonatomic) IBOutlet UIButton *buttonHome;
@property (retain, nonatomic) IBOutlet UIButton *buttonMyMusic;
@property (retain, nonatomic) IBOutlet UIButton *buttonStore;
@property (retain, nonatomic) IBOutlet UIButton *buttonSocial;
@property (retain, nonatomic) IBOutlet UIButton *buttonSettings;
@end
ビューをIBでレイアウトしたかったので、NIBを作成しました
ScreenMenuButtonsView_iPad.xib
Files Owner: no set NSObject
VIEW: ScreenMenuButtonsView
+ UIButton
+ UIButton
+ UIButton
カスタムビューに独自のNIBを内部的にロードしたいので、 http: //nathanhjones.com/2011/02/20/creating-reusable-uiviews-with-a-drop-shadow-tutorial/ http:/の例を使用しました。 /nathanhjones.com/wp-content/uploads/2011/02/ReusableTableHeaders.zip
- (id)initWithFrame:(CGRect)frame {
//self = [super initWithFrame:frame]; // not needed - thanks ddickison
if (self) {
NSArray *nib = [[NSBundle mainBundle]
loadNibNamed:@"HeaderView"
owner:self
options:nil];
[self release]; // release object before reassignment to avoid leak - thanks ddickison
self = [nib objectAtIndex:0];
self.layer.shadowColor = [[UIColor blackColor] CGColor];
self.layer.shadowOffset = CGSizeMake(1.0, 1.0);
self.layer.shadowOpacity = 0.40;
}
return self;
}
CustomViewをインスタンス化するためにどこかでinitWithFrameを呼び出すことを前提としていることを除いて、これは問題ありません。HeaderViewの例では、次のように呼び出します。
// load the header - this could be done in viewWillAppear as well
HeaderView *header = [[HeaderView alloc]
initWithFrame:CGRectMake(0, 0, 320, 60)];
header.lblTitle.text = @"That. Just. Happened.";
tblData.tableHeaderView = header;
[header release];
他のXIBでカスタムビュークラスを使用できるようにしたかった
HomeScreenViewController.xib
Files Owner: HomeScreenViewController
View:
+ ....other controls
+ ScreenMenuButtonsView
問題は、HomeScreenViewControllerがロードされると、customViewでawakeFromNibを呼び出すことです。
そこで、initWithFrameをロードするnibをsetupViewというメソッドに移動し、initWithFrameANDawakeFromNibから呼び出しました。
- (id) initWithFrame:(CGRect)frame
{
if ( ( self = [super initWithFrame: frame] ) )
{
[self setUpView];
}
return self;
}
- (void)awakeFromNib
{
[self setUpView];
}
- (void) setUpView{
if (self) {
NSArray* nibViewsArray = nil;
if([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad){
//IPAD
nibViewsArray = [[NSBundle mainBundle] loadNibNamed:@"ScreenMenuButtonsView_iPad"
owner:self
options:nil];
...
}
私の問題は、HomeScreenViewController.xibがロードされたときです。
HomeScreenViewController.xib
Files Owner: HomeScreenViewController
View:
+ ....other controls
+ ScreenMenuButtonsView
ScreenMenuButtonsViewを作成しようとしますが、NIBではScreenMenuButtonsViewawakeFromNibを呼び出すためです。
しかし、ここではloadNibNamedを呼び出します。
- (void) setUpView{
_viewSetupAlready = TRUE;
//http://nathanhjones.com/2011/02/20/creating-reusable-uiviews-with-a-drop-shadow-tutorial/
//self = [super initWithFrame:frame]; // not needed - thanks ddickison
if (self) {
NSArray* nibViewsArray = nil;
if([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad){
//IPAD
nibViewsArray = [[NSBundle mainBundle] loadNibNamed:@"ScreenMenuButtonsView_iPad"
owner:self
options:nil];
}else{
//IPHONE
nibViewsArray = [[NSBundle mainBundle] loadNibNamed:@"ScreenMenuButtonsView_iPhone"
owner:self
options:nil];
}
if(nibViewsArray){
//[self release]; // release object before reassignment to avoid leak - thanks ddickison
UIView * myView = [nibViewsArray objectAtIndex: 0];
//Check the top level object in NIB is same type as this custom class
//if wrong you probably forgot to use correct NIB name in loadNibNamed:
if([myView isMemberOfClass:[self class]]){
self = (ScreenMenuButtonsView *)myView;
}else{
NSLog(@"ERROR:top level view is not same type as custom class - are you loading the correct nib filename in loadNibNamed:\n%@", myView);
}
}else{
NSLog(@"ERROR:nibViewsArray is nil");
}
}
}
loadNibName:ロード
ScreenMenuButtonsView_iPad.xib
Files Owner: no set NSObject
VIEW: ScreenMenuButtonsView
+ UIButton
+ UIButton
+ UIButton
ただし、上面図はScreenMenuButtonsViewであるため、新しいインスタンスを作成してawakeFromNibを呼び出すと、無限ループが発生します。
ScreenMenuButtonsViewのループが発生し、インスタンスがxibから別のインスタンスをロードしている理由を知っています。
私の質問は
ScreenMenuButtonsView_iPad.xib
Files Owner: no set NSObject
VIEW: ScreenMenuButtonsView
+ UIButton
+ UIButton
+ UIButton
VIEWを変更する必要があります:UIView
しかし、ボタンのアウトレットとアクションはどうですか:ファイル所有者を変更する必要があります:設定されていないNSObject
ビュークラスになる
ファイル所有者:ScreenMenuButtonsView