EDIT:
Solved the problem myself. Turned out it was a leftover in the dealloc method that caused a UIButton to be released twice...
I'm trying to display a UIViewController on top of another UIViewController like a popup. Problem is that the view seems to be getting overreleased. With NSZombieEnabled, I get the following error:
[CALayer release]: message sent to deallocated instance 0x784bf40
I use this code to add the view:
//self.someViewController is declared as (nonatomic, retain)
self.someViewController = [[[SomeViewController alloc] initWithDelegate:self] autorelease];
[self.view addSubview:self.someViewController.view];
Then later on, I remove the view like this:
[self.someViewController.view removeFromSuperview];
self.someViewController = nil;
Should earlier comments not solve this perhaps this may help. I'm assumning you've created your someViewController property like this
#property (nonatomic, retain) NSViewController* someViewController;
in which case I believe your code is correct (at least I can see how it should work) and you might be seeing a secondary crash here.
I.e. when you're calling
self.someViewController = nil;
this should be freeing the memory up immediately (assuming a frame has gone by where the VC exists so the autoreleased count has already been decreased). Therefore if you have ANOTHER object being used in that someViewController VC who still exists and has a delegate set to your someViewController object and is doing a background task it will cause a crash when it trys to call back to your now deallocated object. (If you don't free your VC you wouldn't see this crash)
For example if you have a MKMapKit being displayed in someViewController and the delegate is set to someViewController... if you have implemented the method in someViewController
mapViewDidFinishLoadingMap:(MKMapView*)mapView
the MKMapKit may still be calling this from another thread if you haven't destroyed MKMapView object before yours.
I would always set other object delegates pointing to your VC (like MKMapView) to nil before destroying the said VC it uses to avoid this risk. For PDF rendering (CALayer?) you may find you need to explicitly release the object too given this uses a different memory alloc/free paradigm.
Solved the problem myself. Turned out it was a leftover in the dealloc method that caused a UIButton to be released twice...
Related
normally when I'm using a viewcontroller that will push the current viewcontroller out of the way, I use a UINavigationController and push/pop the new viewcontrollers and let them handle all the dealloc themselves.
However, for example, in this case, I have a MainViewController, which is the default view when the app starts up. I have a second view, called SecondaryViewController, that is a popup on the main screen (sort of like a lightbox).
Here is the code to illustrate:
//From within mainViewController:
secondaryViewController = [SecondaryViewController alloc] initWithNibName:#"SecondaryViewController" bundle:nil];
[self.view addSubview:secondaryViewController.view];
The secondaryViewController interface looks like this:
//interface
#interface SecondaryViewController : UIViewController
{
IBOutlet UILabel *httpLabel;
IBOutlet UIScrollView *scrollView;
}
#property(retain, nonatomic) IBOutlet UILabel *httpLabel;
#property(retain, nonatomic) IBOutlet UIScrollView *scrollView;
As for the implementation, I have the #synthesize for the #property ivars, but I'm not doing any manual allocs. However, I did put a dealloc method:
- (void)dealloc
{
[httpLabel release];
[scrollView release];
[super dealloc];
}
But I'm not sure I need the above.
So my questions would be the following:
1) Do I need the above dealloc method in this case? Or more generally, when would a subview need a dealloc method?
2) If I do or dont need it, does it depend on whether I'm adding the secondaryViewController via addSubview or pushViewController? For instance, if I wanted to replace the entire mainViewController, with this:
[self.navigationController pushViewController:secondaryViewController animated:NO]
Would the secondaryViewController need a dealloc method?
Thank you!
Yes, you do need the dealloc method exactly as you have it, in this case. You are on the right track because you're assuming that since you are not doing any manual allocating, you don't need to do any dealloc/releasing... however, by specifying the property as (retain, nonatomic), you are doing implicit retaining.
This means that if you ever set those properties, what's actually occurring under the covers is something like this:
-(void)setHttpLabel:(UILabel *)newlabel
{
if (newLabel != httpLabel)
{
[httpLabel release];
httpLabel = [newLabel retain];
}
}
As you can see, your synthesize is causing a retain to occur on an object. If you never balance that retain out with a release, it will leak. So the only logical place to put it, is in your dealloc method. This creates the circle of life.
If you never set these properties and don't have release in dealloc, then it won't leak anything, but you obviously wouldn't want to make those assumptions.
If you didn't have any retain properties or any manual allocing of ivars, then and only then, can you nuke the dealloc method.
Hope that helps.
I think this is allowed in the latest iOS 5+ but previously you were not supposed to add another viewcontrollers view to your main viewcontroller. This is clear misuse and can lead to issues.
The concept of viewcontroller is one who controls all the views. A view controller should not control another viewcontroller unless it is a container viewcontroller such as UINavigationController/UITabBarController.
So please rethink the design. why do you need the SecondaryViewController. Why cannot the mainviewcontroller manage the secondary view as well?
Lastly, every viewcontroller should have the dealloc in it.
If you need to access secondaryViewController from your main view controller after you've added its view to the hierarchy, you should not deallocate it at that point. If you don't need to access the secondary controller after you've displayed it, you can dealloc it at that point.
In practical terms, if secondaryViewController is an ivar, it probably makes sense to keep a retained reference to it. If it's a local variable and you're not accessing it later, you should dealloc it.
In my .h file create 3 objects like below
IBOutlet UIScrollView *scrollView;
IBOutlet UITextView *txtMessage;
IBOutlet UIWebView *webView;
In xib make Connection for all 3 objects
hierarchy in xib like
**View
---UIScrollView
---UITextView
---UIWebView**
then I am printing retainCount in dealloc method
NSLog(#"scrollView retainCount:%d",[scrollView retainCount]);
[scrollView release];scrollView=nil;
NSLog(#"txtMessage retainCount:%d",[txtMessage retainCount]);
[txtMessage release];txtMessage=nil;
NSLog(#"webView retainCount:%d",[webView retainCount]);
[webView release];webView=nil;
on console i am getting like below
scrollView retainCount:3
txtMessage retainCount:2
webView retainCount:2
I want to know why its happens like this ,and one more thing how can release this objects in dealloc method...
The answer is: you don't release them. You didn't alloc] init] then, they're not your responsibility memory-wise.
The only case where they're somehow your responsibility, is when you retain them using a #property (retain) for the IBOutlets. In that case, you'll release them in [dealloc]
Answering to your comment in another answer about instruments and releasing the outlets that the xib creates: if you release them, then the view will be unload sometime and the responsible for releasing the elements in the .xib (which it wasn't you) will release them again, and it will crash ;) The reason why you go back to another view and the memory doesn't decrease is because when a view disappears, it's not unloaded, that only happens when either the view controller is deallocated, or when the application gets a memory warning.
I don't think you need to do anything in dealloc. In Objective-C, if you haven't alloc/retain anything, you don't need to worry.
I have a UIViewController that has an IBOutlet for a UILabel with the label wired up in the XIB.
#import <Foundation/Foundation.h>
#interface MyViewController : UIViewController {
IBOutlet UILabel *aLabel;
}
#end
According to iOS Programming: The Big Nerd Ranch Guide (2nd Edition) chapter 7
When [MyViewController] reloads its view, a new UILabel instance is created from the XIB file.
Thus it recommends releasing the label in viewDidUnload.
- (void)viewDidUnload {
[super viewDidUnload];
[aLabel release];
aLabel = nil;
}
Being a C# programmer, I've had it drummed into me that assigning nil/null to things is pointless. While I can see it makes more sense in Objective-C, it still grates my sense of code aesthetic slightly*. I removed it and it all worked fine.
However, when I tried to do a similar thing with MKMapView the application errors EXC_BAD_ACCESS while trying to load the NIB.
#import <Foundation/Foundation.h>
#interface MyViewController : UIViewController {
IBOutlet MKMapView *mapView;
}
#end
- (void)viewDidUnload {
[super viewDidUnload];
[mapView release];
mapView = nil; // Without this line an exception is thrown.
}
Why is there an error when mapView is not set to nil, but not when aLabel is not set to nil?
* I realise I need to adjust my sense of code aesthetic for the new language, but it takes time.
It turns out I was just flat out wrong about aLabel not being referenced. Not sure what made me think it wasn't.
However, that still leaves the question of why they're being referenced while the NIB is being loaded.
When the field or property is set, a release message is sent to the old value (either the synthesized properties set method sends the release message, or setValue:forKey: sends the message if it's a field). Because the old value has already been released, this results in EXC_BAD_ACCESS.
It's because of memory management, specifically the lack of garbage collection.
In C# (as you know) objects that are no longer in scope are removed. In objective-c, that doesn't happen. You have to rely on retain/release to tell the object when you are done with it.
There's a drawback to the objective-c reference counting method that your mapView bug exhibits. Calling release on an object might result in it being deallocated. However, your pointer to the object will still point to the same place - your object just won't be there anymore.
For example
// We create an object.
MyObject *object = [[MyObject alloc] init];
// At this point, `object` points to the memory location of a MyObject instance
// (the one we created earlier). We can output that if we want :
NSLog(#"0x%08X", (int)myObject);
// You should see a number appear in the console - that's the memory address that
// myObject points to.
// It should look something like 0x8f3e4f04
// What happens if we release myObject?
[myObject release];
// Now, myObject no longer exists - it's been deallocated and it's memory has been
// marked as free
// The myObject pointer doesn't know that it's gone - see :
NSLog(#"0x%08X", (int)myObject);
// This outputs the same number as before. However, if we call a method on myObject
// it will crash :
NSLog(#"%#", myObject);
In objective-c, if you try to call a message on nil, nothing happens. So if each time you are finished with an object and call release on it, you should also set it to nil - this means that if you try to use that pointer again, it won't crash!
viewDidUnload is usually called when the device receives a memory warning.
In the View stack there may be situations where the device can free up memory by releasing objects that aren't in use. Imagine you have a navigation stack with a number of view controllers. The interface view controllers lower on the stack are not accessible but are still using up memory. So its usually a good idea to nil out any interface elements that can't be accessed. These will then be reloaded with viewDidLoad when needed.
Generally in ViewDidUnload you should release any view objects that are created from a Nib file or allocated in your ViewDidLoad method
Your mapView is throwing an exception because your view controller is trying to access to MapView but the mapView has been released. When you set the outlet to nil any messages sent to it are ignored.
I am having an iphone app with admob on two screens's viewdidLoad
My code is:
AbMob =[[GADBannerView alloc]initWithFrame:CGRectMake(0.0,self.view.frame.size.height-195, 320, 50)];
AbMob.adUnitID = AdMob_ID;
AbMob.rootViewController = self;
[self.view addSubview:AbMob];
GADRequest *r = [[GADRequest alloc] init];
r.testing = NO;
[AbMob loadRequest:r];
Problem is this code works fine on one screen but crashes on other screen with error
* -[GADOpener didOpen]: message sent to deallocated instance
0x6074750
Can anybody tell me what could be the problem
You have a retain/release problem somewhere in your code. You say it works in one view, but not another - this makes me believe that you are storing this instance outside of your view controllers. The message sent to deallocated instance issue is due to you trying to use a variable that has been removed from memory somewhere in the code before this error pops up. You need to ensure that the view controller that is creating this object is properly retaining it so that it does not get deallocated before you need to use it again with:
GADBannerView *_adMobBannerView;
#property(nonatomic,retain) GADBannerView *adMobBannerView; //view controller retains object when using self.adMobBannerView = bla
It sounds like you may need to brush up on your memory management documentation, but the gist of it is that anywhere you are calling alloc, you are managing that memory and need to call release when you are done with it. If you need a variable to stick around for longer than an autoreleased object is living for, then you need to create an instance variable and retain the object yourself with ivar properties #property (nonatomic, retain).
using facebook-facebook-ios-sdk-cf1c2c3, the _sessionDelegate object is being deallocated before my app is moved to the background.
This means when the app comes to the foreground after the authentication/authorization callback, this method in Facebook.m hits causes a EXC_BAD_ACCESS:
- (void)fbDialogLogin:(NSString *)token expirationDate:(NSDate *)expirationDate
The offending line in that method being this one:
if ([self.sessionDelegate respondsToSelector:#selector(fbDidLogin)]) {
[_sessionDelegate fbDidLogin];
}
I think this is because in Facebook.h, _sessionDelegate is being assigned not retained. Therefore at some point it is deallocated:
#property(nonatomic, assign) id<FBSessionDelegate> sessionDelegate;
Changing it to retain appears to resolve the problem:
#property(nonatomic, retain) id<FBSessionDelegate> sessionDelegate;
Seems like too obvious a thing to me. Therefore I must be missing something!
Any ideas?
Many thanks,
xj
Changing the delegate to a retain method in this case is probably a more stable solution than anything else. However somewhere your delegate is being released before you want it to be released and you may need to look into what would cause it to be released early. However if you do this make sure you edit the Facebook.m dealloc() method to release your delegate
I had same EXC_BAD_ACCESS problem.i resolved it by removing other allocated instance of rootViewController.
RootViewController *rootViewController = [[RootViewController alloc] init]; <--------
facebook = [[Facebook alloc] initWithAppId:kAppId andDelegate:rootViewController];
it should be allocated only once.
that means if you are again allocating your rootViewController and pushing/adding it another viewController it retains its previous instance.
Hope it helps to resolve EXC_BAD_ACCESS.
In calling page you must disable ARC!