subview didn't call dealloc when superview(UIViewController) dealloc - iphone

I was confuse with memory management of removeFromSuperview.
Here is my code:
MySubView *tMySubView = [[MySubView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
tMySubView.center = self.view.center;
tMySubView.tag = 1111;
[self.view addSubview:tMySubView];
[tMySubView release];
"self" is UIViewController.
When "self" call dealloc but MySubView didn't call dealloc.
I know addSubView retainCount +1.
So I try add [tMySubView removeFromSuperview] in "self" dealloc
And MySubView dealloc was called...
Should I add [subView removeFromSuperview]; when superView dealloc?
Or superView removeFromSuperview ,it will automaticly call subView's removeFromSuperview...?
I can't figure it out. :(
Thanks!

It means that self.view is not properly released. It will remove all it's subviews only in case when it is deallocated.
Check your loadView method (where you're probably initialize it). If it looks like this:
-(void) loadView {
self.view = [[UIView alloc] init];
}
then you've got leak and have to rewrite it like this:
-(void) loadView {
self.view = [[[UIView alloc] init] autorelease];
}
OR
-(void) loadView {
UIView* v = [[UIView alloc] init];
self.view = v;
[v release];
}
Also check all the places where you're accessing self.view and make sure you're not over-retaining it.

Related

How to initialize view without known frame?

I'm building view without .xib file, just using loadView method. But in the point, when loadView is called, the frame of view is yet unknown. So, I use it just to build view hierarchy without concrete frames. (Than I update view's layout when it's frame is known.)
The question is: should I use [[UIView alloc] init] or [[UIView alloc] initWithFrame:CGRectZero] or may be something else, to initialize view without known frame?
Here is the code:
- (void)loadView
{
UIView *containerView = [[UIView alloc] init];
// or
// UIView *containerView = [[UIView alloc] initWithFrame:CGRectZero];
// or something else?
// ...
self.view = containerView;
[containerView release];
}
- (id)initWithFrame: is the designated initializer for UIView, so you should use that, with a zero-sized rect.

adding UIView to UIViewController

I need to add a Button or a label to a UIView and add it to my UIViewController. I did the following but it only crashed the program.
UIView *myview = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 0, 300)] ;
[myview addSubview:myButton];
[self.view addSubview:myView];
The code crashes. Why is that?
You set your myview's width to 0.
You sure you created "myButton"?
You create myview but you add my*V*iew as subview. Is there any warning?
The first step you need to take is:
Make Sure you have allocated & initialized UIButton object with "initWithFrame" method.
provide a width to your UIView in "initWithframe" method, So that it can be seen.
Now use your [self.view addSubview:myView];
Please let me know if it is useful.
Use:
//Assuming that myview should have the size of the main view:
UIView *myview = [[UIView alloc] initWithFrame:self.view.bounds];
[myview addSubview:myButton]; //Whatever ...
[self.view addSubview:myview]; //There was a typo in this line
If this code block is in the init or loadView of viewcontroller, this will crash.
Make sure you have created a view for view controller in this case before adding views to self.view
UIView *aView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
self.view = aView;
[aView release];
myButton = [[UIButton alloc] init....
.....
UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 0, 300)] ;
[myView addSubview:myButton];
[self.view addSubview:myView];
Try updating the view with the following:
[myview setNeedsDisplay];
and remove the second call to addSubView (which is probably causing the crash):
[self.view addSubview:myView];

App freeze when I remove [super loadView]

When I remove the [super loadView]; the view wont display. The superclass is UIViewController.
- (void)loadView
{
[super loadView];
UITableView *tableview = [[UITableView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 367.0f) style:UITableViewStylePlain];
tableview.dataSource = self;
tableview.delegate = self;
self.tableView = tableview;
[tableview release];
[self.view addSubview:self.tableView];
}
Any idea why? Thanks in advance!
1) UIViewController Class Reference, loadView section
Your custom implementation of this method should not call super.
2) You have to set view property to something. After all this method is called loadView :). Instead of [self.view addSubview:self.tableView]; try
self.view = tableView;
If you look at the view programming guide, it mentions that if you override [loadView], you should construct your own view.
default loadView will look at bunch of stuff, like load from nib first, then construct normal view.
So, just construct a view, and assign it to self.view -
UIView *view = [[UIView alloc] initWithFrame ...];
self.view = view;
[view release];
then it should be fine.
edit: example with your code:
- (void)loadView
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 367.0f)];
self.view = view;
[view release];
UITableView *tableview = [[UITableView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 367.0f) style:UITableViewStylePlain];
tableview.dataSource = self;
tableview.delegate = self;
self.tableView = tableview;
[tableview release];
[self.view addSubview:self.tableView];
}
edit2: link to viewcontroller programming guide:
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/BasicViewControllers/BasicViewControllers.html#//apple_ref/doc/uid/TP40007457-CH101-SW1
Look at custom view controller section, Creating the View Programmatically, and few other places in that doc.
I think you wanna move that [ tableview release ] after the addSubview.
This is because you never assign the view property in the code. When in the last line you access the view property, it causes -loadView to be called again, which results in a endless loop.

Creating a UITableViewController programmatically

This is what I tried. Nothing appears on the screen and none of the UITableView methods that you are supposed to implement are getting called.
-(void)loadView
{
UIView *view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
self.view = view;
[view release];
}
- (void)viewDidLoad
{
[super viewDidLoad];
UITableViewController *TVC = [[[UITableViewController alloc]
initWithStyle:UITableViewStylePlain] autorelease];
CGRect cgRct = CGRectMake(0, 10, 320, 100);
UIView *newView = [[UIView alloc] initWithFrame:cgRct];
TVC.view = newView;
[newView release];
[self.view addSubview:TVC.view];
}
I've looked for good examples and tutorials on doing this programmatically but there are none.
What I am trying to achieve is a Table that doenst take up my who screen. Maybe 3/4 of my screen would be good.
Many Thanks
Code
The problem is that you're creating a UITableViewController, which is a UIViewController, and will expect to be on the nav stack. What you want to do is create a UITableView, which is a UIView. You are also not setting the table's delegate and data source, which you will need to do to get calbacks.
Your viewDidLoad should look something like this
- (void)viewDidLoad
{
[super viewDidLoad];
UITableView *table = [[[UITableView alloc] initWithStyle:UITableViewStylePlain] autorelease];
table.dataSource = self;
table.delegate = self;
table.frame = CGRectMake(0, 10, 320, 100);
[self.view addSubview:table];
}
(Note that if you're going to need access to the table outside of the callbacks, you should save it in an ivar rather than declaring it locally, and should retain it. Let me know if you need a few more lines of code to show you what I mean)
Make sure you set the delegate of TVC, with
TVC.delegate = self;
That's the reason why none of those methods are getting called. Also, make sure your class implements the UITableViewDelegate protocol by changing your interface declaration to
#interface YourViewController : UIViewController <UITableViewDelegate> {
//declare variables here
}
Also, equally important, don't set TVC.view, as this already happens when you initialize the view controller. You're just setting it to a blank view, which is why you're not seeing anything.
iOS7 seems to like this way of init'ing the tableview:
//make tableview
UITableView *table = [[UITableView alloc] initWithFrame:CGRectMake(0, 81, 200, 200) style:UITableViewStylePlain];
table.dataSource = self;
table.delegate = self;
[self.dataView addSubview:table];
try that out. Hope it helps someone.
UIView *newView = [[UIView alloc] initWithFrame:cgRct];
TVC.view = newView;
I'll give you a hint. Here you are setting the view of the UITableViewController to an EMPTY VIEW...

Proper way to release view in UIViewController

I am building my own view in loadView of view controller. Just to check if I can release the view like below or there is anything else I will need to release it? I know framework will set it to nil once it requires to free up some memory.
- (void)loadView
{
self.view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
[self.view release];
...
}
That looks a bit weird, I'd do this instead:
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
self.view = view;
[view release];
If you're using #property (retain) you don't have to worry about releasing it when it's set to nil e.g. self.view = nil;. However you should release it in dealloc.
The view property of a UIViewController will be released for you by the UIViewController itself. You are right however that when you create the view that you assign to a UIViewController you need to release it, but the way you are trying to do it is wrong. Either do what jtbandes suggest or simply:
self.view = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)] autorelease];