ARC + Dealloc is not called - ios

I am little confuse because my dealloc is not called in ARC. I have using storyboard in my application.
Case 1: Mydealloc called when i use all IBOutlet from storyboard
Case 2: My dealloc is not called when i try to use alloc and init methods in UIViewController. such as below.
UIViewController *vc = [[UIViewController alloc] initWithNibName:#"ProfileDetailView" bundle:nil];
__weak ProfileDetailView *detailview = (ProfileDetailView *)vc.view;
detailview.backgroundColor = [UIColor clearColor];
vc = nil;
....Set value in object.....
[self.view addSubview:detailview];;
detailview = nil;
Can you explain why dealloc is not called? and How can i able to achieve to call dealloc?
Thanks

The concept of ARC is that an object's retain count should theoretically be 1 in order for it to be deallocated. When you execute:
[self.view addSubview:detailview];;
Your self.view increments detailview's retain count by 1 when it adds it to view.subviews. Logically, when self.view removes detailview, the retain count is decremented by 1.
Again, this is a theoretical perspective. The reality is usually:
INSANE.
No one really knows how the mysterious Objective-C runtime works! (just kidding the whole source code is available online.)

Thanks for your reply. I am able to called my dealloc function when view controller pop. For achieving that, we need to remove my added subviews from my view when user tapped on back button.

Related

ViewControllers dont get removed from scrollview

My project is using ARC and objective c. And i'm having troubles with the
ViewControllers that is created inside my scrollview. They dont get removed
completely.
What i did was that i have created a UIScrollView inside the main
ViewController. Then i have created 2 other ViewControllers.
I'm placing the 2 viewControllers inside the UIScrollView like that:
ViewController1 * test1 = [[ViewController1 alloc] init];
ViewController2 * test1 = [[ViewController2 alloc] init];
[scrollview addSubview:test1.view];
[scrollview addSubview:test2.view];
it works and i can see both of my design from the viewControllers. But when i try to remove both viewControllers from the main viewController and add them back later it create new views, but the same old views still exist underneath. I want to completely remove them from the main viewController and create new ones instead.
i'm removing them like that:
[test1 removeFromParentViewController];
[test2 removeFromParentViewController];
[test1.view removeFromSuperview];
[test2.view removeFromSuperview];
The code where i'm adding new views for the second time is like the first one, but here it is:
ViewController1 * test1 = [[ViewController1 alloc] init];
ViewController2 * test1 = [[ViewController2 alloc] init];
[scrollview addSubview:test1.view];
[scrollview addSubview:test2.view];
but i'm only doing this when the remove is done.
FIXED IT:
The problem was that i was using block-based notification handlers which sometimes stops the app from calling dealloc to release my viewcontrollers. I tested that anything that use block-based stuff will kind block the app from calling dealloc the fix is to stop/free the block-based notification and then make a remove call of the views.
FIXED IT:
The problem was that i was using block-based notification handlers which sometimes stops the app from calling dealloc to release my viewcontrollers. I tested that anything that use block-based stuff will kind block the app from calling dealloc the fix is to stop/free the block-based notification and then make a remove call of the views.

Dealloc is not calling immediately after release

I have a root view that loads two view controller. e.g.:FirstVC,SecondVC.
I am showing FirstVC as the root view controller when the app launches, on some action on FirstVC I load SecondVC by removing first.
For loading SecondVC I first remove FirstVC by
[FirstVCobj.view removeFromSuperView];
[FirstVCobj release];
FirstVCobj = nil;
After that I allocate and create SecondVC
Now only after calling SecondVC's viewdidload() is FirstVC's dealloc() method called.
Is this the right execution path, or is it due to some mistake I have made?
The above is exactly how I remove and create my view controllers.
i assume it is a UIView you're talking about.
addSubview retains the view
removeFromSuperView releases or AUTORELEASES it -- an implementation detail you don't control
to 'see' it: wrap it in a pool of your own
#autoreleasepool {
[FirstVCobj.view removeFromSuperView];
[FirstVCobj release];
FirstVCobj = nil;
}
[FirstVCobj removeFromParentAndCleanup:YES];
Check with this might work.

iOS - Popping UIViewController doesn't destroy its properties

When I pop a UIViewController instance off of my UINavigationController, I find that its properties remain (NSTimers keep timing, AVAudioPlayers keep playing, etc.). I'm wondering what's wrong with my approach?
I push the UIViewController instance onto the UINavigationController this way:
- (IBAction)buttonPressed:(id)sender {
UINavigationController *nc=[self navigationController];
NewViewController *nvc=[[NewViewController alloc] init];
[nvc setNameToUse:[self nameToUse]];
[nc pushViewController:nvc2 animated:YES];
}
The NewViewController has a sub-viewcontroller, that is added via NiewViewController's viewDidLoad method:
self.mySubViewController=[[SubViewViewController alloc] initWithName:self.nameToUse];
self.mySubViewController.view.frame=CGRectMake(0,
0,
self.mySubViewController.view.frame.size.width,
self.mySubViewController.view.frame.size.height);
[self.view addSubview:self.mySubViewController.view];
It's the properties of SubViewController that don't go away when NewViewController is popped. One of these in particular is a timer, declared as follows:
#property (nonatomic) NSTimer *aTimer;
Any advice on this would be terrific. I'm hoping that by solving this issue, the crashes that have been happening once in a while (after the app has been running for 45 or so minutes) will stop! Or at least I'll have a better idea of what's causing them... :) Thanks for reading.
NSTimer retains it's target, if you are passing self (your SubViewViewController) then you'll be creating a retain cycle between the view controller and the timer.
Simply adding SubViewController's view to ViewController's will not correctly pass events.
You need to correctly implement UIViewController child containment, as such:
So your second code block should be something like:
[self addChildViewController:self.mySubViewController];
[self.view addSubview:self.mySubViewController.view];
[self.mySubViewController didMoveToParentViewController:self];

UISwitch not reaction

This is probably simple. My UISwitch from my xib is connected to an IBOutlet "switch".
however when i create the viewController, i want to check if a variable is YES/NO, and the switch should be the correct value.
ViewController *vc = [[ViewController alloc] init];
if(variable ==YES){
[vc.switch setOn:YES];
}else{
[vc.switch setOn:NO];
}
however its always unchecked. What could i be doing wrong? i´ve double checked the connection to the IBOutlet
You aren't calling the correct method; UISwitch doesnt' have a setOn method. it has an on property and a senOn:animated: method.
either:
ViewController *vc = [[ViewController alloc] init];
vc.switch.on = variable
or:
ViewController *vc = [[ViewController alloc] init];
[vc.switch setOn:variable animated:YES];
Note, you are already checking against a BOOL, I've shown how to do it without the needless check.
This is the most common problem new developers have. Actually i had the same problem once. at that time i don't know the reason of happening this. i think now i am clear about such problems.
Let me give you some tips.
You should never access any UIView controls before presenting or pushing viewcontroller. you can access the UIView controls after presenting/pushing.
You can achieve this by setting the boolean value also. Create deafultSwitchStatus boolean property because its a boolean type this value will remain memory before viewDidLoad. and you can assign this status to your UISwitch object in viewDidLoad.
In short. UIView controls are not created/loaded before viewDidLoad method and viewDidLoad is called after preseting/pushing any controller. it means your controls are nil if you are accessing before presenting/pushing. those controls will not have any effect of your code because it will be overwritten.
Hope i explained right :)
You have created ViewController, but not presented it. So loadView was never called and yours .switch is nil.
try this:
ViewController *vc = [[[ViewController alloc] init] autorelease];
[self presentViewController:vc
animated:YES
completion:^(){
vc.switch.on = variable;
}];

UiViewController - Pop doesn't pop

I'm displaying UIControllerView subclass when a button is pressed from a another UIViewController like this:
- (IBAction)openNextLevelViewController
{
NSLog(#"openNextlevelViewController");
[self.navigationController pushViewController:nextLevelViewController animated:YES];
}
And the app will return from that view on a button push which trigger this method:
-(IBAction) returnToStart {
NSLog(#"returnToStart method called");
[self.navigationController popViewControllerAnimated:YES];
}
The problem is that the displayed view not getting destroyed/deallocated on the pop. As a result, when it gets pushed, it's not executing the viewDidLoad, which initiates some variables. This may be causing a related problem where, the second time through, when the user presses the return button, the "pop" no longer causes a return to the previous controller.
What's the best way to deal with this? I could move the initialization code to the "willAppear" method, but it seems as if that could be called almost randomly.
Well, its not getting released because nextLevelViewController is still being retained somewhere else. Most likely in your nextLevelViewController variable.
- (IBAction)openNextLevelViewController
{
NSLog(#"openNextlevelViewController");
// assuming you have nib already set up
UIViewController *nextLevelViewController = [[NextLevelViewController alloc] init];
// RETAIN COUNT = 1
// navigationController retains your controller
[self.navigationController pushViewController:nextLevelViewController animated:YES];
// RETAIN COUNT = 2
// Don't need it any more let navigation controller handle it.
[nextLevelViewController release]
// RETAIN COUNT = 1 (by NavigationController)
}
Further On
-(IBAction) returnToStart {
[self.navigationController popViewControllerAnimated:YES];
// RETAIN COUNT = 0, dealloc will be called on your viewController, make sure to release all your retained objects.
}
Now when your controller gets popped, it SHOULD get released (shouldn't have been retained anywhere else). And next time you call openNExtLevelViewController, it'll be initializing a new instance of your viewController anyway.
I'm a fan of releasing viewController when it is no longer needed (displayed), instead of holding it in memory. Let navigationController and TabBarController handle viewControllers whenever possible.

Resources