Objective-C and retain/release of returned objects

发布时间:2014-10-23 23:30:10

Objective-C and retain/release of returned objects I am new to Objective-C, so this might be a dumb question. I cannot help but see the similarities between ObjC and Microsoft's COM with respect to memory management (AddRef/Release vs retain/release). In a COM environment, it's more or less imposed on you to always AddRef (retain) an object before returning it to the caller. From what I've seen so far (I'm a third through Cocoa® Programming for Mac® OS X (3rd Edition)), the memory management part is somewhat fuzzy. Assuming there is no GC, what is the idiomatic way to return an object? Answers 1. Read Memory Management Programming Guide about autorelease pools. In Objective-C, by convention, objects should be returned autoreleased (unless the method returning the object has a name that begins with “alloc”, “new”, “copy”, or “mutableCopy”). Autoreleased objects are tracked by Objective-C in a pool and automatically handled, which means you don't need to care about sending a final release to them. This greatly simplifies reference counting compared to COM, and this is why you're not seeing any release calls on returned objects most of the time. In contrast, the same convention specifies that all objects returned by a method whose name begins with alloc, new, copy, or mutableCopy, are the responsibility of the method caller. You have to manually call release on these objects or your program will have memory leaks. 2. Cocoa goes around the limitations of AddRef/Release in COM by introducing a third sibling;autorelease. retain - I need this, make it stick around. release - I don't need this anymore, you may remove it immediately. autorelease - I don't need this, but let it stay around a few seconds in case someone else wants to pick it up first. This tiny addition allow most return values to be handles as-if we had garbage collection. If you are not interested in keeping the return value around, just do nothing extra. In order to get this to work there is a convention (a convention good enough to let the compiler do the memory stuff automatically for you with upcoming ARC): Method names beginning with these must return retained instances: alloc copy new retain All other must return autoreleased instances. Three example implementation for how this can be applied in practice: -(NSString*)newHelloWorldString { NSString* s = [NSString stringWithString:@"Hello world"]; // Apply retain because s in now autoreleased return [s retain]; //new开头的方法名 需要返回+1 retain的对象 } -(NSString*)helloWorldString { NSString* s = [[NSString alloc] initWithString:@"Hello world"]; // Apply autorelease because s is now retained. return [s autorelease]; } -(NSString*)fullName { // No memory management needed, everything is autoreleased and good. NSString* fn = [self firstName]; NSString* ln = [self lastName]; NSString* s = [NSString stringWithFormat:@"%@ %@", fn, ln]; return s; } 3. Essentially i would recommend making the class that receives it retain it. i.e class stackoverflow receives object answer. i.e -(void) setAnswer:(Answer*) _answer{ self.answer = _answer; // If the answer is created from a returned message. [_answer release]; } edit: I think I might have put up the wrong stuff up there now that i am looking at it the 2nd time . Meant something along the lines: Answer *_answer = [stackoverflow createAnswer]; self.answer = _answer; [_answer release]; Another question about return and retain: Should I send retain or autorelease before returning objects? I thought I was doing the right thing here but I get several warnings from the Build and Analyze so now I'm not so sure. My assumption is (a) that an object I get from a function (dateFromComponents: in this case) is already set for autorelease and (b) that what I return from a function should be set for autorelease. Therefore I don't need to send autorelease or retain to the result of the dateFromComponents: before I return it to the caller. Is that right? As a side note, if I rename my function from newTimeFromDate: to gnuTimeFromDate the analyzer does not give any warnings on this function. Is it the convention that all "new*" methods return a retained rather than autoreleased object? In Memory Management Programming Guide for Cocoa it says "A received object is normally guaranteed to remain valid within the method it was received" and that "That method may also safely return the object to its invoker." Which leads me to believe my code is correct. However, in Memory Management in Cocoa it says "Assume that objects obtained by any other method have a retain count of 1 and reside in the autorelease pool. If you want to keep it beyond the current scope of execution, then you must retain it." Which leads me to think I need to do a retain before returning the NSDate object. I'm developing with Xcode 3.2.1 on 10.6.2 targeting the iPhone SDK 3.1.2. Here's the code in case you have trouble reading the screen shot: //============================================================================ // Given a date/time, returns NSDate for the specified time on that same day //============================================================================ +(NSDate*) newTimeFromDate:(NSDate*)fromDate Hour:(NSInteger)hour Minute:(NSInteger)min Second:(NSInteger)sec { NSCalendar* curCalendar = [NSCalendar currentCalendar]; const unsigned units = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit; NSDateComponents* comps = [curCalendar components:units fromDate:fromDate]; [comps setHour: hour]; [comps setMinute: min]; [comps setSecond: sec]; return [curCalendar dateFromComponents:comps]; } Answers: You are nearly right. The only problem that clang correctly points out is that your method promises a retain count +1 object (for its name containing “new”) but you are returning an autoreleased object. You have two options: removing the “new" from the method name or retaining the returned object. It’s far more Cocoa-ish to return the autoreleased object (as you do) and name the method timeFromDate: