So here is my code:
-(void)setMovie:(NSURL *)movieLocal {
movie = movieLocal;
[self.movie retain];
...
}
And i get this error:
Potential leak of an object allocated on line 43
Line 43 is [self.movie retain];. Am i doing something wrong, and how can i get rid of this error?
There are a couple issues here:
The old value for movie is never released
'movie' and 'movieLocal' might point to the exact same object. If that is the case, you will call retain on movie/movieLocal without a subsequent balanced release call.
You might want to use the following:
-(void)setMovie:(NSURL *)movieLocal {
if (movie == movieLocal) {
return;
}
[movie release];
movie = [movieLocal retain];
//...
}
Here's the proper setter:
-(void)setMovie:(NSURL *)movieLocal {
if (movie != movieLocal) {
[movie release];
movie = movieLocal;
[movie retain];
}
}
However, if you declared your property (in .h file):
#propert (nonatomic, retain) NSURL *movie;
and synthesized it in .m file, by #synthesize movie;, than there is no need to explicitly override the setter - the code above will be generated automatically for you. So whenever you want to set your movie you'll just call self.movie = newMovie; which will be equivalent to calling [self setMovie:newMovie];.
For more info read a section "Declared Properties" in Learning Objective-C guide.
EDIT: to explain what was wrong with your setter.
-(void)setMovie:(NSURL *)movieLocal {
movie = movieLocal; // first line
[self.movie retain]; // second line
...
}
In 1st line you are assigning movie to point to movieLocal, but you don't release old NSURL object that movie was pointing to before assignment. This was way, your causing a memory leak - you abandon memory, so it can never be relinquished back by your app. In general, abandoning memory is an easy way to get you application terminated by iOS, when objects are big and often leaked.
In 2nd line you are calling you setMovie setter again as self.movie = syntax causes the runtime to call a setter for movie property. This time it'll cause an infinite loop.
I hope my wording was clear for you and my answer helpful.
Related
I have a setter like this:
- (UIImagePickerController *) foto {
if (_foto == nil) {
_foto = [[UIImagePickerController alloc] init];
_foto.delegate = self;
}
return _foto;
}
it is declared like
#property (nonatomic, retain) UIImagePickerController *foto;
with
#synthesize foto = _foto;
on my dealloc I have
[_foto release];
At some point in my code I want to do this
self.foto = nil;
but something in my soul says the object assigned to self.foto previously will leak, because it was alloc on the setter... how do I make it right?
thanks.
Edit: No, that should be fine. As long as you don't assign something else to _foto before you release, it should work.
Yup. You create an object, then loose the pointer to it. If you throw an autorelease on the init line, that will fix it. You could also use ARC.
The init line doesn't actually do anything... You assign the pointer to an object you create, then assign it to something else.
I don't think there is a leak there. When you assign to self.foto like this:self.foto = nil;, it will release the former one automatically. If you assign it by this way: _foto = nil;, you need to release it manually before the assignment.
Yes that works, and will not leak. When you set the value of _foto, its retain count is 1 (because you called alloc). As long as you release it (which you've said you do) in dealloc, you should be fine, as the retain count will go back to 0. UNLESS your setter is ALSO written by you, and written improperly. It needs to explicitly release the old value, if it's not nil. Something like this:
- (void)setFoto:(UIImagePickerController*)foto {
if (_foto) {
[_foto release];
_foto = nil;
}
if (foto)
_foto = [foto retain];
}
Serious Problem here... i'm getting ECX_BAD_ACCESS if i try to NSLog an instance variable of my custom object. Following Function is called in my ViewController, payload holds String Data which is pulled from a url.
- (void) initVcardWithData:(NSString *)payload {
NSLog(#"1. initVcardWithData");
aVCard = [[vcardItem alloc] initWithPayload:payload];
VCardViewController *aVCardViewController = [[VCardViewController alloc] initWithVCard:aVCard];
[self presentModalViewController:aVCardViewController animated:YES];
[aVCard release];
}
So far so good. The initWithWithVCard function is as follows, theVCard and theVCardN are defined in #implementation and also set as a #property (nonatomic, retain) in (.h).:
-(id)initWithVCard:(vcardItem *)aVCard {
if(self = [super init]) {
theVCard = [aVCard retain];
theVCardN = [theVCard.PersonName retain];
}
NSLog(#"---- vCardViewController :: initWithVcard :: FirstName: %#", theVCard.PersonName.FirstName);
return self;
}
If i access the theVCardN object in my ViewController aVCardViewController within ViewDidLoad everything works like a charm. I set some labels with data from that object.
If i then try to access the instance variables from theVCardN within a function which is called from an IBAction which is connected to a button in View, i get an EXC_BAD_ACCESS error at the debugger console. The Function which tries to pull data from the instance variables is as follows:
-(IBAction)addressbookButtonTapped {
NSLog(#"RETAIN COUNT FOR theVCard: %i", [theVCard retainCount]);
NSLog(#"RETAIN COUNT FOR theVCardN: %i", [theVCardN retainCount]);
NSLog(#"Save to Adressbook: %#", theVCardN.FirstName);
//[self dismissModalViewControllerAnimated:YES];
}
The RetainCounter for theVCardN right before calling NSLog outputs "1". The NSLog Line then returns EXC_BAD_ACCESS in Debugger Console.
Any idea ?
Do not call -retainCount. Absolute retain counts are useless.
retainCount returns the absolute retain count of an object. The actual value will be an implementation detail that is very often completely out of your control as the system frameworks may do any number of things internally to cause the retain count to be modified in ways you don't expect.
It is useless for debugging and their are a wealth of tools that are specifically focused on tracking down these kinds of issues.
First, if there is a crash, there is a backtrace. Post it. Probably not that interesting in this case, but, still, always look to the backtrace to at least confirm that it is crashing where/how you think it is.
From the evidence posted, it sounds like theVCardN.FirstName is either set to garbage or the underlying string has been over-released. Turn on zombie detection mode and see if that is the case. Since it is crashing on FirstName, then show the code related to creating/storing the FirstName.
Also, instance variables and methods should always start with a lowercase letter; PersonName should be personName & FirstName should be firstName.
Maybe i'm reading the code wrong or misunderstanding your class structure, but it looks like you logging:
NSLog(#"Save to Adressbook: %#", theVCardN.FirstName);
Above, where you say it is still working, you are logging:
theVCard.PersonName.FirstName
Are you missing the "PersonName"? Meaning you should be logging:
NSLog(#"Save to Adressbook: %#", theVCardN.PersonName.FirstName);
In my code, I use a singleton object as a central point in my app to load and cache images the app frequently needs, so I don't have to do resource-intensive memory allocation each time I load an image.
But there are times during the execution of my app where memory usage gets intense and I would like to release the cached image data. Currently, I'm just releasing the UIImage instances from my singleton when I get a memory warning.
I would prefer, however, to be able to release the entire singleton object. Is that possible? If so, how?
Of course it is. Although it's rather likely that the memory usage of this object is negligible compared to the images.
By the nature of a singleton, you need to have an accessor for it, where you will create it if it does not currently exist:
+ (MySingletonClass*) mySingleton
{
if ( mySingleton == nil )
{
mySingleton = [[MySingletonClass alloc] init];
}
return mySingleton;
}
You just need to add another that you call when you want to destroy it:
+ (void) destroyMySingleton
{
[mySingleton release];
mySingleton = nil;
}
If you keep references to it around elsewhere you'll have trouble; don't do that. If you access from multiple threads you'll need to synchronize. Otherwise, it's pretty straightforward -- the getter will recreate when you next need it.
Here's an example of a singleton accessor for the OpenAL code I'm using.
// Eric Wing. Singleton accessor. This is how you should ALWAYS get
// a reference to the sound controller. Never init your own.
+ (OpenALSoundController*) sharedController
{
static OpenALSoundController* shared_sound_controller;
#synchronized(self)
{
if (nil == shared_sound_controller)
{
shared_sound_controller = [[OpenALSoundController alloc] init];
}
}
return shared_sound_controller;
}
OpenAL takes a while to load up so keeping one instance around is exactly what I need. With more than one thread in play (not my situation currently but I want my code to be ported to situations where this is the case) I put a lock on self. #synchronized(self) does exactly that.
Now I allocated the memory so I'm responsible for releasing it. I could call [shared_sound_controller autorelease] in the +sharedController accessor method but this may release the controller early, particularly when I have more than one thread and I call the accessor for the first time in a thread that's not the main thread.
Any object you create you can just release at any time. (Presuming you create it and set it's properties.)
self.myObject = [[myObjectClass alloc] init];
// do something with the object
[self.myObject release]; // anytime that you are not using the object
self.myObject = nil; // will also work if you've set the #property (retain, nonatomic)
I'm constructing a small iphone app and using a singleton to store and update a string that gets updated when the user taps letters or numbers on the screen to form a code.
i.e. they tap 3 then S then 4 and I need to track and combine that input to give me "3S4" say. When the singleton is initialised it creates an empty NSString and I then use the stringByAppendString method to add on the next letter/number tapped. When I first tried this I did not have the [enteredCode retain] line in there and the app would crash with EXC_BAD_ACCESS, always after 2 inputs. I set the NSZombie property which told me that the enteredCode had been de-allocated but I don't know where or how that happened. All I know is that at the end of the addInput method it will report the retainCount to be 2 say and then straight after I can see (by calling the singleton from elsewhere) it will drop down to 1 (when the retain line is in there).
My question is: though what I've done by adding [enteredCode retain] works for me am I breaking some rules here or going about this in the wrong/bad way? I just can't see why the string is being released.
I'm new to Objective-C btw
in MySingleton.h
#interface MySingleton : NSObject {
NSString *enteredCode;
}
in MySingleton.m
-(void) addInput:(NSString *) input
{
NSLog(#"enteredCode retain count is : %d \n ",[enteredCode retainCount]);
enteredCode = [enteredCode stringByAppendingString:input];
NSLog(#"enteredCode retain count is : %d \n ",[enteredCode retainCount]);
[enteredCode retain]; // without this the app crashes
NSLog(#"enteredCode retain count is : %d \n ",[enteredCode retainCount]);
}
-(id) init
{
self = [super init];
if (self)
{
enteredCode = #"";
}
return self;
}
First, never use the -retainCount method. The absolute count of retains on an object is an implementation detail of the frameworks and will often return confusing results.
Retain counts are something you should maintain entirely as a balanced set of deltas. If you cause a retain count to be added to something, you must release or autorelease that object somewhere. End of story.
This document explains it all.
With that knowledge in hand, the source of your crash is a fairly common memory management mistake.
enteredCode = [enteredCode stringByAppendingString:input];
Every time that line of code is executed, you are replacing enteredCode with an autoreleased instance of NSString. The autorelease pool is drained and your program crashes the next time enteredCode is used.
Your solution of retaining enteredCode is only half the solution. You need to ensure that the original value of enteredCode is released, too. See the memory management docs.
If this were my app, I would turn enteredCode into an #property that copies the string and always set and access enteredCode through that property, never retaining or releasing it manually in my code (outside of -dealloc, of course).
NSString's stringByAppendingString: returns a new NSString made by appending one string to the other, and the new NSString is set to autorelease, which empties the autorelease pool and your next run crashes the app. You're redefining an existing string with stringByAppendingString:, and that's causing the retain problems. (Alternatively, use NSMutableString and you can avoid this.)
By the way, you can do if (self = [super init]) in your init override. The declaration returns true if it occurs or can occur.
Here's how your code should look:
#interface MySingleton : NSObject {
NSString *enteredCode;
}
#property (nonatomic, retain) NSString *enteredCode;
#end
#synthesize enteredCode;
-(void) addInput:(NSString *) input
{
self.enteredCode = [self.enteredCode stringByAppendingString:input];
}
- (void)dealloc {
[enteredCode release];
}
#end
I'm doing the following:
- (void) accelerometer: (UIAccelerometer *)accelerometer didAccelerate: (UIAcceleration *)acceleration {
if (self.lastAcceleration) {
double i = self.lastAcceleration.x;
It works fine until I actually tilt the phone. Then I get EXC_BAD_ACCESS on the last line. lastAcceleration is a property with a retain. When I look at "x" in the debugger, it has a large negative value. Why would that throw a EXC_BAD_ACCESS exception only on tilt?
-- EDIT (Since this answer applies to responses below) --
I added this and now it works:
- (void)dealloc {
[lastAcceleration release];
Why would that matter? Also, should it be
[self.lastAcceleration release];
I wasn't previously releasing lastAcceleration anywhere. Here is the header declaration:
#interface MyViewController : UIViewController <UIAccelerometerDelegate> {
UIAcceleration *lastAcceleration;
}
#property(nonatomic, retain) UIAcceleration *lastAcceleration;
#end
My hunch is that the accelerometer API has nothing to do with the crash, the code you have shown smells like bad memory management, given that you're mixing ivar and property access I suspect you might be doing the same in other parts you're not showing.
Anyway a couple best practice things:
any object you have a pointer for in your class you should have retained, and conversely when you release it you should also zap the pointer so you don't risk accessing it after it has been deallocated (the exception to this rule are some patterns like the delegate object, where retaining the object would cause a retain cycle, but that's a whole other topic)
ivar setters and getters that are automatically generated via the #synthesized directive will retain and release the object for you for code that simply looks like it's assigning a pointer, so they're pretty handy, but property access (self.something = ...) and ivar access (something = ...) are not equivalent so you have to be careful
One easy way to make sure you don't mix the two up is to do something like this:
#interface MyObject : NSObject
{
SomethingObject *_something;
}
#property (nonatomic, retain) SomethingObject *something;
#end
#implementation MyObject
#synthesize something = _something;
#end
What we're doing here is making the ivar and property names slightly different, so that you are more aware of which one you're using, and the compiler will bark if you use don't use the bare something = ... syntax.
Now the #synthesize'd accessors are something like this:
- (void)setSomething:(SomethingObject *)newSomething
{
[newSomething retain];
[_something release];
_something = newSomething;
}
- (SomethingObject *)something
{
return _something;
}
With all that out of the way, [lastAcceleration release] is a bad thing to do because it isn't also setting the lastAcceleration pointer to nil, you are not guaranteed that it won't be deallocated and if you accidentally use it you are likely to crash.
[self.lastAcceleration release]; is incorrect because accessors take care of all the retain/release stuff for you.
The correct thing to do here is self.lastAcceleration = nil; that, if you look at the accessor code, will release and set the pointer to nil.
What is likely happening is that you are releasing lastAcceleration somewhere without also setting it to nil, and the if (self.lastAcceleration) { check is hitting a released object.
Main reason to have retained properties is to avoid explicit retain/release calls and memory management bugs associated with them. But in dealloc method either way is fine, since object will cease to exist soon.
[self.lastAcceleration release]; - not necessary.
[lastAcceleration release]; self.lastAcceleration = nil;
Both are fine if used in dealloc.
Outside of dealloc use only
self.lastAcceleration = nil;
EXC_BAD_ACCESS is raised when you access released memory. My guess would be that you somewhere released self.lastAcceleration but didn't set it to null.
Are you sure it is related to tilting?