NSPersistentContainer를 통한 코어데이터 스택생성하기

macOS Sierra로 업데이트되면서 코어데이터에 NSPersistentContainer 클래스가 추가되었다. 이 클래스를 사용하면 코어데이터 스택을 셋업하는 여러 귀찮은 과정을 생략하고 간단하게 처리할 수 있다. 사실 코어데이터 스택을 수동으로 셋업하는 과정에서 필요한 정보는 코어데이터 모델 파일의 이름과, 저장소 파일을 생성할 위치 정도이며, 그외의 대부분의 코드는 보일러 플레이트라 할 수 있다.  저장소 파일 위치는 적당한이름(?)으로 사용자 라이브러리 내에 만들어지므로 결국 최소한으로 필요한 정보는 데이터 모델 파일 이름이 된다. 즉 관리 객체 모델의 이름만 있다면 코어데이터 스택의 초기화에 필요한 코드는 사실상 동일하다 하겠다.

NSPersistentContainer를 사용한 코어데이터 스택 초기화 방법은 다음과 같다.

/// 영구저장소 컨테이너를 프로퍼티로 선언한다. 
@interface AppController: NSObject
@property (readonly, strong) NSPersistentContainer* persistentContainer;
@end


@implmentation AppController
@synthesize persistentConatainer=_persistentContainer;

- (NSPersistentContainer*)persistentContainer
{
  /// 영구저장소 컨테이너 초기화
  if(!_persistentContainer) {
    // Managed Model의 이름을 기준으로 구성할 수 있다.
    // 이 때, 이름에는 확장자를 생략해야 한다.
    _persistentContainer = [[NSPersistentContainer alloc]
                            initWithName: @"MyDataModel"];
    [_persistentContainer loadPersistentStoresWithCompletionHandler:
            ^(NSPersistentStoreDescription *desc, NSError *error){
        if(!error) {  // 저장소 로딩 중 에러가 발생
          NSLog(@"Unresolved error %@, %@", error, error.userInfo);
      }
    }];
  }
  return _persistentContainer;
}

Swift 코드는 2 페이지에 있습니다.

매우 간단하게 모든 설정이 완료됐다. 실제 데이터를 사용할 때 필요한 관리객체모델과 컨텍스트는 이 컨테이너 객체의 managedObjectModel, viewContext 프로퍼티로 액세스할 수 있다. 컨텍스트만 따로 외부로 노출하려한다면, 다음과 같이 프로퍼티를 선언/정의한다.

@property (readonly, nonatomic) NSManagedObjectContext* context;
//....


- (NSManagedObjectContext*) context { return self.persistentContainer.viewContext }

저장소에 관한 커스터마이징

NSPersistentStoreCoordinator를 직접 셋업하는 경우에는 초기화 시점에 저장소 위치와 타입등의 정보를 설정해야 했다. 이러한 설정정보를 하나의 클래스로 묶은 것이 저장소 디스크립션으로 NSPersistentStoreDescription이라는 클래스로 만들어져있다. NSPersistentContainer는 이 디스크립션을 이용해서 “각각의 저장소들을” 생성한다.(즉 컨테이너는 기본적으로 하나의 컨텍스트에서 여러 개의 저장소를 액세스하는 것을 지원하고 있다.)

기본적으로 아무런 정보가 주어지지 않으면 컨테이너는 SQLite 타입의 저장소를 라이브러리 디렉토리 내에 저장하게 된다. 만약 저장소 위치를 옮기고 싶거나, 타입을 바꾸고 싶으면 새로운 저장소 디스크립션을 생성해서 바꿔주면 된다. 대신 이 동작이 유효하려면 loadPersistentStores...:를 호출하기 전에 설정을 변경해 두어야 한다.

// 영구 저장소 위치를 직접 지정하고 싶을 때
// NSPersistentStoreDescription 객체를 만들어서 
// 영구저장소 로딩전에 컨테이너에 세팅한다.
  NSURL* dirURL = [[[NSFileManager defaultManager] 
             URLsForDirectory:NSDocumentDirectory
             inDomains:NSUserDomainMasks] lastObject];
  NSURL* storeURL = [dirURL URLByAppendingPahtComponent:@"mydata.db"];

  NSPersistentStoreDescription* desc = [[NSPersistentStoreDescription alloc] initWithURL:storeURL];
  desc.type = NSSQLiteStoreType;
  [_persistentContainer setPersistentStoreDescriptions:@[desc]];

  [_persistentContainer loadPersistentStoresWithHandler:^ ...

저장소 디스크립션은 기존 API에도 추가되었다. 수동으로 스택을 셋업하면서 NSPersistentStoreCoordinator를 사용하는 경우에도 addPersistentStoreWithDescription:completionHandler:를 사용할 수 있으니 참고하자.