0

First of all: I already searched on google and SO for solutions - none worked. I've got an application which loads the artwork of the current iTunes track and displays it; this is stored in a NSImage instance, among some other variables, in a class:

@interface infoBundle : NSObject
 @property (strong) NSImage *track_artwork;
 @property (weak) NSString *track_title;
 @property (weak) NSString *track_album;
 @property (weak) NSString *track_artist;
@end

Then, an instance of this class is created:

-(infoBundle*)returnInfoBundle {
 infoBundle* tmpBundle = [[infoBundle alloc]init];
 tmpBundle.track_artwork = [[NSImage alloc]initWithData:[(iTunesArtwork *)[[[iTunes currentTrack] artworks] objectAtIndex:0] rawData]];
 [...]
 return tmpBundle;
}

And later used:

-(void)iTunesDidChange {
 infoBundle* tmpBundle = [self returnInfoBundle];
 [...]
 [imageView setImage:tmpBundle.track_artwork];
}

That's eating up ~2MB (Cover size, I'd guess) per call of iTunesDidChange.

I already tried:

  • [tmpBundle autorelease];
  • [tmpBundle release];
  • [tmpBundle dealloc];
  • tmpBundle = nil;

and, after that didn't help: - Enabling ARC.

=> Why is this eating up memory, although the object (tmpbundle) should get removed? => How may I achieve leak-less NSImage usage?

Thanks for any tips/suggestions/solutions :)

  • Tip for next time: Try using Instruments to debug performance issues like these, much more helpful about other aspects of your application and quicker. – duci9y Jul 05 '14 at 14:21
  • `tempBundle.track_artwork`looks like a typo? – mikeD Jul 05 '14 at 16:21
  • @duci9y did that. However, I found the information provided by Instruments not very helpful. Detailed, indeed, but not helpful. – w00pied1ner Jul 05 '14 at 19:11
  • @mikeD where is that typo? :) – w00pied1ner Jul 05 '14 at 19:12
  • It'd always be useful. Maybe we could help you interpret the results. – duci9y Jul 05 '14 at 19:17
  • You don't present tmpBundle, only tmpbundle. Opps, my typo, too. Anyway, the uppercase B is confusing. – mikeD Jul 05 '14 at 19:22
  • Also, please read this guide and name your methods and variables properly https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html . This is the third time today I'm advising someone to read it. – duci9y Jul 05 '14 at 19:36
  • Create a property of `infoBundle* tmpBundle`, and use it when you need. After you are done with it, you release and set it to `nil` – E-Riddie Jul 05 '14 at 20:18
  • @3r1d I already am setting tmpBundle to nil. Can you give me a code-example, please, as I guess I misunderstand your answer. :) – w00pied1ner Jul 05 '14 at 20:58

3 Answers3

0

Issue

You will have a memory leak if you create your object on your method and not release it inside that method or you have to reference it when you pass it as a parameter by reference : Passing arguments by value or by reference in objective C

Your problem is that you are creating an instance of infoBundle two times, and when you are initializing another instance of it, you are leaving the first one without reference, so it remains in memory, and without connection to remove it (memory leak).

Solution

To make your things easier you should create an instance of your object

@implementation
{
    infoBundle* tmpBundle;
}

Use it where ever you need it

-(infoBundle*)returnInfoBundle 
{
    tmpBundle = [[infoBundle alloc]init];
    tmpBundle.track_artwork = [[NSImage alloc]initWithData:[(iTunesArtwork *)[[[iTunes currentTrack] artworks] objectAtIndex:0] rawData]];
    [...]
    return tmpBundle;
}

-(void)iTunesDidChange 
{
    tmpBundle = [self returnInfoBundle];
    [...]
    [imageView setImage:tmpBundle.track_artwork];
} 

And when you are finished with that object dealloc will automatically release it if you add it to dealloc method:

- (void) dealloc
{
    [tmpBundle release];
    tmpBundle = nil;
}

Hope it helps! :)

Community
  • 1
  • 1
E-Riddie
  • 14,660
  • 7
  • 52
  • 74
0

Just modifiy this line :-

  infoBundle* tmpBundle = [[[infoBundle alloc]init]autorelease];
Hussain Shabbir
  • 14,801
  • 5
  • 40
  • 56
-1

I can’t tell from your code what you are doing in [imageView setImage:tmpbundle.track_artwork]; but you may be having the same problem I had.

I was using

self.imageToDisplay  = [UIImage imageNamed:pictFileName];

and kept getting leaks. I switched to

self.imageToDisplay = [UIImage imageWithContentsOfFile:pictFile];

and they went away.

According to the documentation for imageNamed,

This method looks in the system caches for an image object with the specified name and returns that object if it exists… If you have an image file that will only be displayed once and wish to ensure that it does not get added to the system’s cache, you should instead create your image using imageWithContentsOfFile:. This will keep your single-use image out of the system image cache, potentially improving the memory use characteristics of your app.

It sounds like you have either the same or a similar issue.

JScarry
  • 1,507
  • 1
  • 13
  • 25
  • How do you use UIImage in developing a Cocoa application? – El Tomato Jul 05 '14 at 21:40
  • If Cocoa doesn’t use UIImage, then he has a different problem than I did. My point was that UIImage:imageNamed caches the files and causes leaks. UIImage:imagewithContentsOfFile doesn’t cache the image so there is no leaking. I couldn’t tell from his code how he displays the image, so I thought he might have a similar problem. – JScarry Jul 05 '14 at 22:59
  • Cocoa and Cocoa Touch are two different things, silly. – El Tomato Jul 05 '14 at 23:14