2

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];


        }

このプロジェクトでは ARC を使用していますが、まだこの行でメソッドがリークしています:

[parameterScanner scanUpToString:isEqual intoString:&name];

何が漏れているのか、どうすればこれを解決できますか?

4

4 に答える 4

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];


    }
}

ただし、これはおそらく不要であり、実行ループはとにかくオブジェクトをクリアします。

とはいえ、コンパイラが追加の一時変数を作成していることを意味する小さな問題がまだ残っています。変数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];
}

それが役立つことを願っています!


私は別の考えを持っていました、おそらくname単に赤いニシンです. リークは、割り当てが発生した場所を示しますが、nameに追加されると、このループを超えて存在し続けますparametersNSMutableDictionaryセレクターに基づいて、または類似していると思います。私があなただったらname、その辞書 (または後で辞書からそれらのキーを読み取るもの) が漏洩しているため、インスタンスが漏洩していないことを確認します。

于 2012-01-16T13:18:48.920 に答える
1

name変数を初期化する理由はありません

    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 = nil;
        [parameterScanner scanUpToString:isEqual intoString:&name];

        NSString *value = [parameterString substringFromIndex:([name length] + 1)];
        [parameters setObject:value forKey:name];


    }
于 2012-01-11T14:00:12.713 に答える
0

autoreleased イニシャライザの使用はどうですか?

// [NSScanner scannerWithString:]
// and
// [NSString string]

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

NSString *parameterString = [NSString string];
while ([scanner scanUpToString:ampersand intoString:&parameterString]) 
{
    NSScanner *parameterScanner = [NSScanner scannerWithString:parameterString];

    NSString *name = [NSString string];
    [parameterScanner scanUpToString:isEqual intoString:&name];

    NSString *value = [parameterString substringFromIndex:([name length] + 1)];
    [parameters setObject:value forKey:name];
}
于 2012-01-20T10:21:52.527 に答える