最初の起動時に、メインバンドルの「Populator」フォルダにある一連のファイルがdocumentsディレクトリにコピーされるようにアプリケーションを設定しようとしています。
私の現在の実装は次のとおりです。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *sourcePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"Populator"];
NSString *folderPath = [documentsDirectory stringByAppendingPathComponent:@"Files"];
NSLog(@"Source Path: %@\n Documents Path: %@ \n Folder Path: %@", sourcePath, documentsDirectory, folderPath);
NSError *error;
[[NSFileManager defaultManager] copyItemAtPath:sourcePath
toPath:folderPath
error:&error];
NSLog(@"Error description-%@ \n", [error localizedDescription]);
NSLog(@"Error reason-%@", [error localizedFailureReason]);
....
return YES;
}
ただし、これは、次のコンソールメッセージで初めて実行されたときにクラッシュします(ただし、ファイルはコピーされます)。次回アプリを開いたときにクラッシュすることはありません。
2010-07-13 15:14:26.418 AppName[5201:207] Source Path: /Users/jack/Library/Application Support/iPhone Simulator/3.2/Applications/1076C1FA-60B0-4AC7-8CD4-74F81472DAE6/AppName.app/Populator
Documents Path: /Users/jack/Library/Application Support/iPhone Simulator/3.2/Applications/1076C1FA-60B0-4AC7-8CD4-74F81472DAE6/Documents
Folder Path: /Users/jack/Library/Application Support/iPhone Simulator/3.2/Applications/1076C1FA-60B0-4AC7-8CD4-74F81472DAE6/Documents/Files
2010-07-13 15:14:26.466 AppName[5201:207] *** +[AppNameAppDelegate localizedDescription]: unrecognized selector sent to class 0xa79c
2010-07-13 15:14:26.475 AppName[5201:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** +[AppNameAppDelegate localizedDescription]: unrecognized selector sent to class 0xa79c'
2010-07-13 15:14:26.495 AppName[5201:207] Stack: (
40911435,
2569270537,
41183227,
40645910,
40642578,
9142,
2815466,
2819475,
2844680,
2826401,
2858055,
49271164,
40452156,
40448072,
2817668,
2850273,
8776,
8630
)
何が悪いのかについて誰かが何か提案がありますか? 「初回起動時のみ」の機能を実装するためのコードをすでに設定していますが、わかりやすくするためにここには含めていません。
ありがとう
IPhoneプログラミングやObjectiveCについてはよくわかりませんが、好奇心から、コピー操作が実際に成功した場合のエラーは何ですか?エラーがなかった場合にクラッシュしているのはログ行でしょうか?
[編集]また、そのようなサブディレクトリの内容全体をコピーすることは許可されていますか? (繰り返しになりますが、私はiOS APIに慣れておらず、他の言語/ APIについて知っていることに基づいて、考えられるエラーの原因を特定しているだけです)
NSError *error;
ローカル変数を初期化せずに宣言しています。そのため、ゴミでいっぱいになります。
[[NSFileManager defaultManager] copyItemAtPath:sourcePath
toPath:folderPath
error:&error];
この行でエラーが発生しなかった場合でも、error
のガベージステータスは残ります。
NSLog(@"Error description-%@ \n", [error localizedDescription]);
ここで、ランダムな初期化されていない場所にメッセージを送信します。これがクラッシュの原因です。
これを回避するには、error
をnil
に初期化します。
NSError* error = nil;
// ^^^^^
または、-copyItemAtPath:…
がNO(error
が正しく入力されている)を返した場合にのみエラーを出力します。
if (![[NSFileManager defaultManager] copyItemAtPath:sourcePath ...]) {
NSLog(...);
}
コードを読んだところ、問題が見つかりました。ショーン・エドワーズが上で指摘したように、成功してもエラーはありません。したがって、クラッシュします。
興味のある人のための私の新しいコードは次のとおりです。
if([[NSFileManager defaultManager] copyItemAtPath:sourcePath toPath:folderPath error:&error]){
NSLog(@"File successfully copied");
} else {
NSLog(@"Error description-%@ \n", [error localizedDescription]);
NSLog(@"Error reason-%@", [error localizedFailureReason]);
}
ファイルがすでに存在するかどうかを確認する必要があります。次にコピーします。
+ (BOOL) getFileExistence: (NSString *) filename
{
BOOL IsFileExists = NO;
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
NSString *favsFilePath = [documentsDir stringByAppendingPathComponent:filename];
NSFileManager *fileManager = [NSFileManager defaultManager];
// Check if the database has already been created in the users filesystem
if ([fileManager fileExistsAtPath:favsFilePath])
{
IsFileExists = YES;
}
return IsFileExists;
}
+ (NSString *)dataFilePath:(NSString *)filename {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDirectory = [paths objectAtIndex:0];
return [docDirectory stringByAppendingPathComponent:filename];
}
- (void)copyFileToLocal:(NSString *)filename
{
if (![AppDelegate getFileExistence:filename])
{
NSError *error;
NSString *file = [[NSBundle mainBundle] pathForResource:filename ofType:nil];
if (file)
{
if([[NSFileManager defaultManager] copyItemAtPath:file toPath:[AppDelegate dataFilePath:filename] error:&error]){
NSLog(@"File successfully copied");
} else {
[[[UIAlertView alloc]initWithTitle:NSLocalizedString(@"error", nil) message: NSLocalizedString(@"failedcopydb", nil) delegate:nil cancelButtonTitle:NSLocalizedString(@"ok", nil) otherButtonTitles:nil] show];
NSLog(@"Error description-%@ \n", [error localizedDescription]);
NSLog(@"Error reason-%@", [error localizedFailureReason]);
}
file = nil;
}
}
}
NSLocalizedString
は、アプリケーションのローカライズ文字列です。
エラーがあることを知る前にエラーをログに記録します
コードをifブロックに入れます
if(error)
{
NSLog(@"Error description-%@ \n", [error localizedDescription]);
NSLog(@"Error reason-%@", [error localizedFailureReason]);
}
問題をより詳細に説明すると、エラーのポインタはどこにでもあり、そのオブジェクトはそのメッセージを認識しません。したがって、例外が発生します
一般的なプログラミング手法として、変数をデフォルト値で初期化するのが常に最善です。
NSError *error = nil;
Objective-Cでは、nil
にメッセージを送信することが有効です。したがって、あなたの場合、エラー変数はnil
に初期化されていればクラッシュを引き起こしません。
件名チェックの詳細についてはSending Messages to nil
セクション https://developer.Apple.com/library/ios/#documentation/cocoa/conceptual/objectivec/Chapters/ocObjectsClasses.html