Ios 无需猜测即可从nib文件加载UIView
好的,还有一个问题 我正在创建一个名为Ios 无需猜测即可从nib文件加载UIView,ios,memory-management,uiview,uiviewcontroller,Ios,Memory Management,Uiview,Uiviewcontroller,好的,还有一个问题 我正在创建一个名为ProgressView的UIView,它是一个半透明的视图,带有活动指示器和进度条 如果需要,我希望能够在我的应用程序中的不同视图控制器中使用此视图 我知道3种不同的方法(但我只对其中一种感兴趣): 1) 以编程方式创建整个视图,根据需要实例化和配置。不用担心,我有这个 2) 在interface builder中创建UIView,添加所需的对象,并使用如下方法加载它。问题是我们基本上猜测视图是objectAtIndex:0,因为在文档中我没有找到对从[[
ProgressView
的UIView,它是一个半透明的视图,带有活动指示器和进度条
如果需要,我希望能够在我的应用程序中的不同视图控制器中使用此视图
我知道3种不同的方法(但我只对其中一种感兴趣):
1) 以编程方式创建整个视图,根据需要实例化和配置。不用担心,我有这个
2) 在interface builder中创建UIView,添加所需的对象,并使用如下方法加载它。问题是我们基本上猜测视图是objectAtIndex:0,因为在文档中我没有找到对从[[NSBundle mainBundle]loadNibName:
函数返回的元素顺序的引用
NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:@"yournib"
owner:self
options:nil];
UIView *myView = [nibContents objectAtIndex:0];
myView.frame = CGRectMake(0,0,300,400); //or whatever coordinates you need
[scrollview addSubview:myView];
3) 子类UIViewController,并让它按照正常方式管理视图。在这种情况下,我永远不会将视图控制器推到堆栈上,而只将其主视图:
ProgressViewController *vc = [[ProgressViewController alloc] initWithNibName:@"ProgressView" bundle:nil];
[vc.view setCenter:CGPointMake(self.view.center.x, self.view.center.y)];
[self.view addSubview:vc.view];
[vc release];
就我所知,#3是正确的方法(除了编程),但我不完全确定在另一个控制器的视图保留其主视图时释放ProgressView的视图控制器是否安全(gut feel说它会泄漏?)
在这种情况下,我应该在内存管理方面做些什么,何时何地释放ProgressView的视图控制器
提前感谢您的想法
干杯
Rog我投票支持选项2。来自-[NSBundle loadNibNamed]的返回值是顶级对象数组。因此,只要nib中只有一个顶级对象,那么索引0将是正确的。其他视图是子视图,而不是顶级对象
当然,另一种选择是为所有视图控制器创建一个超类,其中包括一个名为“progressView”的出口,然后将视图连接到nib中文件所有者的该出口。不过,这似乎有些过分。我认为您的解决方案#3通过引入将UIViewController实例定义为ProgressView的容器,以便您可以设置nib绑定。虽然我确实认为能够使用IBOutlet绑定属性而不是迭代nib内容是很好的,但您可以这样做,而无需引入您既不需要也不想要其行为的UIViewController。这应该是避免混淆如何以及何时释放视图控制器,以及它可能对响应者链或加载视图的其他行为产生的副作用(如果有) 相反,请重新考虑使用NSBundle并利用
owner
参数的强大功能
@interface ProgressViewContainer : NSObject {
}
@property (nonatomic, retain) IBOutlet ProgressView *progressView;
@end
@implementation ProgressViewContainer
@synthesize progressView = progressView;
- (void) dealloc {
[progressView release];
[super dealloc];
}
@end
@interface ProgressView : UIView {
}
+ (ProgressView *) newProgressView;
@end
@implementation ProgressView
+ (ProgressView *) newProgressView {
ProgressViewContainer *container = [[ProgressViewContainer alloc] init];
[[NSBundle mainBundle] loadNibNamed:@"ProgressView" owner:container options:nil];
ProgressView *progressView = [container.progressView retain];
[container release];
return progressView;
}
@end
创建一个名为“ProgressView”的nib,其中包含ProgressView,并将其文件的所有者类设置为ProgressViewContainer。现在您可以创建从nib加载的ProgressView
ProgressView *progressView = [ProgressView newProgressView];
[scrollView addSubview:progressView];
[progressView release];
如果您有多个进度视图配置,那么您可能希望在ProgressView上实现-initWithNibNamed:
方法,而不是+newProgressView
,这样您可以指定使用哪个nib来创建每个ProgressView实例。我也更喜欢备选方案2。如果“0”困扰您,您可以:
- 创建名为ProgressView的UIView子类
- 创建一个名为ProgressView.xib的nib文件,描述您的进度视图
- 选择nib中最顶层的视图,并在interface builder中将其类设置为ProgressView
NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:@"ProgressView" owner:self options:nil];
ProgressView *progressView = nil;
for (UIView *view in nibContents) {
if ([view isKindOfClass:[ProgressView class]]) {
progressView = (ProgressView *) view;
break;
}
}
if (progressView != nil) {
//Use progressView here
}
我最终在UIView中添加了一个类别:
#import "UIViewNibLoading.h"
@implementation UIView (UIViewNibLoading)
+ (id) loadNibNamed:(NSString *) nibName {
return [UIView loadNibNamed:nibName fromBundle:[NSBundle mainBundle] retainingObjectWithTag:1];
}
+ (id) loadNibNamed:(NSString *) nibName fromBundle:(NSBundle *) bundle retainingObjectWithTag:(NSUInteger) tag {
NSArray * nib = [bundle loadNibNamed:nibName owner:nil options:nil];
if(!nib) return nil;
UIView * target = nil;
for(UIView * view in nib) {
if(view.tag == tag) {
target = [view retain];
break;
}
}
if(target && [target respondsToSelector:@selector(viewDidLoad)]) {
[target performSelector:@selector(viewDidLoad)];
}
return [target autorelease];
}
@end
此处的解释:我可以评论一下,如果您将所有者设置为代码中所示的self,我相信您仍然会收到错误。如果我错了,请纠正我,但我能够实现这一点的唯一方法是将所有者设置为“容器”对象。嘿,这对我有用,谢谢。我会说这有点奇怪,不完全是直观的-例如,我第一次忘了连接IBOutlet。看起来苹果应该让这个功能更容易访问。