문제

저는 목록 앱을 만들고 이를 핵심 데이터로 뒷받침해 왔습니다.

사용자가 처음부터 시작할 필요가 없도록 공항 항목 10개의 기본 목록을 갖고 싶습니다.

이를 수행할 수 있는 방법이 있습니까?

도움을 주시면 감사하겠습니다.미리 감사드립니다.

도움이 되었습니까?

해결책

가장 좋은 방법은 다음과 같습니다 (SQL 지식이 필요하지 않음).
목록 앱과 동일한 객체 모델을 사용하여 빠른 핵심 데이터 iPhone 앱 (또는 Mac 앱)을 만듭니다. 상점에 원하는 기본 관리 객체를 저장하기 위해 몇 줄의 코드를 작성하십시오. 그런 다음 시뮬레이터에서 해당 앱을 실행하십시오. 이제 ~/라이브러리/응용 프로그램 지원/iPhone 시뮬레이터/사용자/응용 프로그램으로 이동하십시오. Guids 중 응용 프로그램을 찾은 다음 SQLITE 저장소를 List App의 프로젝트 폴더에 복사하기 만하면됩니다.

그런 다음 Coredatabooks 예제에서와 같이 그 상점을로드하십시오.

다른 팁

예, 실제로 Coredatabooks 예제가이를 수행합니다. 여기에서 코드를 다운로드 할 수 있습니다. 샘플 코드

귀하가하는 일은 일반 절차를 사용하여 내부 상점 (데이터베이스)을 작성하여 다른 스토어와 마찬가지로 매장을 초기화하는 것입니다. 그러면 단순히 코드를 실행하고 Coredatabooks 예제 (아래 코드 스 니펫에 설명 된대로 코드를 실행하도록하십시오. ). 상점이 초기화되면 NSManagedObjectContext 생성 된 영구 저장소로 초기화하고 필요한 모든 엔티티를 삽입하고 컨텍스트를 저장하십시오.

컨텍스트가 성공적으로 저장되면 응용 프로그램을 중지 한 다음 Finder로 이동하여 폴더로 이동할 수 있습니다. ~/Library/Developer 검색을 입력하고 .sqlite를 입력하고 아래 /개발자를 봅니다. 날짜별로 정렬하면 코드가 실행되는 시간과 일치 해야하는 최신 .Qlite 데이터베이스가 제공됩니다. 그러면이 스토어를 가져 와서 프로젝트의 리소스로 추가 할 수 있습니다. . 그런 다음이 파일은 지속적인 매장 코디네이터가 읽을 수 있습니다.

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

if (persistentStoreCoordinator) {
    return persistentStoreCoordinator;
}


NSString *storePath = [[self applicationDocumentsDirectory]      stringByAppendingPathComponent: @"CoreDataBooks.sqlite"];
 /*
  Set up the store.
 For the sake of illustration, provide a pre-populated default store.
 */
NSFileManager *fileManager = [NSFileManager defaultManager];
// If the expected store doesn't exist, copy the default store.
if (![fileManager fileExistsAtPath:storePath]) {
  NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"CoreDataBooks"      ofType:@"sqlite"];
 if (defaultStorePath) {
 [fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
 }
}

NSURL *storeUrl = [NSURL fileURLWithPath:storePath];

 NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber   numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; 
  persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];

 NSError *error;
 if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
  // Update to handle the error appropriately.
  NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
 exit(-1);  // Fail
}    

return persistentStoreCoordinator;
}

도움이되기를 바랍니다.

-oscar

이 방법을 사용하면 별도의 앱을 만들거나 SQL 지식이 필요하지 않습니다. 초기 데이터에 대한 JSON 파일 만 만들 수 있어야합니다.

객체로 구문 분석 한 JSON 파일을 사용한 다음 코어 데이터에 삽입합니다. 앱이 초기화되면이 작업을 수행합니다. 또한이 초기 데이터가 이미 삽입되었는지를 나타내는 핵심 데이터에서 하나의 엔티티를 만듭니다. 초기 데이터를 삽입 한 후이 엔티티를 설정 한 후 다음에 스크립트가 실행되면 초기 데이터가 이미 초기화되었음을 알 수 있습니다.

json 파일을 객체로 읽으려면 :

NSString *initialDataFile = [[NSBundle mainBundle] pathForResource:@"InitialData" ofType:@"json"];
NSError *readJsonError = nil;
NSArray *initialData = [NSJSONSerialization
                        JSONObjectWithData:[NSData dataWithContentsOfFile:initialDataFile]
                        options:kNilOptions
                        error:&readJsonError];

if(!initialData) {
    NSLog(@"Could not read JSON file: %@", readJsonError);
    abort();
}

그런 다음 다음과 같이 엔티티 객체를 만들 수 있습니다.

[initialData enumerateObjectsUsingBlock:^(id objData, NSUInteger idx, BOOL *stop) {

    MyEntityObject *obj = [NSEntityDescription
                          insertNewObjectForEntityForName:@"MyEntity"
                          inManagedObjectContext:dataController.managedObjectContext];

    obj.name = [objData objectForKey:@"name"];
    obj.description = [objData objectForKey:@"description"];

    // then insert 'obj' into Core Data

}];

이 작업을 수행하는 방법에 대한 자세한 설명을 원한다면이 자습서를 확인하십시오.http://www.raywenderlich.com/12170/core-data-tutorial-how-tropreloadimport-existing-data-updated

10 개 항목의 경우 내 에서이 작업을 수행 할 수 있습니다. applicationDidFinishLaunching: 앱 대의원에서.

방법을 정의하십시오 insertPredefinedObjects, 그것은 공항 품목 관리를 담당하는 엔티티의 사례를 생성하고 채우고 컨텍스트를 저장합니다. 파일에서 속성을 읽거나 단순히 코드에서 하드 와이어를 사용하여 단순히 하드 와이어 할 수 있습니다. 그런 다음이 메소드를 내부로 호출하십시오 applicationDidFinishLaunching:.

Coredatabooks 예제 코드를 따를 때 iOS 데이터 저장 지침을 중단 할 수 있습니다.

https://developer.apple.com/icloud/documentation/data-storage/

(읽기 전용) 사전 인구 데이터베이스를 문서 디렉토리에 복사하는 데 앱이 거부되었으며 Apple은 사용자가 생성 한 파일에만 발생하기를 원합니다.

위의 지침은 몇 가지 솔루션을 제공하지만 대부분은 다음과 같습니다.

  • DB를 캐시스 디렉토리에 보관하고 OS가 캐시를 제거하는 상황을 우아하게 처리합니다. DB를 재건해야합니다.

  • DB 파일에서 'Do n't Cache Attribute'를 설정합니다. DB 파일은 다른 OS 버전에 대해 다르게 수행해야하므로 약간의 원인입니다.

나는 그것이 너무 까다 롭다고 생각하지 않지만, 당신이 Icloud와 함께 그 예제 코드를 작동시키기 위해 할 일이 조금 더 있다는 것을 알고 있어야합니다 ...

그래서 저는 사전(아마도 JSON)에서 로드하고 데이터베이스를 채우는 일반적인 방법을 개발했습니다.안전한 채널의 신뢰할 수 있는 데이터에만 사용해야 하며 순환 참조를 처리할 수 없으며 스키마 마이그레이션이 문제가 될 수 있습니다.하지만 나와 같은 간단한 사용 사례에는 괜찮을 것입니다.

여기 간다

- (void)populateDBWithDict:(NSDictionary*)dict
               withContext:(NSManagedObjectContext*)context
{
    for (NSString* entitieName in dict) {

        for (NSDictionary* objDict in dict[entitieName]) {

            NSManagedObject* obj = [NSEntityDescription insertNewObjectForEntityForName:entitieName inManagedObjectContext:context];
            for (NSString* fieldName in objDict) {

                NSString* attName, *relatedClass, *relatedClassKey;

                if ([fieldName rangeOfString:@">"].location == NSNotFound) {
                    //Normal attribute
                    attName = fieldName; relatedClass=nil; relatedClassKey=nil;
                } else {
                    NSArray* strComponents = [fieldName componentsSeparatedByString:@">"];
                    attName = (NSString*)strComponents[0];
                    relatedClass = (NSString*)strComponents[1];
                    relatedClassKey = (NSString*)strComponents[2];
                }
                SEL selector = NSSelectorFromString([NSString stringWithFormat:@"set%@:", attName ]);
                NSMethodSignature* signature = [obj methodSignatureForSelector:selector];
                NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
                [invocation setTarget:obj];
                [invocation setSelector:selector];

                //Lets set the argument
                if (relatedClass) {
                    //It is a relationship
                    //Fetch the object
                    NSFetchRequest* query = [NSFetchRequest fetchRequestWithEntityName:relatedClass];
                    query.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:relatedClassKey ascending:YES]];
                    query.predicate = [NSPredicate predicateWithFormat:@"%K = %@", relatedClassKey, objDict[fieldName]];

                    NSError* error = nil;
                    NSArray* matches = [context executeFetchRequest:query error:&error];


                    if ([matches count] == 1) {
                        NSManagedObject* relatedObject = [matches lastObject];
                        [invocation setArgument:&relatedObject atIndex:2];
                    } else {
                        NSLog(@"Error! %@ = %@ (count: %d)", relatedClassKey,objDict[fieldName],[matches count]);
                    }


                } else if ([objDict[fieldName] isKindOfClass:[NSString class]]) {

                    //It is NSString
                    NSString* argument = objDict[fieldName];
                    [invocation setArgument:&argument atIndex:2];
                } else if ([objDict[fieldName] isKindOfClass:[NSNumber class]]) {

                    //It is NSNumber, get the type
                    NSNumber* argument = objDict[fieldName];
                    [invocation setArgument:&argument atIndex:2];

                }
                [invocation invoke];


            }

            NSError *error;
            if (![context save:&error]) {
                NSLog(@"%@",[error description]);
            }
        }
    }   
}

그리고 json에서 로드합니다...

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"initialDB" ofType:@"json"];
NSData *jsonData = [NSData dataWithContentsOfFile:filePath];

NSError* error;
NSDictionary *initialDBDict = [NSJSONSerialization JSONObjectWithData:jsonData
                                                           options:NSJSONReadingMutableContainers error:&error];

[ self populateDBWithDict:initialDBDict withContext: [self managedObjectContext]];

JSON 예

    {
    "EntitieA": [ {"Att1": 1 }, {"Att1": 2} ],
    "EntitieB": [ {"Easy":"AS ABC", "Aref>EntitieA>Att1": 1} ]
    }

그리고

{
    "Country": [{"Code": 55, "Name": "Brasil","Acronym": "BR"}],
    "Region": [{"Country>Country>code": 55, "Code": 11, "Name": "Sao Paulo"},
               {"Country>Country>code": 55, "Code": 31, "Name": "Belo Horizonte"}]
}

객체가 존재하는지 확인하고 그렇지 않은 경우 일부 데이터로 객체를 작성하는 것은 어떻습니까?

NSManagedObjectContext *managedObjectContext = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Settings"];
_managedObjectSettings = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy];

if ([_managedObjectSettings count] == 0) {
    // first time, create some defaults
    NSManagedObject *newDevice = [NSEntityDescription insertNewObjectForEntityForName:@"Settings" inManagedObjectContext:managedObjectContext];

    [newDevice setValue:[NSNumber numberWithBool: YES ] forKey:@"speed"];
    [newDevice setValue:[NSNumber numberWithBool: YES ] forKey:@"sound"];
    [newDevice setValue:[NSNumber numberWithBool: NO ] forKey:@"aspect"];
    [newDevice setValue:[NSNumber numberWithBool: NO  ] forKey: @"useH264"];
    [newDevice setValue:[NSNumber numberWithBool: NO ] forKey: @"useThumbnail"];

    NSError *error = nil;
    // Save the object to persistent store
    if (![managedObjectContext save:&error]) {
        NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]);
    }
}

이 답변은 다음과 같은 사람들에게만 해당됩니다.

  • 앱에 미리 채워진 데이터베이스 포함
  • 다양한 플랫폼(iOS, Android 등)용 앱 만들기

Android 앱용으로 미리 채워진 SQLite 데이터베이스를 만들었습니다.그러다가 iOS 버전의 앱을 만들면서 Core Data를 사용하는 것이 가장 좋겠다고 생각했습니다.그래서 저는 핵심 데이터를 배우고 데이터베이스를 미리 채우는 코드를 다시 작성하는 데 꽤 오랜 시간을 보냈습니다.두 플랫폼 모두에서 모든 단계를 수행하는 방법을 배우려면 많은 연구와 시행착오가 필요했습니다.제가 기대했던 것보다 겹치는 부분이 훨씬 적었습니다.

결국 나는 내 Android 프로젝트에서 동일한 SQLite 데이터베이스를 사용하기로 결정했습니다.그런 다음 FMDB 래퍼를 사용하여 iOS의 데이터베이스에 직접 액세스했습니다.혜택:

  • 미리 채워진 데이터베이스를 한 번만 만들면 됩니다.
  • 패러다임 전환이 필요하지 않습니다.Android와 FMDB 간의 구문은 다르지만 여전히 상당히 유사합니다.
  • 쿼리 수행 방법을 훨씬 더 효과적으로 제어할 수 있습니다.
  • 전체 텍스트 검색을 허용합니다.

Core Data를 배운 것을 후회하지는 않지만, 다시 공부한다면 SQLite만 고수했다면 시간을 많이 절약할 수 있었을 것입니다.

iOS에서 시작한 다음 Android로 이동할 계획이라면 FMDB와 같은 SQLite 래퍼나 다른 소프트웨어를 사용하여 데이터베이스를 미리 채울 것입니다.핵심 데이터로 미리 채워진 SQLite 데이터베이스를 기술적으로 추출할 수 있지만 스키마(테이블 및 열 이름 등)의 이름은 이상하게 지정됩니다.

그런데 미리 채워진 데이터베이스를 수정할 필요가 없다면 앱을 설치한 후 이를 문서 디렉터리에 복사하지 마세요.번들에서 직접 액세스하면 됩니다.

// get url reference to databaseName.sqlite in the bundle
let databaseURL: NSURL = NSBundle.mainBundle().URLForResource("databaseName", withExtension: "sqlite")!

// convert the url to a path so that FMDB can use it
let database = FMDatabase(path: databaseURL.path)

이렇게 하면 두 개의 복사본이 없게 됩니다.

업데이트

나는 지금 사용한다 SQLite.swift FMDB보다는 Swift 프로젝트와 더 잘 통합되기 때문입니다.

기본값 저장을위한 또 다른 방법은 nsuserDefaults를 통해 찾을 수 있습니다. (놀라움!) 그리고 쉬운.

어떤 사람들이 제안한 것은 그것을 applicationDidFinishLaunching

주어진 10 개의 기본값의 경우, 공항 0 Thru 9

환경

NSUserDefaults *nud = [NSUserDefaults standardUserDefaults];
[nud setString:@"MACADDRESSORWHY" forKey:@"Airport0"];
    ...
[nud setString:@"MACADDRESSORWHY" forKey:@"Airport9"];
[nud synchronize];

또는

[[NSUserDefaults standardUserDefaults] setString:@"MACADDRESSORWHY" forKey:@"Airport9"]];
     ...
[[NSUserDefaults standardUserDefaults] synchronize];

그런 다음 기본값을받습니다.

NSString *air0 = [[NSUserDefaults standardUserDefaults] stringForKey:@"Airport0"];

이것은 나를 위해 효과가있었습니다. 이것은 이것의 수정입니다 대답 ~에 의해 안드레아 토소 그리고 이것에 영감을 받았습니다 블로그. 답의 유일한 문제는 FileManager와 함께 SQLITE 파일을 이동할 때 데이터 손실 가능성이 있다는 것입니다. 필자 대신 대체물을 사용하여 약 500 행의 데이터를 저장했습니다.

1 단계
다른 앱에서 핵심 데이터를 채우고이 코드를 사용하여 파일의 경로를 가져옵니다.

let paths = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
print(documentsDirectory)

2 단계
.sqlite 확장으로 3 개의 파일을 Xcode 프로젝트로 드래그하십시오. (대상에 추가 옵션을 선택하십시오).

STEP3
appdelegate.swift에서 앱의 첫 실행을 확인하는 기능을 작성하십시오.

func isFirstLaunch() -> Bool {
    let hasBeenLaunchedBeforeFlag = "hasBeenLaunchedBeforeFlag"
    let isFirstLaunch = !UserDefaults.standard.bool(forKey: hasBeenLaunchedBeforeFlag)
    if (isFirstLaunch) {
        UserDefaults.standard.set(true, forKey: hasBeenLaunchedBeforeFlag)
        UserDefaults.standard.synchronize()
    }
    return isFirstLaunch
}

단계 4
이 기능을 AppDelegate.swift에 복사하여 SQLITE 데이터베이스를 이동 해야하는 URL을 가져옵니다.

func getDocumentsDirectory()-> URL {
    let paths = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)
    let documentsDirectory = paths[0]
    return documentsDirectory
}

5 단계
PersistentContainer의 선언을 다음과 같이 대체하십시오.

// MARK: - Core Data stack

lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "ProjectName")

    let storeUrl = self.getDocumentsDirectory().appendingPathComponent("FileName.sqlite")

    if UserDefaults.isFirstLaunch() {
        let seededDataUrl = Bundle.main.url(forResource: "FileName", withExtension: "sqlite")
        try! container.persistentStoreCoordinator.replacePersistentStore(at: storeUrl, destinationOptions: nil, withPersistentStoreFrom: seededDataUrl!, sourceOptions: nil, ofType: NSSQLiteStoreType)
    }

    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top