I suspect that name is not actually leaking, it is simply not being released when you think it is. Under ARC, I believe that scanUpToString:intoString:
would be defined similarly to methods using NSError
. In other words, it takes NSString * __autoreleasing *
. Therefore, whatever value is passed to it is actually autoreleased, and won't be released until the current autorelease pool is drained. Assuming you don't have any others dotted around, that will be when the run loop goes around again. If that memory usage is a problem to you, it would be possible to place an explicit autorelease pool around the loop, so the objects go away immediately:
NSScanner *scanner = [[NSScanner alloc] initWithString:query];
[scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"&?"]];
@autoreleasepool
{
NSString *parameterString = [NSString new];
while ([scanner scanUpToString:ampersand intoString:¶meterString])
{
NSScanner *parameterScanner = [[NSScanner alloc] initWithString:parameterString];
NSString *name = [NSString new];
[parameterScanner scanUpToString:isEqual intoString:&name];
NSString *value = [parameterString substringFromIndex:([name length] + 1)];
[parameters setObject:value forKey:name];
}
}
That is probably unnecessary though, and the run loop will clear up the objects anyway.
That said, there is still a small issue that means the compiler is creating an additional temporary variable for you. Your name
variable is implicitly __strong
, so the compiler inserts a temporary variable that is __autoreleasing
and copies the values around for you. You can avoid this by explicitly declaring the NSString
as autoreleasing. You also do not need to init
it, as rckoeness said, because the scanUpToString:intoString:
is doing that for you (which is why it has to be __autoreleasing
in the first place). (See http://developer.apple.com/library/mac/ipad/#releasenotes/ObjectiveC/RN-TransitioningToARC/_index.html for more info).
So, overall I think you actually want your code to look like this:
NSScanner *scanner = [[NSScanner alloc] initWithString:query];
[scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"&?"]];
NSString __autoreleasing *parameterString = nil;
while ([scanner scanUpToString:ampersand intoString:¶meterString])
{
NSScanner *parameterScanner = [[NSScanner alloc] initWithString:parameterString];
NSString __autoreleasing *name = nil;
[parameterScanner scanUpToString:isEqual intoString:&name];
NSString *value = [parameterString substringFromIndex:([name length] + 1)];
[parameters setObject:value forKey:name];
}
Hope that helps!
I've had another thought, perhaps name
is simply a red herring. Leaks will show your where the allocation happened, but name
continues to exist beyond this loop, when it is added to parameters
. I presume that it is an NSMutableDictionary
or similar, based on the selector. If I were you I would confirm that the name
instances are not being leaked because that dictionary (or something that later reads those keys from the dictionary) is being leaked.