Download UIView from nib file without guesses

Ok, here's another question.

I am creating a UIView called ProgressView , which is a translucent view with an activity indicator and a progress indicator.

I want to be able to use this view in different view managers in my application, when necessary.

I know three different ways to do this (but I'm only interested in one):

1) Create the whole view programmatically, create and customize as needed. Don’t worry, I get this one.

2) Create a UIView in the interface builder, add the necessary objects and load it using a method similar to the one below. The problem is that we basically assume that the view is objectAtIndex: 0, because nowhere in the documentation did I find a reference to the order of the elements returned by the [[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) Subclass UIViewController and let it control the view in accordance with normal. In this case, I would never push the view controller onto the stack, but only its main view:

 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]; 

As far as I can tell, # 3 is the right way to do this (except programmatically), but I'm not quite sure that it is safe to free the ProgressView view controller, while the other kind of controller retains its main look (Does it feel like it will expire?) ?

What should I do in terms of memory management in this case, where and when should I release the ProgressView view controller?

Thanks in advance for your thoughts.

Greetings

Horn

+7
source share
4 answers

I think your solution # 3 adds unnecessary complexity by introducing an instance of UIViewController as a container for your ProgressView so that you can set up nib bindings. Although I think it’s nice to work with the property bound to IBOutlet, and not iterate the contents of the nib, which you can do without introducing a UIViewController, whose behavior you do not need and do not need. This should avoid your confusion as to how and when to release the view controller and what, if any, side effects it might have in the responder chain or other behaviors of the loaded view.

Instead, try redefining the use of NSBundle and taking advantage of the owner argument.

 @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 

Create a thread called "ProgressView" containing the ProgressView and set the File Owner class for it to the ProgressViewContainer. Now you can create ProgressViews loaded from your nib.

 ProgressView *progressView = [ProgressView newProgressView]; [scrollView addSubview:progressView]; [progressView release]; 

If you have several configurations of your progress view, you might want to implement the -initWithNibNamed: method in ProgressView instead of +newProgressView so that you can specify which nib to use to create each instance of ProgressView.

+10
source

I will vote for option No. 2. The return value is [NSBundle loadNibNamed] - this is an array of top-level objects. So for now, you only have one top-level object in your nib, then index 0 will be correct. Other views are subviews, not top-level objects.

Another option, of course, is to create a superclass for all your view controllers, which includes an output called "progressView", and then connecting your view to this outlet for the file owner in the bank. It seems like too much.

+3
source

I also prefer alternative # 2. If "0" bothers you, you can:

  • Create a subclass of UIView called ProgressView
  • Create a nib file called ProgressView.xib that describes your view of progress.
  • Select the topmost view in your nib and set its class to ProgressView in the interface constructor

then do

 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 } 
+3
source

I ended up adding a UIView category for this:

  #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 

here: http://gngrwzrd.com/blog-view-controller-less-view-loading-ios-mac.html

+3
source

All Articles