Notice
Recent Posts
Recent Comments
Dharma
[iPhone-Dev] iOS 4.2 SDK 환경에서 개발할 때 CoreData 사용하는 Apps 에서 SQLite DB 파일 미리 불러오기 본문
프로그래밍
[iPhone-Dev] iOS 4.2 SDK 환경에서 개발할 때 CoreData 사용하는 Apps 에서 SQLite DB 파일 미리 불러오기
광이랑 2010. 11. 30. 16:44
iPhone 에서는 실행파일 과 번들이 속한 디렉토리가 Read-only 기 때문에 읽고-쓸 수 있는 Sqlite 파일을 만들어 줄려면 수동으로 복사해 줘야 하는 코드가 필요합니다.
즉 앱스가 읽고 쓸 수 있는 'Documents' 디렉토리에 번들로 포함된 Sqlite 파일을 옮겨주기만 하면 되는 것입니다.
해결방법
- (void) createEditableCopyOfDatabaseIfNeeded { // test for existance NSFileManager * fileManager = [NSFileManager defaultManager]; NSString *documentsDirectory = [self applicationDocumentsDirectory]; NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:@"OhReading.sqlite"]; BOOL dbexists = [fileManager fileExistsAtPath:writableDBPath]; if(!dbexists) { NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"OhReading.sqlite"]; NSError * error; BOOL success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error]; if (!success) { NSAssert1(0, @"Failed to create writable database file with message '%@', ", [error localizedDescription]); } } } - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { if (persistentStoreCoordinator_ != nil) { return persistentStoreCoordinator_; } NSURL *storeURL = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"OhReading.sqlite"]]; NSError *error = nil; [self createEditableCopyOfDatabaseIfNeeded]; persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
중간에
[self createEditableCopyOfDatabaseIfNeeded];
라는 식으로 persistentStoreCoordinator 함수 중간에 추가해 주면 번들에 있는 OhReading.sqlite 파일을 읽고-쓸 수 있는 Documents 디렉토리에 복사해줍니다.
매우 쉽게 해결하기는 했지만, 막상 저는 고생했습니다. 예전에 참조했던 책인 'Head First iPhone Development - 2009' 에서 해결하는 방법이 몸에 익어버렸기 때문입니다. (Chapter 07 , 359 page)
iOS (3.1.3) 해결 방법 (책에 나온 방법)
- (void)applicationDidFinishLaunching:(UIApplication *)application { // Override point for customization after app launch [self createEditableCopyOfDatabaseIfNeeded]; } - (void) createEditableCopyOfDatabaseIfNeeded { // test for existance NSFileManager * fileManager = [NSFileManager defaultManager]; NSString *documentsDirectory = [self applicationDocumentsDirectory]; NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:@"OhReading.sqlite"]; BOOL dbexists = [fileManager fileExistsAtPath:writableDBPath]; if(!dbexists) { NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"OhReading.sqlite"]; NSError * error; BOOL success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error]; if (!success) { NSAssert1(0, @"Failed to create writable database file with message '%@', ", [error localizedDescription]); } } }
하지만 이제 안되는 이유는
applicationDidFinishLaunching 함수가 사라졌(?)습니다. 사실 존재하는 것 같기는 하지만 숨긴 것 같습니다. 대신
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
함수가 대신해서 생긴 것 같습니다. 하는 일이 비슷한 것 같다는 것이죠.
그렇다고 이렇게 만들면 문제가 발생합니다.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. [self createEditableCopyOfDatabaseIfNeeded]; // Add the navigation controller's view to the window and display. [window addSubview:navigationController.view]; [window makeKeyAndVisible]; return YES; }
createEditableCopyOfDatabaseIfNeeded
함수가 호출 되기 전에 이미 Documents 디렉토리에 sqlite 파일이 생기는 문제인데요. 대체 이유가 뭔가 해서 스택에 호출된 함수를 일일이 뒤지다가 시간이 다 지나갔습니다. 결국 '오컴의 면도날(클릭)' 을 생각해 냈습니다. '스택을 다 뒤지는 것 같이 복잡한 것이 아닐 것이다. 쉬운 해결 방법이 있을 것이다' 그래서 다른 접근 방법을 통해서
persistentStoreCoordinator 가 호출되기 전에 sqlite 파일이 존재하는지 체크해서 존재 안하면 생성 시켜버렸습니다.