programing

핵심 데이터를 미리 채울 방법이 있습니까?

codeshow 2023. 9. 14. 23:42
반응형

핵심 데이터를 미리 채울 방법이 있습니까?

리스트 앱을 만들어서 핵심 데이터로 지원하고 있습니다.

저는 사용자가 처음부터 시작할 필요가 없도록 공항의 10개 품목에 대한 기본 목록을 가지고 싶습니다.

이것을 할 수 있는 방법이 없을까요?

어떤 도움이든 감사히 받겠습니다.미리 감사드립니다.

SQL 지식이 필요 없는 가장 좋은 방법은 다음과 같습니다.
List 앱과 동일한 객체 모델을 사용하여 빠른 Core Data iPhone 앱(또는 Mac 앱)을 만듭니다.몇 줄의 코드를 작성하여 저장소에 기본 관리 개체를 저장합니다.그런 다음, 시뮬레이터에서 그 앱을 실행합니다.이제 ~/라이브러리/애플리케이션 지원/아이폰 시뮬레이터/사용자/애플리케이션으로 이동합니다.GUID 중에서 응용 프로그램을 찾은 다음 목록 앱의 프로젝트 폴더에 sqlite 스토어를 복사하기만 하면 됩니다.

그런 다음 CoreDataBooks 예제처럼 저장소를 로드합니다.

예, CoreDataBooks 예제에서는 이 작업을 수행합니다. 여기에서 코드를 다운로드할 수 있습니다. 샘플 코드

일반적인 절차를 사용하여 내부 저장소(데이터베이스)를 생성하여 다른 저장소와 마찬가지로 저장소를 초기화한 다음 코드를 실행하여 CoreDataBooks 예제(아래 코드 조각)에 설명된 대로 코드를 실행할 수 있습니다.스토어가 초기화되면 다음을 생성할 수 있습니다.NSManagedObjectContext생성된 영구 저장소로 초기화하고 필요한 모든 엔티티를 삽입한 후 컨텍스트를 저장합니다.

폴더로 할 수 .~/Library/Developersearch .sqlite를 /sqlite를 검색합니다. 날짜별로 정렬하면 코드가 실행된 시간과 일치하는 최신 .sqlite 데이터베이스가 제공됩니다. 그러면 이 저장소를 가지고 프로젝트의 리소스로 추가할 수 있습니다.그러면 영구 저장소 코디네이터가 이 파일을 읽을 수 있습니다.

- (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;
}

도움이 되길 바랍니다.

-오스카

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

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

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-to-preloadimport-existing-data-updated 를 확인해 보세요.

10개의 아이템에 대해서는 그냥 안에서 할 수 있습니다.applicationDidFinishLaunching:당신의 앱 대리인에게.

방법을 정의합니다. 예를 들어,insertPredefinedObjects를 저장합니다 , 의 를 하는 의 를 하고 합니다 를 의 합니다 를 의 하고 의 를 의 .파일에서 속성을 읽거나 코드에서 간단히 하드와이어할 수 있습니다.이 을요으로 안에 .applicationDidFinishLaunching:.

CoreDataBooks 예제 코드를 따를 때 iOS DataStorage Guideline을 위반할 가능성이 있음을 유의하십시오.

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

미리 입력된 (읽기 전용) 데이터베이스를 문서 디렉토리에 복사하는 것에 대해 앱이 거부되었습니다. 그러면 iCloud에 백업됩니다. 그리고 Apple은 사용자가 생성한 파일에만 이러한 일이 발생하기를 원합니다.

위 지침은 몇 가지 해결책을 제공하지만 대부분 다음과 같이 요약됩니다.

  • 캐시 디렉토리에 DB를 저장하고, OS가 캐시를 삭제하는 상황을 적절하게 처리합니다. DB를 다시 만들어야 할 것이고, 아마도 대부분의 사람들은 DB를 배제할 것입니다.

  • DB 파일에 '캐시하지 않음 속성'을 설정합니다. 이는 OS 버전에 따라 다르게 수행해야 하므로 약간 난해합니다.

그다지 까다롭지는 않지만, 예제 코드가 iCloud와 함께 작동하도록 하려면 추가로 해야 할 일이 조금 더 있다는 것을 알아두시기 바랍니다.

이 대답은 오직 다음과 같은 사람들을 위한 것입니다.

  • 앱에 미리 저장된 데이터베이스 포함
  • 여러 플랫폼(iOS, Android 등)을 위한 앱 만들기

안드로이드 앱을 위해 미리 입력된 SQLite 데이터베이스를 만들었습니다.그러다가 iOS 버전의 앱을 만들 때 코어 데이터를 사용하는 것이 가장 좋다고 생각했습니다.그래서 저는 Core Data를 배운 후 데이터베이스를 미리 채우기 위해 코드를 다시 작성하는 데 꽤 많은 시간을 보냈습니다.두 플랫폼 모두에서 모든 단계를 수행하는 방법을 배우는 데는 많은 연구와 시행착오가 필요했습니다.내가 기대했던 것보다 훨씬 적은 중복이 있었습니다.

결국 안드로이드 프로젝트에서 나온 것과 같은 SQLite 데이터베이스를 사용하기로 결정했습니다.그리고 FMDB 래퍼를 사용하여 iOS에서 데이터베이스에 직접 접속하였습니다.이점:

  • 미리 입력된 데이터베이스를 한 번만 만들면 됩니다.
  • 패러다임 전환이 필요하지 않습니다.Android와 FMDB의 구문은 다르지만 여전히 상당히 유사합니다.
  • 질의가 수행되는 방식을 보다 많이 제어할 수 있습니다.
  • 전체 텍스트 검색을 허용합니다.

Core Data를 배운 것을 후회하지는 않지만, 반복해서 사용한다면 SQLite만 사용하면 많은 시간을 절약할 수 있었을 것입니다.

iOS에서 시작하고 Android로 이동할 계획이 있다면 FMDB와 같은 SQLite 래퍼나 다른 소프트웨어를 사용하여 데이터베이스를 미리 채울 것입니다.Core Data로 미리 입력하는 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)

이렇게 하면 복사본이 두 개가 안 나오게 됩니다.

갱신하다

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

저는 이게 통했어요.Andrea Toso가 이 답변을 수정한 이고 이 블로그에서 영감을 얻었습니다.답변의 유일한 문제는 FileManager로 sqlite 파일을 이동할 때 데이터가 손실될 가능성이 있다는 것입니다.FileManager.default.copy 대신 replacePersistentStore를 사용하여 약 500행의 데이터를 절약했습니다.아이템

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

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


.가 있는의 파일을 로 끌어다 .sqlite 확장자가 3 파일을 xCode 프로젝트로 . 옵션을 선택해야 .(Add to targets 옵션을 선택해야 합니다.)


swiftAppDelegate.swiftAppDelegate.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
}


AppDelegate.swift에서 이 함수를 복사하여 sqlite 데이터베이스가 이동될 URL을 가져옵니다.

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

55단계
을 persistentContainer이로다을다es로n:fe이을rntn

// MARK: - Core Data stack

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

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

    if 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
}()

그래서 저는 (아마도 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]);
    }
}

기본값을 저장하는 또 다른 방법은 NSUserDefaults를 통해 찾을 수 있습니다.(웃음!)그리고 쉽죠.

어떤, 을 을, .applicationDidFinishLaunching

주어진 10개의 기본값의 경우, Airport0 ~ 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"];

대부분의 답이 꽤 오래되었기에 다음 튜토리얼을 추천합니다.어떻게 할 수 있는지 설명해 줍니다.

https://www.youtube.com/watch?v=xcV8Ow9nWFo

언급URL : https://stackoverflow.com/questions/2230354/any-way-to-pre-populate-core-data

반응형