Objective-C - Unloading loaded view when it is swapped - objective-c

What is the best way to do view management in a multiview application?
Right now I have this ViewSwitcher method/function that comes from a custom delegate I created.
The code is a whole bunch of if else like this
MyViewController *c = [[MyViewController alloc] initWithNibName:#"MyViewController" bundle:nil];
c.delegate = self;
self.myViewController = c;
[self.viewHolder insertSubview:c.view atIndex:0];
[c release];
That works fine, but when I visited the function a second time, is there going to be 2 instances of MyViewController now or just 1?
How do I unload MyViewController when I switch to another view?
Or is there a better way to manage my views?
Thanks,
Tee

If self.myViewController is a retained property, then there will be two instances of MyViewController up until this line:
self.myViewController = c;
... at that point the synthesized accessors will release the instances created in the first pass and then retain the newly created one. If the first instances has not been retained by another object, it will deallocate.

Related

When is it safe to manipulate screen controls through code in iOS/Objective-C

I have a question regarding iOS (or perhaps more accurately Objective-C) and properties. I have a UIView with a UISegmentedControl, by default it has 3 segments. I have a message which accepts a parameter and based on this parameter I may want to remove one of the segments. In UIView A I do this:
MyViewController *myview = [[[MyViewController alloc] initWithNibName:#"MyViewController" nib:nil] autorelease];
[[self navigationController] pushViewController:myview animate:YES];
[myview showItem:item];
In UIView B this happens in showItem:
-(void) showItem:(Item*)item{
if (item.removeSegment){
[segmentControl removeSegmentAtIndex:0 animate:NO];
}
}
I have noticed that the segment only gets removed when I call showItem after I have pushed it on the navigation controller. When I swap those two line, so I first call showItem and then push the view, the UISegmentedControl still has three segments instead of two.
This just feels wrong, it seems like bad practice that my code will break if someone doesn't call two messages in the right order. Is there a better way to do this? I've been looking at some sort of a property lifecyle that I can use, I am very familiar with this from ActionScript 3, but I have been unable to find anything on the subject.
(as an aside: in AS3 I would make a property, in the setter I don't manipulate any screen controls but call InvalideProperties. My overriden methode CommitProperties will be called once the entire object and child controls have been created. In CommitProperties I check if my property value has changed and this is where I would remove the segment.)
A common way of doing something like this is to create an Item *item property in MyViewController and set that when myview is created. So, your code becomes:
MyViewController *myview = [[[MyViewController alloc] initWithNibName:#"MyViewController" nib:nil] autorelease];
myview.item = item;
[[self navigationController] pushViewController:myview animate:YES];
MyViewController would then use that property in its viewWillAppear: method to configure its own segment control.
I think what you are falling prey to is myview->segmentControl doesn't exist until myview.view is referenced because of the lazy load of the view.
-(void) showItem:(Item*)item{
[self view]; // NO OP TO FORCE LOAD!!
if (item.removeSegment){
[segmentControl removeSegmentAtIndex:0 animate:NO];
}
}
Should work for you. Hope this helps!

reference to view property is retaining the view controller

I am having memory leaks when I m using a view controller's view
My code sequence is like this
viewController1 = [[ViewController alloc] init];
destinationViewController = [[DestinationViewController alloc] init];
[destinationViewCOntroller useView:viewController1.view];
[viewController1 release];
[destinationViewController release];
And for testing purpose I have empty implementation in useView method. So my problem is viewController1 is never getting deallocated. I have made sure that no other place has any reference to viewController1.
When I remove the method call(useView) where I pass viewcontroller1.view then viewcontroller1 is deallocating properly.
Any ideas why the behaviour is like this?
This seems to be a rather academic problem. Just enable ARC and forget about it.

What happens after a viewController is pushed into another viewController

I was just wondering while programming. I have got a rootViewController which creates an instance of a childViewController. This childVC is pushed onto my rootViewController through [self.navigationController pushViewController:childVC] from another childViewController (say childVC2). Now I was wondering what happens with my instance of childVC2. Does it get released? Because when returning from childVC to childVC2 I create a new instance of childVC2 and push it into my rootViewController. Obviously I do not have any use for the earlier instance of childVC2 so what happens with it or haw can I manually release it?
Yes if you are alloc the ViewController you have to release it .. the push will increase its reference count by 1 so you have to be sure that you are pop it to decrase the reference count .. and for the creating the instance define it in .h and when create it do it like this
if(yourViewController)
[yourViewContoller release];
yourViewController = [yourViewControllerClass alloc] init];
another opition is to make it autorelease and in this case you are not responsible to release the ViewController
yourViewController = [yourViewControllerClass alloc] init]autorelease];

Does releasing a view controller releases all its properties?

I have a BaseViewController, which is a subclass of UITabBarController, and set up my views in this view controller.
-(void)setUpViews
{
FirstController *mainViewController = [[FirstController alloc] initAssignment:delegate.currentAssignment withMutableArray:myArray];
UINavigationController *firstNavController = [[UINavigationController alloc] initWithRootViewController:mainViewController];
SecondController *secondViewController = [[SecondController alloc] initWithNibName:#"SecondController" bundle:nil];
UINavigationController *secondNavController = [[UINavigationController alloc] initWithRootViewController:secondViewController];
self.viewControllers = [NSArray arrayWithObjects:firstNavController, secondNavController,nil];
firstNavController.tabBarItem.image = [UIImage imageNamed:#"blablabla.png"];
firstNavController.tabBarItem.title = #"Stream";
secondViewController.tabBarItem.image = [UIImage imageNamed:#"blabla.png"];
secondViewController.tabBarItem.title = #"Favourite";
}
Now I have another view controller, I call it ViewHandlerController, a subclass of BaseViewController. in my viewDidLoad in this viewHandler, i invoke setUpViews which is declared in BaseViewController. in the first screen of my app, when a Login button is pressed, I instantiate my ViewHandlerController, and presented my tabcontroller succesfully with nav controllers by using.
[[[UIApplication sharedApplication].windows objectAtIndex:0] addSubview:viewControllerHandler.view];
Inside my app. there is a logout button. I am using NSNotificationCenter to call my logoutMethod which is declared in my first screen. My question is, in this logoutMethod, how can I release the previously allocated objects to avoid memory pressure since the user can log in again (logIn - logOut -logIn)? since I'm using ARC, is setting my ViewController to NIL will do all the clean up?
EDIT: is removing my ViewControllerHandler from superview and setting it to nil helps releasing its subviews too?
Cheers
Well, answer for your question (not ARC) – no, basicaly view controller doesn't releases his properties when release. But you should nil your properties in viewDidUnload and (or) dealloc methods.
If you use ARC, you should notice that some actions can retain your controller, and it can never be deleted in some cases. Watch for methods, which takes object for delegate, they may not using weak references
Have a look at this Apple article about memory management.
You can just use autorelease in alloc methods or for (UIView *view in [self.view subviews]) {view release}; in dealloc.
In fact release is opposite operation to retain. When you do retain, you increase by 1 count of object instances in allocated memory. It happens when you call alloc, copy, new, mutableCopy. If you are using ARC you can't release objects, memory management is not your problem already.

Values not passed back after dismissModalViewController

I'm passing a string variable for the sake of testing (isLoggedIn) as well as an NSManagedObject (userObject). However, when I dismiss the VC and it comes back to the root, I do not have the new data that was set in the variables in the loginViewController.
LoginViewController *loginVC = [[LoginViewController alloc] initWithNibName:#"LoginViewController" bundle:nil];
loginVC.managedObjectContext = self.managedObjectContext;
loginVC.userObject = self.userObject;
loginVC.isLoggedIn = self.isLoggedIn;
[self presentModalViewController:loginVC animated:YES];
[loginVC release];
I later dismiss the view with:
[self dismissModalViewControllerAnimated:YES];
Update:
Ended up using delegates as someone suggested. I used the following post as a guideline:
UIViewController parentViewController access properties
I ended up using delegates as someone above suggested. I used the following post as a guideline:
UIViewController parentViewController access properties
I may not be following you properly so this could be irrelevant.
I am guessing you mean that:
You set your ivars after alloc/init
You make some changes inside LoginViewController
You expect those changes to be reflected in self.userObject and self.isLoggedIn of the class that instantiated LoginViewController
which may or may not happen if you act on the objects themselves or you reassign the pointers
e.g.
If you call self.userObject.name = #"Test"; inside LoginViewController then the change will be reflected in the class that instantiated LoginViewController and LoginViewController because the ivars are pointing to the same object in memory and you are manipulating the object.
OR
If you call self.userObject = theResultOfSomeNewFetch; then the change will not be reflected as you now have a pointer in LoginViewController that is pointing to a different userObject to the pointer in the class that called LoginViewController
Hopefully I have not lost the plot completely and this is somewhere near what you mean.