我正在尝试设置我的应用程序,以便在首次启动时,位于主包中“Populator”文件夹中的一系列文件被复制到文档目录中。
我目前的实施如下:
- (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
)
有没有人对出了什么问题有任何建议?我已经设置了一些代码来实现“仅在首次启动时”功能,但为了清楚起见,未将其包含在此处。
由于
答案 0 :(得分:15)
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(...);
}
答案 1 :(得分:5)
我只是阅读了我的代码并发现了问题。正如肖恩·爱德华兹(Sean Edwards)所指出的那样,如果成功就没有错误 - 因此崩溃了。
以下是我感兴趣的新代码:
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]);
}
答案 2 :(得分:4)
我对iPhone编程或目标C了解不多,但出于好奇,如果复制操作实际成功,那么错误是什么?如果没有错误,它可能是崩溃的日志行吗?
[edit]另外,你是否允许复制像这样的子目录的全部内容? (再一次,我不熟悉iOS API,根据我所知道的其他语言/ API识别可能的错误来源)
答案 3 :(得分:4)
你应该检查文件是否已经存在!然后复制。
+ (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
是本地化应用程序的字符串。
答案 4 :(得分:2)
您在知道错误之前记录错误
将代码放入if-block
if(error)
{
NSLog(@"Error description-%@ \n", [error localizedDescription]);
NSLog(@"Error reason-%@", [error localizedFailureReason]);
}
更详细地描述您的问题:错误指针指向ANYWHERE并且该对象无法识别该消息。因此你得到一个例外
答案 5 :(得分:1)
作为一般编程实践,最好使用默认值初始化变量:
NSError *error = nil;
在Objective-C中,向nil
发送消息是有效的。因此,在您的情况下,如果错误变量初始化为nil
,则不会导致崩溃。
Sending Messages to nil
部分