0

ループ プロセス中に、アプリがエラーなしでクラッシュします。配列数は 175260 です。プロファイラーではリークがないため、アプリが終了する理由がわかりません。CPU 使用率が長時間 100% になる可能性があります。

ご協力ありがとうございました。

次のコードだけで App がクラッシュします。

    for(unsigned int i = 0; i <14;i++)
    {
        if(findSensor[i]==YES)
        {
            for(unsigned int j = 1; j <[array count];j++)
            {
                @autoreleasepool {

                    if([[[[array objectAtIndex:j] componentsSeparatedByString:@";"] objectAtIndex:0] isEqualToString:[NSString stringWithFormat:@"%d",10*(i+1)]])
                    {
                        //Code here 
                    }
                }
            }
        }
    }

完全なコードは次のとおりです。

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *fileName = [NSString stringWithFormat:@"%@/%@",documentsDirectory,[ibNavSettings interfaceSettings].selectedFileToDataBase];

NSFileHandle *fh = [NSFileHandle fileHandleForReadingAtPath:fileName];

NSFileHandle *output = [NSFileHandle fileHandleForReadingAtPath:[NSString stringWithFormat:@"%@/%@10",documentsDirectory,[ibNavSettings interfaceSettings].selectedFileToDataBase]];

if(output == nil)
{

    NSManagedObjectContext *context = [self managedObjectContext];
    _recordlocal = [NSEntityDescription insertNewObjectForEntityForName:@"RECORD" inManagedObjectContext:context];
    _recordlocal.date = [ibNavSettings interfaceSettings].selectedFileToDataBase;

    NSData *inputData = [NSData dataWithData:[fh readDataToEndOfFile]];

    NSString *inputString = [[NSString alloc] initWithData:inputData encoding:NSUTF8StringEncoding];

    NSArray *array = [[NSArray alloc] initWithArray:[inputString componentsSeparatedByString:@"\n"]];


    for(unsigned int i = 0; i <14;i++)
    {
        if(findSensor[i]==YES)
        {
            [[NSFileManager defaultManager] createFileAtPath:[NSString stringWithFormat:@"%@/%@%d",documentsDirectory,[ibNavSettings interfaceSettings].selectedFileToDataBase,10*(i+1)] contents:nil attributes:nil];

            NSMutableString *saveString = [[NSMutableString alloc] init];

            int count = 0;

            for(unsigned int j = 1; j <[array count];j++)
            {
                @autoreleasepool {

                    if([[[[array objectAtIndex:j] componentsSeparatedByString:@";"] objectAtIndex:0] isEqualToString:[NSString stringWithFormat:@"%d",10*(i+1)]])
                    {
                        [saveString appendString:[array objectAtIndex:j]];
                        [saveString appendString:@"\n"];
                        if(i == 0)
                            count++;
                        progress++;
                        pourcent = progress/total;
                        load = pourcent*100;
                        if(load%5==0)
                            [self performSelectorInBackground:@selector(changeUI:)withObject:[NSNumber numberWithFloat:(pourcent)]];


                    }
                }
            }

            [saveString writeToFile:[NSString stringWithFormat:@"%@/%@%d",documentsDirectory,[ibNavSettings interfaceSettings].selectedFileToDataBase,10*(i+1)] atomically:YES encoding:NSUTF8StringEncoding error:nil];
            if(i == 0)
                _recordlocal.count = [[NSNumber alloc] initWithInt:(count/50)];
        }

    }

    _recordlocal.load = [[NSNumber alloc] initWithBool:YES];

    NSError *error = nil;
    if (![context save:&error]) {
        NSLog(@"Core data error %@, %@", error, [error userInfo]);
        abort();
    }
4

3 に答える 3

2

特に、多数の反復を実行していることを示しているため、使用可能な RAM が不足しているため、アプリは読み取り可能な例外なしでクラッシュしていると思います。

テストのために、自動解放プールで Rikkles が提案していることを実行することをお勧めします。さらに、i の値 (および結果として比較文字列) がほとんど変更されないため、その文字列も j ループの外に作成します。これにより、多くの余分な文字列が作成されるのを回避できます。

さらに、セミコロンで区切られた文字列の先頭にある文字列を探しているように見えるので、componentsSeparatedByString を実行して要素ゼロを調べる代わりに、NSString メソッド hasPrefix を使用して条件を確認することをお勧めします。あなたは探している。

次に例を示します。

for(unsigned int i = 0; i <14;i++)
{
    NSString *searchString = [NSString stringWithFormat:@"%d;", 10*(i+1)];
    if(findSensor[i]==YES)
    {
        for(unsigned int j = 1; j <[array count];j++)
        {
            if([[array objectAtIndex:j] hasPrefix:searchString])
            {
                //Code here 
            }
        }
    }
}

(これがコンパイルされて実行されることを願っています。そうでない場合は、マイナーな調整以上のものが必要になるはずです。私は今、Mac から離れています。)

これで問題が解決しない場合は、 //Code here 内で何かが起こっていることが原因であるに違いありません。

于 2013-03-01T18:31:46.380 に答える
1

なぜ[array count]autoreleasepools を作成するのですか? それらの多くを作成するポイントは何ですか?それが原因でクラッシュする可能性があります。@autoreleasepoolfor ループの外側に置きます。そうするだろうと私が考える唯一の理由は、for ループの各反復内に非常に多くの一時的なオブジェクトを作成し、反復から抜けたらすぐにそれらを取り除きたい場合です。ただし、各反復内でそれらのオブジェクトを再利用するなど、他の方法もあります。

于 2013-03-01T18:18:18.050 に答える
0

最初の提案

内側のループに高速列挙を使用するだけで、実際にはインデックス「j」を何にも使用していません

https://developer.apple.com/library/mac/documentation/General/Conceptual/DevPedia-CocoaCore/Enumeration.html

2番目の提案

いくつかの NSLog を配置すると、すべてが遅くなりますが、どの時点で失敗しているかを把握する必要があります。それは、全員を正しい方向に向けるのに役立ちます。

3番目の提案

実際に NSError オブジェクトを使用し、エラーがスローされた場合はその値を出力します。

NSError *writeError = nil;
[saveString writeToFile:[NSString stringWithFormat:@"%@/%@%d",documentsDirectory,[ibNavSettings interfaceSettings].selectedFileToDataBase,10*(i+1)] 
             atomically:YES 
               encoding:NSUTF8StringEncoding 
                  error:&writeError];
if(error != nil) NSLog(@"error writing file: %@", [[writeError userInfo]description]);

4番目の提案

バックグラウンド スレッドから UI を更新しようとしているようです。これは機能しないか、クラッシュを引き起こします。UI コードは、メイン スレッドからのみ呼び出すことができます。だからこれをしないでください:

[self performSelectorInBackground:@selector(changeUI:)withObject:[NSNumber numberWithFloat:(pourcent)]];

すでにバックグラウンド スレッドを使用している場合、スレッド上のスレッドにスレッドを作成しているため、おそらくクラッシュします。代わりに次のように呼び出します。

[self performSelectorOnMainThread:@selector(changeUI:)withObject:[NSNumber numberWithFloat:(pourcent)]];

5番目の提案

NSString の最大長を超えている可能性があります (これは大きいですが、以前に偶然に一度やったことがあります)。おそらく、代わりにループの各反復でファイルを追加するだけでよいので、NSMutableString が増え続けることはありません。

NSString *path = [NSString stringWithFormat:@"%@/%@%d",documentsDirectory,[ibNavSettings interfaceSettings].selectedFileToDataBase,10*(i+1)]
NSFileHandle *fh  = [NSFileHandle fileHandleForWritingAtPath:filePath];

NSData *newLine = [@"\n" dataUsingEncoding:NSUTF8StringEncoding];
for(NSString *rowString in array)
{
    if([[[rowString componentsSeparatedByString:@";"] objectAtIndex:0] isEqualToString:[NSString stringWithFormat:@"%d",10*(i+1)]])
    {
        NSData *stringData = [rowString dataUsingEncoding:NSUTF8StringEncoding];
        [fh truncateFileAtOffset:[fh seekToEndOfFile]];
        [fh writeData:stringData];
        [fh truncateFileAtOffset:[fh seekToEndOfFile]];
        [fh writeData:newLine];
        if(i == 0)
            count++;
        progress++;
        pourcent = progress/total;
        load = pourcent*100;
        if(load%5==0)
            [self performSelectorOnMainThread:@selector(changeUI:)withObject:[NSNumber numberWithFloat:(pourcent)]];


        }
    }
}

これには、自動リリースプールを捨てるのに役立つという追加の利点があります

これは無効でした

配列に実際に 175260 行がある場合、それがおそらく問題です。unsigned int をインデックス var として使用してループしています。c の符号なし int の最大値は 65535 のみです。最大 4294967295 の unsigned long int を使用してください。

于 2013-03-01T18:34:01.593 に答える