4

I need to copy a few sample files from my app's resource folder and place them in my app's document folder. I came up with the attached code, it compiles fine but it doesn't work. All the directories I refer to do exist. I'm not quite sure what I am doing wrong, could someone point me in the right direction please?

NSFileManager*manager = [NSFileManager defaultManager];

NSString*dirToCopyTo = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents"];

NSString*path = [[NSBundle mainBundle] resourcePath];

NSString*dirToCopyFrom = [path stringByAppendingPathComponent:@"Samples"];


NSError*error;

NSArray*files = [manager contentsOfDirectoryAtPath:dirToCopyFrom error:nil];

for (NSString *file in files)
{
        [manager copyItemAtPath:[dirToCopyFrom stringByAppendingPathComponent:file] toPath:dirToCopyTo error:&error];

        if (error)
        {
            NSLog(@"%@",[error localizedDescription]);
    }
}

EDIT: I just edited the code the way it should be. Now however there's another problem:

2010-05-15 13:31:31.787 WriteIt Mobile[4587:207] DAMutableDictionary.h 2010-05-15 13:31:31.795 WriteIt Mobile[4587:207] FileManager Error:Operation could not be completed. File exists

EDIT : I have fixed the issue by telling NSFileManager the names of the copied files's destinations.

        [manager copyItemAtPath:[dirToCopyFrom stringByAppendingPathComponent:file] toPath:[dirToCopyTo stringByAppendingPathComponent:file] error:&error];
Pripyat
  • 2,937
  • 2
  • 35
  • 69
  • Don't suppress error returns (`contentsOfDirectoryAtPath:error:`). Also, for `copyItemAtPath:toPath:error:`, test whether the method failed before attempting to use the error object; see http://rentzsch.tumblr.com/post/260201639/nserror-is-hard . – Peter Hosey May 15 '10 at 19:48

4 Answers4

5

I think the problem is in this line:

NSArray*files = [manager contentsOfDirectoryAtPath:dirToCopyTo error:nil];

You are listing files in a destination directory instead of the source. Change it to something like:

NSArray*files = [manager contentsOfDirectoryAtPath:dirToCopyFrom error:nil];

And you should be fine.

Eimantas
  • 48,927
  • 17
  • 132
  • 168
  • thanks! this was indeed the problem. now i've hit another one though - this is my log output: 2010-05-15 13:31:31.787 WriteIt Mobile[4587:207] DAMutableDictionary.h 2010-05-15 13:31:31.795 WriteIt Mobile[4587:207] FileManager Error:Operation could not be completed. File exists 2010-05-15 13:31:31.795 WriteIt Mobile[4587:207] DAMutableDictionary.m 2010-05-15 13:31:31.802 WriteIt Mobile[4587:207] FileManager Error:Operation could not be completed. File exists etc... etc.... what does that mean exactly? – Pripyat May 15 '10 at 12:33
  • Seems that you're trying to overwrite a file. Before copying - make sure it does not exist. – Eimantas May 15 '10 at 14:06
  • but the Documents directory is empty? which is why I am surprised? – Pripyat May 15 '10 at 14:17
  • even after resetting the iPhone Simulator, it still says the same. – Pripyat May 15 '10 at 14:40
2

I think the problem is that yo are reading the files to copy from dirToCopyTo and I think you meant dirToCopyFrom

Also to get the documents directory you should be using NSDocumentDirectory with - (NSArray *)URLsForDirectory:(NSSearchPathDirectory)directory inDomains:(NSSearchPathDomainMask)domainMask

mmmmmm
  • 32,227
  • 27
  • 88
  • 117
  • it doesn't really matter since both return the same result ;) – Pripyat May 15 '10 at 12:33
  • In a non English version of OSX is the directory always Documents? – mmmmmm May 15 '10 at 15:02
  • yes marc, my iPhone is set to german and all documents directories are still called "Documents". – Pripyat May 15 '10 at 15:18
  • Mark: That method doesn't exist on the iPhone. The only way in an iPhone app (aside from forging the path from whole cloth) is the `NSSearchPathForDirectoriesInDomains` function: http://developer.apple.com/iphone/library/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html#//apple_ref/c/func/NSSearchPathForDirectoriesInDomains – Peter Hosey May 15 '10 at 19:56
2

Please note that lengthy operation on startup must be avoided:

  1. Not a good User Experience (delay and croppy behavior)
  2. Watchdog in iOS can kill your app as if it were stuck.

So perform copy in a secondary thread (or operation... or whatever uses a different execution path).

Another problem will arise if You need data to populate your UI: in that case:

  • Disable UI elements
  • Start an async / threaded operation
  • In the completion call back of copying (via a notification, a protocol.. or other means) notify to the UI interface it can start fetching data.

For example we copy a ZIP file and decompress it, but it takes some time so we had to put it in a timer procedure that will trigger UI when done.

If You need an example, ket me know.

PS:
Copying using ZIP file is MORE efficient as:

  1. Only call to file system
  2. Far less bytes to copy

The bad news: you must use a routine do decompress zip file, but you can find them on the web.

Decompressing Zip files should be more efficient as these calls are written in straight C, and not in Cocoa with all the overhead.

Shadow The GPT Wizard
  • 66,030
  • 26
  • 140
  • 208
ingconti
  • 10,876
  • 3
  • 61
  • 48
1
    [manager copyItemAtPath:[dirToCopyFrom stringByAppendingPathComponent:file] toPath:dirToCopyTo error:&error];

The destination path is the path you want the copy to have, including its filename. You cannot pass the path to a directory expecting NSFileManager to fill in the name of the source file; it will not do this.

The documentation says that the destination path must not describe anything that exists:

… dstPath must not exist prior to the operation.

In your case, it's the path to the destination directory, so it does exist, which is why the copy fails.

You need to make it a path to the destination file by appending the desired filename to it. Then it will not exist (if not previously copied), so the copy will succeed.

Peter Hosey
  • 95,783
  • 15
  • 211
  • 370