0

これが私が達成したいことです。1. すべてのファイルを検索する 2. 検索中にすべての .jpg ファイルを見つける 3. すべての .jpg ファイル パスを NSMutableArray に保存する

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

  1. NSMutableArray を作成しました:

    NSMutableArray *jpgFiles = [[[NSMutableArray alloc]init]autorelease]; 
    
  2. (/Users/) パスの下にあるすべての親フォルダーを検索します (ここで NSThread を開始します)。

    NSString* filePath = [url path];
    NSArray *dirFiles = [[NSFileManager defaultManager]contentsOfDirectoryAtPath:filePath error:nil];
    
    if([dirFiles count]!=0)
    {
       for (int j=0; j<[dirFiles count]; j++) {
    
        NSString* pathExtension = [[dirFiles objectAtIndex:j] pathExtension];
    
        //if extension is null, we forwards to next level.
        if ([pathExtension isEqualTo:@""])
        {
            @autoreleasepool {
                [NSThread detachNewThreadSelector:@selector(searchingPicture:) toTarget:self withObject:[filePath stringByAppendingPathComponent:[dirFiles objectAtIndex:j]]];
            }
        }
        else
        {
            //if find jpg in this level, save into array
            if([pathExtension isEqualTo:@"JPG"])
            {
                [jpgFiles addObject:[filePath stringByAppendingPathComponent:[dirFiles objectAtIndex:j]]];
            }
        }
      }
    }  
    
  3. 残りのサブフォルダーを検索し続け、適切なファイル パスを配列に保存します。

    -(void)searchingPicture:(NSString*)path
     {
       NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
    
       NSURL *directoryURL = [NSURL URLWithString:[path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
    
       NSArray *keys = [NSArray arrayWithObject:NSURLIsDirectoryKey];
    
       NSDirectoryEnumerator *enumerator = [fileManager
                                     enumeratorAtURL:directoryURL
                                     includingPropertiesForKeys:keys
                                     options:0
                                     errorHandler:^(NSURL *url, NSError *error) {
                                         // Handle the error.
                                         // Return YES if the enumeration should continue after the error.
                                         return YES;
                                     }];
    
      for (NSURL *url in enumerator) {
          NSError *error;
          NSNumber *isDirectory = nil;
          if (! [url getResourceValue:&isDirectory forKey:NSURLIsDirectoryKey error:&error]) {
               // handle error
           }
           else if (! [isDirectory boolValue]) {
              // No error and it’s not a directory; do something with the file
              if([[[url path] pathExtension]isEqualTo:@"JPG"])
              {
                  //This line gives me error !!!
                  [jpgFiles addObject:[url path]];
              }
           }
        }    
     }
    
  4. エラー: (最初は問題なく動作し、多くの異なるファイルを配列に保存しますが、約 50 個のファイルを保存した後、エラーが発生し始め、最後にクラッシュします)。

配列に追加される正しい要素は次のとおりです。

    /Users/NAME/Documents/Graduate Books/IMG_2517.JPG

エラーメッセージは次のとおりです。

    -[NSPathStore2 addObject:]: unrecognized selector sent to instance 0x10011d4d0

ただし、このエラーが発生しても、一部のパスを配列に保存し続け、別のエラーをスローします。

    An uncaught exception was raised

直し方教えていただけないでしょうか??ありがとう !!

4

2 に答える 2

1

まず、スレッドをランダムに生成してパフォーマンスを向上させようとすると、確実に失敗します。並行性を考慮して制御する必要があります。

第 2 に、遅いリソース (ファイルシステムなど) にアクセスしているコードの実行時間を制限なしでリソースに同時にアクセスすることで、そのコードの実行時間を短縮しようとすると、シリアル化されたアクセスよりも遅くなります。ファイルシステムへの I/O は比較的遅く、線形 I/O は常に同時実行の競合するランダム I/O よりも高速です。

最後に、NSMutableDictionaryスレッドセーフではありません。他のミュータブル コレクション クラスもそうではありません。複数のスレッドからコレクションに何かを押し込むと、未定義の動作 (通常はクラッシュ) が発生します。

于 2013-05-16T05:39:51.583 に答える
0

NSMutableArrayスレッドセーフではありません。正しくガードすると、スレッドセーフになります。そのため、いつでも複数のスレッドが使用することはできません。

説明する:

- (void)addPath:(NSString *)pPath
{
  [self.lock lock];
  [self.files addObject:pPath];
  [self.lock unlock];
}

- (NSUInteger)countPaths
{
  [self.lock lock];
  const NSUInteger count = self.files.count;
  [self.lock unlock];
  return count;
}

- (NSArray *)copyPaths
{
  [self.lock lock];
  NSArray * paths = [self.files copy];
  [self.lock unlock];
  return paths;
}

そして bbum が指摘したように、あなたの例に見られるディレクトリの列挙は、並列化に適した問題ではありません。このシナリオでは、並列化が問題になります。より実用的なアプローチは、1 つのスレッドから列挙することです。一部の画像をすぐにロードしたい場合は、「I/O スレッド」からもロードしてください。

于 2013-05-16T06:38:15.963 に答える