message sent to released object (never released manually) - iphone

Removed release statements. Some of them seemed to be okay, but that was probably just because other things were exploding first.
- (void)handleNowPlayingItemChanged:(id)notification {
MPMediaItem *item = self.musicPlayer.nowPlayingItem;
NSString *title = [item valueForProperty:MPMediaItemPropertyTitle];
NSNumber *duration = [item
valueForProperty:MPMediaItemPropertyPlaybackDuration];
float totalTime = [duration floatValue];
progressSlider.maximumValue = totalTime;
CGSize artworkImageViewSize = self.albumCover.bounds.size;
MPMediaItemArtwork *artwork = [item valueForProperty:
MPMediaItemPropertyArtwork];
if (artwork) {
self.albumCover.image = [artwork imageWithSize:artworkImageViewSize];
} else {
self.albumCover.image = nil;
}
titleLabel.text = title;
/*OpenEars stuff*/
}
In another question I mention the SQLite errors concerning artwork.
** Deleted error and details concerning NSZombieEnabled alert of call to released objects. **
Well don't I feel stupid. It was all memory management.
I put effort into not leaking anything, even in a temporary solution, and yet I did this...

In the code you provide I do not see any calls to retain, alloc/init, or some variation of copy. That means that you should not have a any calls to release in that method and that will be the cause of your crash. Make sure you are not over releasing in other methods and remember the basics of memory management.

You're releasing title and artwork, but they're not yours. This will lead, soon or later, to a tentative to release an already deallocated object (from item's dealloc or somewhere else).

// [artwork release];
//[title release];
comment those since those are autoreleased object

Related

retainCount shows MaxInt

After trying to print retainCount of object I get 2147483647. Why do I get such a result? It should be 1, shouldn't?
NSString *myStr = [NSString new];
NSUInteger retCount = [myStr retainCount];
NSLog(#"refCount = %u", retCount);
2011-09-08 17:59:18.759 Test[51972:207] refCount = 2147483647
I use XCode Version 4.1. Tried compilers GCC 4.2 and LLVM GCC 4.2 - the same result.
Garbage Collection option was set to unsupported.
NSString is somewhat special when it comes to memory management. String literals (something like #"foo") are effectively singletons, every string with the same content is the same object because it can't be modified anyway. As [NSString new] always creates an empty string that cannot be modified, you'll always get the same instance which cannot be released (thus the high retainCount).
Try this snippet:
NSString *string1 = [NSString new];
NSString *string2 = [NSString new];
NSLog(#"Memory address of string1: %p", string1);
NSLog(#"Memory address of string2: %p", string2);
You'll see that both strings have the same memory address and are therefore the same object.
This doesn't directly answer your question, but retainCount is not really all that useful and should not be used for testing. See this SO post for details.
When to use -retainCount?
While NSString's are an odd case (there are others in the framework) you might also run across this in other clases - it's one of the ways of creating a singleton object.
A singleton only exists once in the app and it's pretty important that it never gets released! Therefore, it will overwrite some methods of NSObject including (but not limited to):
- (id)release {
// Ignore the release!
return self;
}
- (NSUInteger)retainCount {
// We are never going to be released
return UINT_MAX;
}
This object can never be released and tells the framework that it's a singleton by having a ludicrously high retain count.
Checkout this link for more information about singleton objects.
I've seen this a couple of times regarding NSStrings, the retainCount returns the maximum count instead of the actual one when you try to look at retainCounts of strings in this manner.
Try this;
NSString *myStr = [[NSString alloc] init];
NSUInteger retCount = [myStr retainCount];
NSLog(#"refCount = %u", retCount);
Edit: Restored NSUInteger

Why does this cause a crash?

I have these two buttons hooked up to these two methods (they're nearly identical)
-(void)moveOneImageNewer{
int num = [numberOfImage intValue];
num--;
numberOfImage = [[NSString stringWithFormat:#"%i",num] retain];
//Load the image
[self loadImage];
}
-(void)moveOneImageOlder{
int num = [numberOfImage intValue];
num++;
numberOfImage = [NSString stringWithFormat:#"%i",num];
//Load the image
[self loadImage];
}
If I hit either of them twice (or once each, basically if they get called a total of two times) I get an EXC_BAD_ACCESS. If I throw a retain on: numberOfImage = [[NSString stringWithFormat:#"%i",num]retain] it's fine though. Can someone explain why this is? I did an NSZombie on the instruments and traced it back to this stringWithFormat call. Thanks in advance!
+stringWithFormat: doesn't contain 'new', 'alloc', 'copy', or 'retain', so it should be expected that you have to retain the return value of it if you want the new NSString it creates to stick around.
Edited to include this handy link duskwuff kindly dug up: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-BAJHFBGH
If numberOfImage is a properly declared property, e.g.
#property (copy) NSString *numberOfImage;
and it was properly synthesized (in the #implementation section for the class):
#synthesize numberOfImage;
then you can do:
- (void) moveOneImageNewer
{
self.numberOfImage = [NSString stringWithFormat: #"%i", [self.numberOfImage intValue] - 1];
// Load the image
[self loadImage];
}
The property setter will take care of retaining the string and, if necessary, releasing the previous string.
FWIW, why on earth is numberOfImage a string? Why not a simple int?
numberOfImage is an instance variable or property of your class, right?
You are setting it to a stringWithFormat (which returns an auto-released NSString) without claiming ownership of that object (by calling retain).
If you do not retain it, it will get auto-released before the method is called again (and then the first line will fail, as it tries to access the previously set, now auto-released value).
Consider using properties, they have auto-generated memory management code (including releasing the old NSString when you set the new one).
You haven't retained the string object in "moveOneImageOlder", so that object gets autoreleased at the end of the event cycle and points to nothing. That's why you get the EXC_BAD_ACCESS next time you try to use it.
Use a retain to claim ownership of the NSString. Remember to release when you're done though (you can use properties to help you with this)
-(void)moveOneImageNewer{
int num = [numberOfImage intValue];
num--;
[numberOfImage release];
numberOfImage = [[NSString stringWithFormat:#"%i",num] retain];
//Load the image
[self loadImage];
}
-(void)moveOneImageOlder{
int num = [numberOfImage intValue];
num++;
[numberOfImage release];
numberOfImage = [[NSString stringWithFormat:#"%i",num] retain];
//Load the image
[self loadImage];
}
Add this in dealloc:
- (void)dealloc {
[numberOfImage release];
[super dealloc];
}
Well, the NSString class method "stringWithFormat" returns an autorelease NSString object if I'm right.
So the second call to your method would have numberOfImage pointing to nothing, as the autorelease NSString object it used to be pointing to has already been released and deallocated since you didn't retain it.
The part that is directly causing the crash is [numberOfImage intValue] when you call the method a second time, as you sending a message to an object (pointed to by numberOfImage) that no longer exist.

instruments showing NSPlaceholderstring leaks

I'm trying to reduce the memory leaks in my app, so i used instruments to find all the leaks. I managed to remove almost all of the leaks, except a very annoying one.
Instruments is telling me that i have a lot of NSPlaceholderstring leaks.
The code that generated the leak (according to instruments) is:
if (nil == storedHash)
{
NSString *description = [[NSString alloc] initWithFormat:#"1 = %# 2= %d", uId, service];
self.storedHash = description; // This line is the leak according to instruments
[description release];
description = nil;
}
return storedHash
storedHash is define like this:
#property(copy) NSString* storedHash;
I tried everything i can think of:
I used retain instead of copy
I used an autorelease allocation of the NSString (stringWithFormat)
I tried wrapping the code with an autorelease pool
Nothing of the above changed the leak. (In some cases the type of the leaks change, but there are still leaks)
Ideas anyone?
Where do you release storedHash? Do you release it in dealloc?
Note that NSPlaceholdeString is an implementation detail; it is the class of the instance returned by NSString's +alloc method.
How about in the dealloc method? Did you release the storedHash in the dealloc method? And how about checking if (nil == self.storedHash)
You should use
#property(nonatomic, retain) NSString* storedHash;
instead copy. #property(copy) didn't release your old NSObject and you should do it yourself:
if (nil == storedHash)
{
NSString *description = [[NSString alloc] initWithFormat:#"1 = %# 2= %d", uId, service];
[self.storedHash release];
self.storedHash = description; // This line is the leak according to instruments
[description release];
// description = nil; // it's unnecessary
}
also you should release storedHash in dealloc.

Can't Figure Out How To Fix Memory Leaks on iPhone

I was running Leaks tool and discovered a massive leak in my Dictionary mutableDeepCopy but I can't figure out what's wrong with the code. Any suggestions?
#interface RootViewController : UIViewController{
NSDictionary *immutableDictionary;
NSMutableDictionary *mutableDictionary;
}
Here is the line of code that's highlighted in Instruments
self.mutableDictionary = [self.immutableDictionary mutableDeepCopy];
Here is the method for creating a mutable copy of a Dictionary
#interface NSDictionary(MutableDeepCopy)
-(NSMutableDictionary *)mutableDeepCopy;
#end
Here is method implementation, I've highlighted the code that Leaks saids is leaking 100%
- (NSMutableDictionary *) mutableDeepCopy {
NSMutableDictionary *dictionaryToReturn = [NSMutableDictionary dictionaryWithCapacity:[self count]];
NSArray *keys = [self allKeys];
for(id key in keys) {
id value = [self valueForKey:key];
id copy = nil;
if ([value respondsToSelector:#selector(mutableDeepCopy)]) {
copy = [value mutableDeepCopy];
} else if ([value respondsToSelector:#selector(mutableCopy)]) {
copy = [value mutableCopy]; //This is the Leak
}
if (copy == nil) {
copy = [value copy];
}
[dictionaryToReturn setValue:copy forKey:key];
}
return dictionaryToReturn;
}
You need to analyse this in light of Apple's Memory Management Rules.
Starting with this line:
self.mutableDictionary = [self.immutableDictionary mutableDeepCopy];
I would expect mutableDeepCopy to return an object I own, so at some point I need to release or autorelease it. e.g.
NSMutableDeepCopy* temp = [self.immutableDictionary mutableDeepCopy];
self.mutableDictionary = temp;
[temp release];
or
self.mutableDictionary = [[self.immutableDictionary mutableDeepCopy] autorelease];
So now we need to look at mutableDeepCopy. Because it has 'copy' in the name it needs to returned an "owned" object which, in practice means "forgetting" to release the returned object. You have already failed to do that when you create the returned object in the first line, since dictionaryWithCapacity: gives you an object you do not own. Replace it with
NSMutableDictionary *dictionaryToReturn = [[NSMutableDictionary alloc] initWithCapacity:[self count]];
Now you own it.
It is important that you make your mutableDeepCopy obey the rules because it means you can treat the objects returned from mutableDeepCopy, mutableCopy and copy in exactly the same way. In all three cases you own the object copy that you insert into the array. Because you own it, you must release it or it'll leak as you found out. So, at the end of the loop, you need
[copy release];
That'll stop the leak.
How is your property declared? If is is retain or copy, then this doesn't leak.
Your problem is that the name mutableDeepCopy suggests that it returns a retained object, and not an autoreleased one as it actually does.
Edit:
And at the mutableDeepCopy itself, you need to release the copy variable after adding to the dictionary.
mutableCopy increments the retain count of the object, as does setValue:forKey:. This means that when dictionaryToReturn is dealloc'ed, the object that had mutableCopy called still has a retain count of one.
Try doing this instead:
copy = [[value mutableCopy] autorelease];

NSMutableArray and property leaking memory

I am in memory-leak cleanup mode on my latest app, and have come across something that I am unable to solve.
the following method has been cleaned up except for 1 nagging issue. Instruments tells me that my NSMutableArray called itemsToKeep is leaking memory, at the point that I am creating the object. Any ideas on why I am leaking memory would be most appreciated.
Here are some notes on retainCounts:
entering the method: self.myList has retainCount = 1
exiting the method: self.myList has retainCount = 2 and itemsToKeep has retainCount= 2.
I can easily do a [itemsToKeep release] at the end which brings both counts down to 1, but the app crashes after a while (and I think I know why).
Does anyone know how I can get rid of the memory leak for itemsToKeep?
Thanks.
-(void)parsedScores:(BOOL)shouldAdd {
//trim space, tab, newline from both ends
NSString *tmp = self.lblCurrentName.text;
NSString *list = [self trimString:tmp];
NSString *separators = #",";
[self.myList removeAllObjects]; // doesn't impact retain counts
self.myList = (NSMutableArray *)[list componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:separators]]; //this bumps up the self.myList retain count to 2
NSMutableArray *itemsToKeep = [NSMutableArray arrayWithCapacity:30];
for (NSString *item in self.myList) {
NSString *tmpItem = [self trimString:item];
if (! [self shouldRemoveItem:tmpItem]) {
[itemsToKeep addObject:tmpItem];
}
}
self.myList = itemsToKeep; //makes both variables' retain counts = 2
}
I can't see a leak in the method you've provided, so I assume it's happening elsewhere. You should check if self.myList is retained somewhere else without it being released.
Also, you probably shouldn't be looking at the retain count for debugging purposes. The retain count can be misleading because it doesn't matter how many times an object is retained as long as it's released an equal amount of times.