由于 sqlite 执行事务的方式(使用 wal 或日志文件),我在将我的 sqlite 代码移植到 App Store 时遇到了很多麻烦。Apple文档的相关部分是:
您的应用需要能够打开或保存多个具有相同名称和不同扩展名的相关文件(例如,自动打开与电影文件同名的字幕文件,或允许 SQLite 日志文件)。要访问该辅助文件,请创建一个符合 NSFilePresenter 协议的类。该对象应提供主文件的 URL 作为其 primaryPresentedItemURL 属性,并应提供辅助文件的 URL 作为其presentedItemURL 属性。用户打开主文件后,你的文件展示器对象应该调用 NSFileCoordinator 类的 addFilePresenter: 类方法来注册自己。
Apple DTS 为我提供了以下代码:
- (void)openSQLiteFileAtURL:(NSURL *)fileURL {
NSFileCoordinator *fc = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[fc coordinateReadingItemAtURL:fileURL options:0 error:NULL byAccessor:^(NSURL *newURL) {
sqlite3 *db = NULL;
char *zErrMsg = 0;
[SQLiteRelatedItemPresenter addPresentersForURL:newURL];
int rc = sqlite3_open_v2([[newURL path] fileSystemRepresentation], &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
NSLog(@"open %@ = %d", [newURL path], rc);
rc = sqlite3_exec(db, "CREATE TABLE foo (col1 INTEGER);", callback, 0, &zErrMsg);
if( rc!=SQLITE_OK ){
NSLog(@"SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}
// more sqlite code here
sqlite3_close(db);
}];
return;
}
其中 SQLiteRelatedItemPresenter 是:
@interface SQLiteRelatedItemPresenter : NSObject <NSFilePresenter>
{
NSURL *primaryPresentedItemURL;
NSURL *presentedItemURL;
}
static NSOperationQueue *_presentedItemOperationQueue;
@implementation SQLiteRelatedItemPresenter
+ (void) initialize {
[super initialize];
if (_presentedItemOperationQueue == nil) {
_presentedItemOperationQueue = [[NSOperationQueue alloc] init];
}
}
+ (void)addPresentersForURL:(NSURL *)databaseURL {
SQLiteRelatedItemPresenter *p1, *p2, *p3, *p4;
p1 =[[SQLiteRelatedItemPresenter alloc] initWithFileURL:databaseURL prefix:nil suffix:@"-wal"];
[NSFileCoordinator addFilePresenter:p1];
p2 = [[SQLiteRelatedItemPresenter alloc] initWithFileURL:databaseURL prefix:nil suffix:@"-shm"];
[NSFileCoordinator addFilePresenter:p2];
p3 = [[SQLiteRelatedItemPresenter alloc] initWithFileURL:databaseURL prefix:nil suffix:@"-journal"];
[NSFileCoordinator addFilePresenter:p3];
p4 = [[SQLiteRelatedItemPresenter alloc] initWithFileURL:databaseURL prefix:@"." suffix:@"-conch"];
[NSFileCoordinator addFilePresenter:p4];
// +filePresenters will only return once the asynchronously added file presenters are done being registered
[NSFileCoordinator filePresenters];
}
- initWithFileURL:(NSURL *)fileURL prefix:(NSString *)prefix suffix:(NSString *)suffix {
self = [super init];
if (self) {
primaryPresentedItemURL = fileURL;
NSString *path = [fileURL path];
if (prefix) {
NSString *name = [path lastPathComponent];
NSString *dir = [path stringByDeletingLastPathComponent];
path = [dir stringByAppendingPathComponent:[prefix stringByAppendingString:name]];
}
if (suffix) {
path = [path stringByAppendingString:suffix];
}
presentedItemURL = [NSURL fileURLWithPath:path];
}
return self;
}
- (NSURL *)presentedItemURL {
return presentedItemURL;
}
- (NSOperationQueue *)presentedItemOperationQueue {
return _presentedItemOperationQueue;
}
- (NSURL *)primaryPresentedItemURL {
return primaryPresentedItemURL;
}
这个特定的示例适用于所有在 openSQLiteFileAtURL 方法中执行的 sqlite 操作。如果我尝试将逻辑划分为子方法,我会遇到很多麻烦,例如:
- openSQLiteFileAtURL:(NSURL *)databaseURL; // just open the db
- executeSQLStatement:(NSString *)sql; //perform read/write operations into the sqlite db previously opened in the openSQLiteFileAtURL method
- closeSQLite(); //close db method.
似乎 addPresentersForURL 应该只被调用一次(在 openSQLiteFileAtURL 中),但由于沙盒权限错误,我无法拥有一个正常工作的应用程序......有什么帮助吗?