使用ARC时NSScanner scanUpToString泄漏

Thy*_*hys 2 iphone objective-c nsscanner automatic-ref-counting

要解析URL的部分查询字符串,我使用此方法:

NSScanner *scanner = [[NSScanner alloc] initWithString:query];
        [scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"&?"]];

        NSString *parameterString = [NSString new];
        while ([scanner scanUpToString:ampersand intoString:&parameterString]) 
        {
            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];


        }
Run Code Online (Sandbox Code Playgroud)

在这个项目中我使用的是ARC,但是这个方法仍在泄漏:

[parameterScanner scanUpToString:isEqual intoString:&name];
Run Code Online (Sandbox Code Playgroud)

究竟是什么泄漏,我该如何解决?

ext*_*dom 6

我怀疑这个名字实际上并没有泄漏,只是当你认为它没有被释放时.在ARC下,我相信它的scanUpToString:intoString:定义与使用的方法类似NSError.换句话说,它需要NSString * __autoreleasing *.因此,传递给它的任何值实际上是自动释放的,并且在当前自动释放池耗尽之前不会释放.假设你没有任何其他点缀,那就是当运行循环再次出现时.如果内存使用对你来说是一个问题,那么就可以在循环周围放置一个显式的自动释放池,这样对象就会立即消失:

NSScanner *scanner = [[NSScanner alloc] initWithString:query];
[scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"&?"]];

@autoreleasepool
{
    NSString *parameterString = [NSString new];
    while ([scanner scanUpToString:ampersand intoString:&parameterString]) 
    {
        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];


    }
}
Run Code Online (Sandbox Code Playgroud)

这可能是不必要的,并且运行循环无论如何都会清理对象.

也就是说,仍有一个小问题意味着编译器正在为您创建一个额外的临时变量.您的name变量是隐式的__strong,因此编译器会插入一个临时变量,__autoreleasing并为您复制值.您可以通过明确声明NSString为自动释放来避免这种情况.你也不需要init它,正如rckoeness所说的那样,因为scanUpToString:intoString:它正在为你做这件事(这就是为什么它必须__autoreleasing在第一位).(有关详细信息,请参阅http://developer.apple.com/library/mac/ipad/#releasenotes/ObjectiveC/RN-TransitioningToARC/_index.html).

所以,总的来说,我认为你实际上希望你的代码看起来像这样:

NSScanner *scanner = [[NSScanner alloc] initWithString:query];
[scanner setCharactersToBeSkipped:[NSCharacterSet characterSetWithCharactersInString:@"&?"]];

NSString __autoreleasing *parameterString = nil;
while ([scanner scanUpToString:ampersand intoString:&parameterString]) 
{
    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];
}
Run Code Online (Sandbox Code Playgroud)

希望有所帮助!


我有另一个想法,也许name只是一个红鲱鱼.泄漏将显示分配发生的位置,但name在此循环之后继续存在,当它被添加到parameters.我认为它是一个NSMutableDictionary或类似的,基于选择器.如果我是你,我会确认name实例没有被泄露,因为该字典(或后来从字典中读取这些键的东西)被泄露.