views:

189

answers:

3

In objective-c, I have a utility class with a bunch of static methods that I call for various tasks. As an example, I have one method that returns an NSArray that I allocate in the static method. If I set the NSArray to autorelease, then some time later, the NSArray in my calling method (that is assigned to the returned pointer) losses it's reference because the original form the static method is cleaned up. I can't release the NSArray object in the static method because it needs to be around for the return and assignment.

What is the right way to return an object (like the NSArray) from a static class, and have it hang around for the calling class, but then get cleaned up later when it is no longer needed?

Do I have to create the object first in the caller and pass in a pointer to the object and then return that same object form the static method?

I know this is a basic O-O problem, I just never had this issue in Java and I do not do much C/C++.

Thanks for your help.

+1  A: 

Your autorelease is correct in the return just retain it when you call the static method.

NSArray *data = [[StaticClass getArray] retain];

If you have a property for the place your assigning the return value to, you can just do self.data = .. and the retain is automatic.

Matt S
That helps. Thanks.
Michael Bordelon
Still struggling. I am trying this:for (NSString * date in dateList) { [historyList addObject:[[BIUtility historyForDate:date] retain]]; }In the historyForDate method I autorelease like this...+ (NSArray *) historyForDate:(NSString *)date { NSMutableArray * ret = [[[NSMutableArray alloc] init] autorelease];...The object is getting cleaned up about midway through building the tableview. Ideas?
Michael Bordelon
@Micheal: Though not a direct answer, you don't need to retain an object as you add it to an array ( `NSArray` s automatically retain their elements).
jbrennan
Are you actually returning the array in your class method? It looks as though you aren't but that could just be me nit picking. I think this problem is larger than what what we're seeing at the moment. It's likely how historyList is being managed not the elements inside it.
Matt S
+2  A: 

Please take the time to read over the rules. These apply to all of the frameworks you'll be using, and should apply to your code as well. Burn these into your head, and they'll become second nature. Thankfully, it's not complex, rather simple.

jer
A: 

It's quite simple. If you do not own an object, it will go away at some indeterminate point in the future. In your case, the "indeterminate" point is when the autorelease pool gets drained, which in the normal case, is at the end of processing the current event.

If you want an object to hang around, you need to own it. The memory management rules referred to by jer will tell you exactly how you get ownership of an object. In this case, you need to retain the object. You must then, of course, release it later when you have done with it.

Regards your comment to Matt's answer. Your code is this:

for (NSString * date in dateList) 
{ 
    [historyList addObject:[[BIUtility historyForDate:date] retain]]; 
}

and

+ (NSArray *) historyForDate:(NSString *)date 
{ 
    NSMutableArray * ret = [[[NSMutableArray alloc] init] autorelease]; 
}

The first thing you need to know is that collections retain their members, so, in fact, your retain of the historyForDate is unnecessary. You don't want to own that object, historyList does. If it's disappearing, it's probably because historyList itself is being deallocated (because you don't own it) or is nil.

By the way, historyForDate: does nothing with the date. Is that correct?

JeremyP