Memory cost using UIViewControllers.view or UIView directly - iphone

Hi everyone, sorry my English is not good.
I have the next question: what is better to add a view (My question is about the cost of memory and better programing methods)
Like this:
UIViewController *vcToAdd = [[UIViewController alloc]
initWithNibName:#"vcxib"
bundle:[NSBundle mainBundle]];
[self.view addSubview:vcToAdd.view];
Or like this:
NSArray *xibsArray = [[NSBundle mainBundle]
loadNibNamed:#"MMList_iPhone" owner:nil options:nil];
UIView *vwToAdd = [xibsArray objectAtIndex:0];
[self.view addSubview:vwToAdd];

In the first case you own the UIViewController you create, this means you are responsible for releasing it. If you don't release it, there will probably be a leak somewhere.
UIViewController *vcToAdd = [[UIViewController alloc] initWithNibName:#"vcxib" bundle:[NSBundle mainBundle]];
[self.view addSubview:vcToAdd.view];
[vcToAdd release];
In the second case you DON'T own the content of the Nib file. So you aren't responsible for managing memory. Anyway, here you are getting the content of a Nib file and presenting it "as it is". Without a UIViewController that controls its behavior.
If the view contained in your Nib file needs some complex management, for example animations or getting touches, UIViewController way is probably what you're looking for...
Take a look at Apple's Memory Management Guide here and here (in English).
EDIT: There is a third way... Create your view programmatically without using Nib files.
// Create your content view
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 480.0f)];
// Add objects to it
UIButton *button = [UIButton ...
UILabel *label = [UILabel ...
[view addSubview:button];
[view addSubview:label];
...
// Put your content view on screen
[self.view addSubview:view];
// Free memory
[view release];

Related

Can't edit any objects in method

I have a weird problem. I have a tab bar application. When I wanna set the text of an UILabel in any method, there happens nothing.
For example, nothing happens with 'label1' when I call this method:
-(void)setOne:(NSMutableArray *)theArray {
label1 = [[UILabel alloc] init];
label1.text = #"Test";
}
Does anyone have a solution for this problem?
Thanks,
Jelle
When you call this method a new label is created and the connection to the label which was previously associated with this ivar is lost. This could also be a memory leak.
Edit:
Depending on the rest of your code, this could work:
-(void)setOne:(NSMutableArray *)theArray {
label1.text = #"Test";
}
You don't see anything happened because you create new instance of label and do not add it anywhere. If you really want to add new label to your view then create it with appropriate frame and actually add it to some view, e.g.
-(void)setOne:(NSMutableArray *)theArray {
label1 = [[UILabel alloc] initWithFrame:CGRectMake(10.0f, 10.0f, 200.0f, 30.0f)];
label1.text = #"Test";
[self.view addSubview: label1];
// And do not forget to release your label!
[label1 release];
}
If you want to change text of label that already exists do not create new instance in your method, just set new text to it:
-(void)setOne:(NSMutableArray *)theArray {
// if label1 already exists we don't need to create a new one
label1.text = #"Test";
}
Edit: (from more info in comments)
When you create view controller it may not load its view immediately so in your code
FirstViewController *FVC = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
[FVC setOne:[resultaten objectAtIndex:indexPath.row]];
when you call setOne method fvc's view may still not be loaded and label1 is still nil in that method. You can solve that forcing controller's view to load, the following should work:
FirstViewController *FVC = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
FVC.view;
[FVC setOne:[resultaten objectAtIndex:indexPath.row]];
But in general I'd suggest to store your values in some class that's independent from UI (i.e. Model) or at least in separate variable of your controller and set it to UI elements only when they actually loaded or appear on screen (in viewDidLoad or viewWillAppear methods)
- (void)viewDidLoad
{
[super viewDidLoad];
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 200, 22)];
lbl.text =#"Hello";
[self.view addSubview:lbl];
}

Two view App with root template view

Hi I was wanted to do Application witch have a root template view with a nice logo on top or something adn load other views just below
(here is what I have right now: Test App
)
But I have a little problem. If I'll remove a comment in file TestAppDelegate.m on line 58
//[currentView release];
Application will crash with bunch of errors when I try to switch views.
But if I comment this line Project analyzer is telling me that I have a potential leak
with currentView variable.
Can somebody spare some time and see in that code what I did wrong?
The problem is that you are only adding currentView.view as a subview so that is being retained elsewhere but currentView itself is not. This means that when you release it, it is consequently dealloc'd and its view will have difficulty working without it.
One solution would be to have currentView as an instance variable and create a property for it so that the memory mangement is done for you.
#property (nonatomic, retain) UIViewController *currentView;
and then replace a line like
currentView = [[First alloc] initWithNibName:#"First" bundle:nil];
with
self.currentView = [[First alloc] initWithNibName:#"First" bundle:nil];
This will release the old view controller before retaining the new one. Then lastly don't forget to release currentView in the dealloc method of the class.
I have a function and it looks like this:
- (void) switchView: (int) viewType {
for (UIView *view in [self.viewController.rootView subviews]) {
[view removeFromSuperview];
}
UIViewController *currentView = nil;
switch (viewType) {
case 1:
currentView = [[First alloc] initWithNibName:#"First" bundle:nil];
break;
case 2:
currentView = [[Second alloc] initWithNibName:#"Second" bundle:nil];
break;
}
[self.viewController.rootView addSubview: [currentView view]];
[self.window makeKeyAndVisible];
//[currentView release];
}

Does UIViewController root UIView autosize?

Previously when setting up controllers programatically I have always set the size and position of the root UIView element (i.e.)
// UIViewController -loadView
CGRect viewFrame = CGRectMake(0, 20, 320, 460);
UIView *view = [[UIView alloc] initWithFrame:viewFrame];
[self setView:view];
[view release];
I have just noticed (and I wonder if anyone can confirm) that if your adding the root UIView to a controller that you don't need to set the size or position as it autosizes to the space available. (i.e.)
// UIViewController -loadView
UIView *view = [[UIView alloc] init];
[self setView:view];
[view release];
I understand that subsequent UIViews (i.e. UIButton, UILabel etc.) will need to be positioned and sized, I just want to make sure I am understanding the behaviour I am currently seeing.
It does resize the frame of the view.
UIView *view1 = [[UIView alloc] init];
NSLog(#"ViewFrame before set:%#",NSStringFromCGRect(view1.frame));
[self setView:view1];
NSLog(#"ViewFrame after set:%#",NSStringFromCGRect(view1.frame));
[view1 release];
But I could not find anything in docs that justify this.
Size of the root view of any UIViewController is managed by that controller's parent instance, that may be another controller or window. It determines the size automatically. For example, if you are creating UITabBarController, it determines sizes of all its child controllers' root views. Or, if you write your own container view controller it must determine sizes of root views of its child controllers.
See "View Management" section in this topic:
UIViewController Class Reference

How to initialize UIView from separate file in ViewController?

I've always used IB but am trying to do everything through code and I'm failing at this task.
I have a ViewController to handle User Inputs and 2 UIViews which will both be visible at the same time(each in a separate header/implementation UIView file):
1 UIView represents a custom tab bar that changes (bottom 50 px)
1 UIView represents the displayed interface (everything above the tab bar)
Each needs to exist within its own frame, initialized from the ViewController so it can control them and what they display.
Bra, UIViewControllers have only one UIView as part of their guts.
That is, "view" ... i.e. ... the actual property view, as in self.view = something or view.hidden = YES.
However you can, of course, add as many subviews as you like to that view.
This is how views are used normally. Almost every .view has subviews inside it.
UIView *bottomThing = [[UIView alloc] init];
bottomThing.frame = CGRectMake whatever
UIView *otherThing = [[UIView alloc] init];
otherThing.frame = CGRectMake whatever
[view addSubview:bottomThing];
[view addSubview:otherThing];
In the example, we added two subviews to our main "built-in" view, which you refer to as simply "view". So we added bottomView to our "view" and we added topView to our "view."
The subviews you add could be either plain old UIView, or, your own special subclass of UIView.
MySpecialView *bottomThing = [[UIView alloc] init];
bottomThing.frame = CGRectMake whatever
ExtraordinaryView *otherThing = [[UIView alloc] init];
otherThing.frame = CGRectMake whatever
[view addSubview:bottomThing];
[view addSubview:otherThing];
(I guess FTR conceivably you could subclass UIViewController to have more than one view inside it, but that's completely pointless and irrelevant to this question.)
From your UIViewController you can manipulate the subviews in any way you want.
For example [bottomThing doStuff:3.7], bottomThing.hidden=YES, etc etc.
Once again it is absolutely normal to add more subviews inside your main "view" - this is the basic way in which iPhone apps are made. There is only one ".view" - you add more views inside it as you wish. Hope It Helps.
UIView *myView = [[UIView alloc] init];
[self.view addSubview:myView];
[myView release];

Create UIView through code and add events in iphone

I have created a UIView and added label to it and latter assign it to Controller.
Now whenever I click on my View it shows me "EXC_BAD_ACCESS”.
Below is my code.
//create a UIView in App Delegate
UIView *viewPtr = [[[UIView alloc] initWithFrame:frmRect] autorelease];
//created a Button and added to UIView
UIButton *btnPointer = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btnPointer.frame = cgframe; // provides both a position and a size
[btnPointer setTitle:btnLabelText forState:UIControlStateNormal];
[btnPointer addTarget:self action:#selector(generate:) forControlEvents:UIControlEventTouchUpInside];
[viewPtr addSubview:btnPointer];
//Now need to add this UIView to a controller
viewController.view = viewPtr;
I am able to display the button on the Form but when I click on the form or the button I get
"EXC_BAD_ACCESS”.
You should create the view in the .m file of your view controller like this.
- (void)loadView
{
UIView *viewPtr = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
//created a Button and added to UIView
UIButton *btnPointer = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btnPointer.frame = cgframe; // provides both a position and a size
[btnPointer setTitle:btnLabelText forState:UIControlStateNormal];
[btnPointer addTarget:self action:#selector(generate:) forControlEvents:UIControlEventTouchUpInside];
[viewPtr addSubview:btnPointer];
//Now need to add this UIView to a controller
self.view = viewPtr;
[viewPtr release];
}
Hope this helps.
Thanks,
Madhup
Instead of use the autorelease
UIView *viewPtr = [[[UIView alloc] initWithFrame:frmRect] autorelease];
Create the UIView *viewPtr on the .h file, and only do the release in the dealloc method
So, you will have the declaration on your .h file
UIView *viewPtr;
And you .m file will be with the following lines, when you instantiate the viewPtr in the same place where you was doing previously, but without the autorelease, and the release on the dealloc method as follow:
viewPtr = [[UIView alloc] initWithFrame:frmRect];
.
.
.
.
.
.
.
.
- (void)dealloc {
[viewPtr release];
[super dealloc];
}
The autorelease is the main problem in your code, because when you do this, your UIView won't respond to any event.
Cheers,
VFN
What is self in [btnPointer addTarget:self ... ? Is generate: called? Have you tried debugging there?
As vfn says, this you get the error because you release the view too early. The question I would be asking is why is this case different?
Normally in an assignment like this:
viewController.view = viewPtr;
The viewPtr is retained and you would be correct to release it yourself. But look at the definition:
#property(nonatomic, retain) UIView *view
This means that any value is simply assigned and not automatically retained.