将 SQLite 从一个地方移动到另一个地方:应用程序崩溃和不兼容的类型
Posted
技术标签:
【中文标题】将 SQLite 从一个地方移动到另一个地方:应用程序崩溃和不兼容的类型【英文标题】:Moving SQLite from one place to another: app crash and incompatible type 【发布时间】:2011-02-03 19:12:40 【问题描述】:我开始学习 Objective-C 并帮助我这样做,我正在使用“Head First iPhone Development”。现在我正在学习 SQLite 数据库并让这些数据库正常工作,我被告知 SQLite 文件需要位于应用程序的 Documents 文件夹中,因此我必须移动该文件。
我正在使用书中的示例,但似乎无法使其正常工作。每次我编译它时,我的应用程序都会崩溃。我有以下警告:“初始化'struct NSURL *'的不兼容的Objective-C类型,预期'struct NSString *'
有没有人知道如何解决这个问题?
编辑:
问题似乎出在这两行中,applicationDocumentsDirectory 返回一个 NSURL,但我告诉它返回一个 NSString。我可以告诉它返回一个 NSURL,但这在我使用 stringByAppendingPathComponent 的下一行给我带来了问题。有没有办法解决这个问题?
NSString *documentsDirectory = [self applicationDocumentsDirectory];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:@"iBountyHunter.sqlite"];
这是应用程序崩溃时调试器控制台输出的内容:
2011-02-04 07:33:42.126 iBountyHunter[591:207] -[NSURL stringByAppendingPathComponent:]: unrecognized selector sent to instance 0x6043f80
2011-02-04 07:33:42.128 iBountyHunter[591:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSURL stringByAppendingPathComponent:]: unrecognized selector sent to instance 0x6043f80'
*** Call stack at first throw:
(
0 CoreFoundation 0x00f87be9 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x010dc5c2 objc_exception_throw + 47
2 CoreFoundation 0x00f896fb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x00ef9366 ___forwarding___ + 966
4 CoreFoundation 0x00ef8f22 _CF_forwarding_prep_0 + 50
5 iBountyHunter 0x00001d8e -[iBountyHunterAppDelegate createEditableCopyOfDatabaseIfNeeded] + 107
6 iBountyHunter 0x00001f24 -[iBountyHunterAppDelegate application:didFinishLaunchingWithOptions:] + 37
7 UIKit 0x002ba1fa -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1163
8 UIKit 0x002bc55e -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 439
9 UIKit 0x002c6db2 -[UIApplication handleEvent:withNewEvent:] + 1533
10 UIKit 0x002bf202 -[UIApplication sendEvent:] + 71
11 UIKit 0x002c4732 _UIApplicationHandleEvent + 7576
12 GraphicsServices 0x018bda36 PurpleEventCallback + 1550
13 CoreFoundation 0x00f69064 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 52
14 CoreFoundation 0x00ec96f7 __CFRunLoopDoSource1 + 215
15 CoreFoundation 0x00ec6983 __CFRunLoopRun + 979
16 CoreFoundation 0x00ec6240 CFRunLoopRunSpecific + 208
17 CoreFoundation 0x00ec6161 CFRunLoopRunInMode + 97
18 UIKit 0x002bbfa8 -[UIApplication _run] + 636
19 UIKit 0x002c842e UIApplicationMain + 1160
20 iBountyHunter 0x00001cf8 main + 102
21 iBountyHunter 0x00001c89 start + 53
)
terminate called after throwing an instance of 'NSException'
【问题讨论】:
【参考方案1】:我正在使用书中的示例 但我似乎无法让它工作。 每次我编译它时,我的应用程序都会崩溃。 我有以下警告: “不兼容的 Objective-C 类型 初始化'struct NSURL *', 预期'struct NSString *'
修复警告;您正在将 NSURL 实例分配给需要 NSString 实例的东西。
或者发布导致它的警告和代码行。
如果您的应用崩溃,请发布崩溃。
问题似乎出在这两个 与 申请文件目录 返回一个 NSURL 但我告诉它 返回一个 NSString。我可以告诉它 返回一个 NSURL 但这给了我一个 我使用的下一行的问题 stringByAppendingPathComponent。是 有办法解决这个问题吗?
您不能告诉返回 NSURL 的方法改为返回 NSString。类型转换返回值和如下赋值都不起作用:
NSString *documentsDirectory = [self applicationDocumentsDirectory];
编译器在该行发出警告,因为它已损坏;你不能像对待 NSString 一样对待 NSURL。
类似下面的东西应该可以工作:
NSString *documentsDirectory = [[self applicationDocumentsDirectory] path];
【讨论】:
当然可以。 NSURL 和 NSString 不可互换。编辑您的问题以显示编译错误出现在哪里。 我已更新问题以在调试器控制台中显示输出。【参考方案2】:如果应用程序仍然无法在您的模拟器中运行,请记住从您的模拟器中删除该应用程序,然后再次构建并运行该应用程序。
您从模拟器中删除应用程序的方式与使用真实设备相同。
【讨论】:
【参考方案3】:这样就可以了。
// Check the existence of database
NSFileManager *mngr = [[NSFileManager alloc] init];
// If the database doesn't exist in our Document folder we copy it to Documents (this will be executed only the first time we launch the app).
if (![mngr fileExistsAtPath:[NSString stringWithFormat:@"%@/Documents/db.sqlite", NSHomeDirectory()]])
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"db.sqlite" ofType:nil];
[mngr copyItemAtPath:filePath toPath:[NSString stringWithFormat:@"%@/Documents/db.sqlite", NSHomeDirectory()] error:NULL];
[mngr release];
这是 applicationDocumentsDirectory 方法的另一个版本:
+ (NSString*)applicationDocumentsDirectory
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return documentsDirectory;
【讨论】:
我尝试了您的第一个代码,但无法使其正常工作。它认为该文件已经存在,因此它没有被移动,但我的 TableView 中没有显示任何数据。如何实现其他版本的 applicationDocumentsDirectory 方法? 代码在我的应用程序中有效。执行 nslog 以查看数据库中的实际内容。要使用其他版本,只需找到 applicationDocumentsDirectory 声明并将方法签名更改为 ` + (NSSString *), and copy code into your implementation file. If you want to still call it on self you'll have to change the + to a - so that it's an instance method instead of a class method but theres no reason not to change it to
[iBountyHunterAppDelegate applicationDocumentsDirectory] `
我猜由于您不熟悉objective-c 的基础知识,您可能有一些内存管理问题导致表格视图不显示任何内容。一个关于表格视图的好资源在这里:code.google.com/p/iphone4/downloads/list 这是一本非常好的书的源代码,叫做“高级 ios 4 编程”。如果您在“Head First iPhone Development”方面遇到问题,您可能会考虑购买另一本书。另一个很好的表格视图是“更多 iPhone 3 开发:处理 iPhone SDK”(虽然有点密集)。【参考方案4】:
我收到以下警告:“不兼容的 Objective-C 类型正在初始化 'struct NSURL *',预期为 'struct NSString *'
问题是你正在调用苹果提供的 applicationDocumentsDirectory 方法,该方法返回一个 NSURL。
【讨论】:
是否可以让它返回一个 NSString 或使用带有 NSURL 的 stringByAppendingPathComponent?以上是关于将 SQLite 从一个地方移动到另一个地方:应用程序崩溃和不兼容的类型的主要内容,如果未能解决你的问题,请参考以下文章
使用Objective-c中的进度条将文件从一个地方复制到另一个地方[重复]