Reputation: 888
Here is what I want to achieve. 1. Searching all the files 2. find all .jpg files during the searching 3. save all .jpg file paths into NSMutableArray
Here are the codes:
Created the NSMutableArray:
NSMutableArray *jpgFiles = [[[NSMutableArray alloc]init]autorelease];
Searching all the parent folders under (/Users/) path (Start NSThread in here):
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]]];
}
}
}
}
Keep searching the rest of sub folders and save proper file path into array:
-(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]];
}
}
}
}
Error: (At beginning, it works fine and save many different files into array, but after saved around 50 files it starts to give me error and crash at the end).
Here is the correct element adds into array:
/Users/NAME/Documents/Graduate Books/IMG_2517.JPG
Here is the error message:
-[NSPathStore2 addObject:]: unrecognized selector sent to instance 0x10011d4d0
However, even this error occurs, it still keeps saving some of paths into array and then it will throw another error:
An uncaught exception was raised
Could you guys tell me how to fix it?? Thanks !!
Upvotes: 0
Views: 269
Reputation: 104698
NSMutableArray
is not thread safe. It is thread safe when you guard it correctly -- so that no more than one thread is able to use it any time.
To illustrate:
- (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;
}
And as bbum pointed out, directory enumeration as seen in your example is not a problem which lends itself well to parallelization -- Parallelization hurts in this scenario. A more practical approach would be to enumerate from just one thread. If you want to immediately load some of the images, just load them from the "I/O thread" as well.
Upvotes: 0
Reputation: 162712
First, trying to increase performance by randomly spawning threads is guaranteed failure. Concurrency must be considered and controlled.
Secondly, trying to decrease execution time of code that is accessing a slow resource (like the filesystem) by concurrently accessing said resource without constraint will be slower than serialized access. I/O to filesystems is relatively slow and linear I/O is always faster than concurrent, conflicted, random I/O.
Finally, NSMutableDictionary
is not thread safe. Nor are the other mutable collection classes. If you are shoving stuff into collections from multiple threads, you'll see undefined behavior (typically crashes).
Upvotes: 2