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 파일이 존재하는지 체크해서 존재 안하면 생성 시켜버렸습니다. 






+ Recent posts