目标c:在线程期间将对象添加到NSMutableArray时出错

时间:2013-05-16 03:12:58

标签: objective-c cocoa nsmutablearray nsfilemanager nsthread

这是我想要实现的目标。 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个文件后,它开始给我错误并在结束时崩溃)。

  5. 这是正确的元素添加到数组中:

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

    以下是错误消息:

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

    但是,即使发生此错误,它仍然会将某些路径保存到数组中,然后会引发另一个错误:

        An uncaught exception was raised
    

    你们能告诉我如何解决它吗?谢谢!!

2 个答案:

答案 0 :(得分:1)

首先,尝试通过随机生成线程来提高性能可以保证失败。必须考虑并控制并发。

其次,尝试通过同时无限制地访问所述资源来减少访问慢速资源(如文件系统)的代码的执行时间将比序列化访问慢。文件系统的I / O相对较慢,线性I / O总是比并发,冲突,随机I / O快。

最后,NSMutableDictionary不是线程安全的。其他可变集合类也不是。如果你把东西推到多个线程的集合中,你会看到未定义的行为(通常是崩溃)。

答案 1 :(得分: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指出的那样,在你的例子中看到的目录枚举不是一个很适合并行化的问题 - 在这种情况下并行化会受到伤害。更实际的方法是从一个线程枚举。如果你想立即加载一些图像,只需从“I / O线程”加载它们。