Athiwat Chunlakhan
Athiwat Chunlakhan

Reputation: 7799

How does retain works in Objective-C?

I have this code.

-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
    if ([elementName isEqualToString:@"stat"]) {
        currentKey = [attributeDict objectForKey:@"name"];
        currentValue = [[[NSMutableString alloc] init] autorelease];
    }  
}

-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
    [currentValue appendFormat:string];
}

-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
    if ([currentKey isEqualToString:@"url"])
        self.urlToServerLog = currentValue;
}

And the header file

    @interface HDEAppDelegate : NSObject <NSApplicationDelegate, NSXMLParserDelegate> {
@private
    NSWindow *window;
    NSString* scratchFolder;
    NSMutableString *urlToServerLog;
    NSString *currentKey;
    NSMutableString *currentValue;
}

@property (assign) IBOutlet NSWindow *window;
@property (assign) IBOutlet NSTextField *output;
@property (assign) IBOutlet NSTextField *matchID;
@property (retain) NSString *scratchFolder;
@property (retain) NSMutableString *urlToServerLog;

-(IBAction) ParserButton:(id)sender;
-(NSFileWrapper*)unzip:(NSData*)zipData;

@end

The problem here is the object at urlToServerLog/currentValue gets removed.

I found a solution is to copy the object but my original solution still stands. Why doesn't retain work in this case?

BTW: scratchFolder is also used with a autorelease object and it's working perfectly.(Using in the exact same way, return from NSString(autorelease) and assign to scratchFolder.

Upvotes: 0

Views: 367

Answers (2)

user557219
user557219

Reputation:

In -parser:didStartElement:namespaceURI:qualifiedName:attributes:, you allocate a new string and autorelease it:

currentValue = [[[NSMutableString alloc] init] autorelease];

This means that the this string will be released when the corresponding autorelease pool is drained. In general, if an object needs to be kept alive after a method has finished executing, you need to own it. In your case, do not autorelease it at this point (and remember to release it when you don’t need it any longer), or make currentValue a retain property and use self.currentValue = … instead.

Another point to consider: you probably want to make urlToServerLog a copy property instead of a retain one because currentValue, being a mutable string, will be changed while the XML parser is being executed. If you’re using retain, your urlToServerLog property will also change since it points to the same mutable string. By changing the property to copy, you effectively make a copy of currentValue — any further changes to currentValue won’t affect that property.

Upvotes: 1

Mark Granoff
Mark Granoff

Reputation: 16938

currentValue is being released when didStartElement: finishes. I assume currentValue is a class variable? What value do you see for urlToServerLog after you assign currentValue to it?

Upvotes: 1

Related Questions