임시 NSManagedObject 인스턴스를 처리하는 방법은 무엇입니까?


86

NSManagedObject인스턴스 를 만들고 몇 가지 작업을 수행 한 다음이를 폐기하거나 sqlite db에 저장해야합니다. 문제는 NSManagedObject연결되지 않은 인스턴스를 만들 수 없다는 NSManagedObjectContext것입니다. 즉, DB에있는 일부 개체가 필요하지 않다고 결정한 후 어떻게 든 정리해야합니다.

이를 처리하기 위해 동일한 코디네이터를 사용하여 메모리 내 저장소를 만들고 assignObject:toPersistentStore.Now 를 사용하여 임시 개체를 배치 하고 있습니다. 이러한 임시 개체가 데이터에 도달하지 않도록하려면 어떻게해야하나요? 두 상점 컨텍스트에 공통입니까? 아니면 그러한 작업에 대해 별도의 컨텍스트를 만들어야합니까?


UPD :

이제 메모리 내 저장소에 대해 별도의 컨텍스트를 만드는 방법을 생각하고 있습니다. 한 컨텍스트에서 다른 컨텍스트로 개체를 어떻게 이동합니까? [context insertObject :]를 사용하십니까? 이 설정에서 제대로 작동합니까? 객체 그래프에서 하나의 객체를 삽입하면 전체 그래프도 컨텍스트에 삽입됩니까?


이 질문을 답변으로 표시 했으므로이 질문은 별도의 질문이어야합니다. 새 질문을 작성하고 설명 당신이 스택 별도의 전체 코어 데이터를 필요로 느낄 그냥 메모리 내 상점. 나는 당신과 함께 질문을 탐구하게되어 기쁩니다.
Marcus S. Zarra

UPD 섹션은 이제 관련이 없습니다. 다른 접근 방식을 선택했기 때문에 귀하의 답변에 대한 마지막 의견을 참조하십시오.
fspirit

답변:


146

참고 : 이 답변은 매우 오래되었습니다. 전체 기록을 보려면 댓글을 참조하세요. 이후 권장 사항이 변경되었으며 더 이상 연결되지 않은 NSManagedObject인스턴스를 사용하지 않는 것이 좋습니다 . 현재 권장 사항은 임시 자식 NSManagedObjectContext인스턴스 를 사용하는 것 입니다.

원래 답변

이를 수행하는 가장 쉬운 방법 NSManagedObject은 연결된 NSManagedObjectContext.

NSEntityDescription *entity = [NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:myMOC];
NSManagedObject *unassociatedObject = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];

그런 다음 저장하려는 경우 :

[myMOC insertObject:unassociatedObject];
NSError *error = nil;
if (![myMoc save:&error]) {
  //Respond to the error
}

6
unrelatedObject에 다른 관련되지 않은 객체에 대한 참조가있는 경우 하나씩 삽입해야합니까? 아니면 myMOC가 모든 참조를 수집하고 삽입 할 수있을만큼 똑똑합니까?
fspirit 2010

6
관계도 처리하기에 충분히 똑똑합니다.
Marcus S. Zarra

2
이 접근 방식을 사용하면 MO를 저장하기 전에 일반 데이터 개체처럼 취급 할 수 있다는 점이 마음에 들지만 CoreData 계약에 의해 "지원"되는 방식과 따라서 그것이 얼마나 미래에도 보장되는지에 대해 걱정합니다. 애플은 어디서든이 접근 방식을 언급하거나 사용합니까? 그렇지 않은 경우 향후 iOS 릴리스는 MOC에 의존하도록 동적 속성을 변경하여이 접근 방식을 깨뜨릴 수 있기 때문입니다. 사과의 문서는이에 명확하지 않다 : 그들은 문맥과 초기화 지정의 중요성을 강조하지만, 하나의 언급이 말하는 MO의 문서에있다 "문맥이 전무하지 않은 경우, 다음 ..."이 전무을 시사 확인 수 있습니다
대황

41
이 접근 방식을 얼마 전에 사용했지만 MOC에 삽입하기 전에 해당 개체를 수정하거나 관계를 만들 때 이상한 동작과 충돌이 발생하기 시작했습니다. WWDC의 Core Data 엔지니어와이 문제를 논의했고 그는 관련되지 않은 개체에 대한 API가 있지만 MOC가 개체에서 보낸 KVO 알림에 크게 의존하는 것으로 사용하는 것을 강력히 권장한다고 말했습니다. 그는 임시 객체에 대해 일반 NSObject를 사용하는 것이 훨씬 안전하기 때문에 제안했습니다.
Adrian Schönig 2013 년

7
이것은 iOS 8, 특히 지속적인 관계에서 잘 작동하지 않는 것 같습니다. 다른 사람이 이것을 확인할 수 있습니까?
Janum Trivedi 2014 년

40

iOS5는 Mike Weller의 대답에 대한 더 간단한 대안을 제공합니다. 대신 자식 NSManagedObjectContext를 사용하십시오 . NSNotificationCenter를 통해 트램폴린이 필요하지 않습니다.

하위 컨텍스트를 만들려면 :

NSManagedObjectContext *childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
childContext.parentContext = myMangedObjectContext;

그런 다음 자식 컨텍스트를 사용하여 개체를 만듭니다.

NSManagedObject *o = [NSEntityDescription insertNewObjectForEntityForName:@"MyObject" inManagedObjectContext:childContext];

변경 사항은 하위 컨텍스트가 저장 될 때만 적용됩니다. 따라서 변경 사항을 취소하려면 저장하지 마십시오.

관계에는 여전히 제한이 있습니다. 즉, 다른 컨텍스트의 개체에 대한 관계를 만들 수 없습니다. 이 문제를 해결하려면 objectID를 사용하여 자식 컨텍스트에서 개체를 가져옵니다. 예.

NSManagedObjectID *mid = [myManagedObject objectID];
MyManagedObject *mySafeManagedObject = [childContext objectWithID:mid];
object.relationship=mySafeManagedObject;

하위 컨텍스트를 저장하면 변경 사항이 상위 컨텍스트에 적용됩니다. 상위 컨텍스트를 저장하면 변경 사항이 유지됩니다.

자세한 설명 은 wwdc 2012 세션 214 를 참조하십시오 .


1
제안 해 주셔서 감사합니다! 필자는이 메서드를 nil 컨텍스트를 사용하는 것과 비교하여 테스트하는 데모를 작성했으며 적어도 OSX에서 nil 컨텍스트를 삽입하면 저장할 때 속성이 손실되었습니다. 데모 : github.com/seltzered/CoreDataMagicalRecordTempObjectsDemo
Vivek Gani

moc세 번째 스 니펫에는 어느 것이 있습니까? 그것은인가 childContext또는 myMangedObjectContext?
bugloaf

그것은 childContext입니다
철도 퍼레이드

이 솔루션은 nil 컨텍스트를 갖는 것보다 낫습니다.
Will Y

이후 NSManagedObject이 이미 관련을 제공합니다 NSManagedObjectContext: 당신은 문맥의 검색을 자동화 할 수 있습니다 NSManagedObject* objectRelatedContextually = [objectWithRelationship.managedObjectContext objectWithID:objectRelated.objectID];다음과 objectWithRelationship.relationship = objectRelatedContextually;.
Gary

9

이러한 종류의 작업을 수행하는 올바른 방법은 새로운 관리 개체 컨텍스트를 사용하는 것입니다. 동일한 영구 저장소를 사용하여 관리되는 개체 컨텍스트를 만듭니다.

NSManagedObjectContext *tempContext = [[[NSManagedObjectContext alloc] init] autorelease];
[tempContext setPersistentStore:[originalContext persistentStore]];

그런 다음 새 개체를 추가하고 변경합니다.

저장할 때가되면 tempContext에서 [tempContext save : ...]를 호출하고 저장 알림을 처리하여 원래 컨텍스트에 병합해야합니다. 객체를 버리려면이 임시 컨텍스트를 해제하고 잊어 버리십시오.

따라서 임시 컨텍스트를 저장하면 변경 사항이 스토어에 유지되며 해당 변경 사항을 기본 컨텍스트로 다시 가져 오면됩니다.

/* Called when the temp context is saved */
- (void)tempContextSaved:(NSNotification *)notification {
    /* Merge the changes into the original managed object context */
    [originalContext mergeChangesFromContextDidSaveNotification:notification];
}

// Here's where we do the save itself

// Add the notification handler
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(tempContextSaved:)
                                             name:NSManagedObjectContextDidSaveNotification
                                           object:tempContext];

// Save
[tempContext save:NULL];
// Remove the handler again
[[NSNotificationCenter defaultCenter] removeObserver:self
                                                name:NSManagedObjectContextDidSaveNotification
                                              object:tempContext];

이것은 다중 스레드 코어 데이터 작업을 처리해야하는 방법이기도합니다. 스레드 당 하나의 컨텍스트.

관계를 추가하기 위해이 임시 컨텍스트에서 기존 객체에 액세스해야하는 경우 객체의 ID를 사용하여 다음과 같은 새 인스턴스를 가져와야합니다.

NSManagedObject *objectInOriginalContext = ...;
NSManagedObject *objectInTemporaryContext = [tempContext objectWithID:[objectInOriginalContext objectID]];

NSManagedObject잘못된 컨텍스트에서 를 사용하려고하면 저장하는 동안 예외가 발생합니다.


두 번째 컨텍스트를 만드는 것은 NSManagedObjectContext메모리와 CPU 모두에서 비용이 많이 들기 때문에 매우 낭비 입니다. 나는 이것이 원래 일부 Apple 예제에 있음을 알고 있지만 해당 예제를 업데이트하고 수정했습니다.
Marcus S. Zarra

2
Apple은 CoreDataBooks 예제 코드에 대해이 기술 (두 번째 관리 개체 컨텍스트 생성)을 계속 사용하고 있습니다.
nevan king 2011

1
참고 Apple은 CoreDataBooks를 업데이트했지만 실제로 여전히 두 가지 컨텍스트를 사용하지만 이제 두 번째 컨텍스트는 첫 번째 컨텍스트의 자식입니다. 이 기술은 WWDC 2011 프레젠테이션 303 (iOS의 Core Data의 새로운 기능)에서 논의 (권장)되며 여기에 언급되어 있습니다 (변경 사항을 병합하기위한 훨씬 더 간단한 코드 포함) stackoverflow.com/questions/9791469/…
대황

4
"이를 위해 두 번째 컨텍스트를 만드는 것은 NSManagedObjectContext를 세우는 것이 메모리와 CPU 모두에서 비용이 많이 들기 때문에 매우 낭비입니다." . 아니, 그렇지 않습니다. 영구 저장소 코디네이터의 종속성 (관리 개체 모델 및 구체적인 저장소)은 컨텍스트가 아닙니다. 컨텍스트는 가볍습니다.
quellish

3
@quellish 동의합니다. Apple은 WWDC의 최근 핵심 데이터 성능 발표에서 컨텍스트 생성이 매우 가볍다 고 말했습니다.
Jesse

9

nil 컨텍스트에서 임시 객체를 만드는 것은 실제로 컨텍스트가! = nil 인 객체와 관계를 갖기 전까지는 잘 작동합니다!

괜찮은지 확인하십시오.


나는 괜찮 아니에요
찰리

8

당신이 설명하는 것은 정확히 무엇을위한 NSManagedObjectContext것입니다.

에서 코어 데이터 기본 사항 : 코어 데이터 프로그래밍 가이드

관리되는 개체 컨텍스트를 지능형 스크래치 패드로 생각할 수 있습니다. 영구 저장소에서 개체를 가져올 때 임시 복사본을 스크래치 패드로 가져와 개체 그래프 (또는 개체 그래프 모음)를 형성합니다. 그런 다음 원하는대로 이러한 개체를 수정할 수 있습니다. 그러나 실제로 이러한 변경 사항을 저장하지 않는 한 영구 저장소는 변경되지 않습니다.

핵심 데이터 프로그래밍 가이드 : 관리 개체 유효성 검사

이것은 또한 "스크래치 패드"를 나타내는 관리 객체 컨텍스트의 개념을 뒷받침합니다. 일반적으로 관리 객체를 스크래치 패드로 가져 와서 궁극적으로 변경 사항을 커밋하거나 삭제하기 전에 원하는대로 편집 할 수 있습니다.

NSManagedObjectContexts는 경량으로 설계되었습니다. 당신은 그것들을 마음대로 만들고 버릴 수 있습니다. 이것은 영구 저장소 조정자이며 "무거운"의존성입니다. 단일 영구 저장소 코디네이터는 이와 관련된 여러 컨텍스트를 가질 수 있습니다. 구식 스레드 제한 모델에서 이는 각 컨텍스트에 동일한 영구 저장소 코디네이터를 설정하는 것을 의미합니다. 오늘날 이는 중첩 된 컨텍스트를 영구 저장소 코디네이터와 연관된 루트 컨텍스트에 연결하는 것을 의미합니다.

컨텍스트를 만들고 해당 컨텍스트 내에서 관리되는 개체를 만들고 수정합니다. 이를 유지하고 변경 사항을 전달하려면 컨텍스트를 저장하십시오. 그렇지 않으면 폐기하십시오.

독립적으로 관리되는 개체를 만들려고하면 NSManagedObjectContext문제가 발생합니다. Core Data는 궁극적으로 개체 그래프에 대한 변경 추적 메커니즘입니다. 이 때문에 관리되는 개체는 실제로 관리되는 개체 컨텍스트의 일부입니다 . 문맥은 자신의 라이프 사이클을 관찰 하고, 문맥없이 모든 관리 객체의 기능이 제대로 작동합니다.


6

임시 개체의 사용에 따라 위의 권장 사항에 대한 몇 가지주의 사항이 있습니다. 내 사용 사례는 임시 개체를 만들고 뷰에 바인딩하려는 것입니다. 사용자가이 개체를 저장하도록 선택하면 기존 개체에 대한 관계를 설정하고 저장하려고합니다. 이러한 값을 유지하기 위해 임시 개체를 만드는 것을 방지하기 위해이 작업을 수행하고 싶습니다. (예, 사용자가보기 내용을 저장할 때까지 기다렸다가보기 내용을 가져올 수 있지만 이러한보기를 테이블 내부에 넣고이를 수행하는 논리가 덜 우아합니다.)

임시 개체에 대한 옵션은 다음과 같습니다.

1) (선호) 자식 컨텍스트에서 임시 개체를 만듭니다. 개체를 UI에 바인딩하고 개체 접근자가 자식 컨텍스트에서 호출된다는 것을 보장 할 수 없기 때문에 작동하지 않습니다. (다른 설명이있는 문서를 찾지 못 했으므로 가정해야합니다.)

2) nil 개체 컨텍스트로 임시 개체를 만듭니다. 이것은 작동하지 않으며 데이터 손실 / 손상을 초래합니다.

내 솔루션 : nil 객체 컨텍스트로 임시 객체를 생성하여이 문제를 해결했지만 객체를 # 2로 삽입하지 않고 저장할 때 모든 속성을 기본 컨텍스트에서 생성 한 새 객체에 복사합니다. NSManagedObject 하위 클래스에서 cloneInto :라는 지원 메서드를 만들었습니다.이 메서드를 사용하면 모든 개체에 대한 특성과 관계를 쉽게 복사 할 수 있습니다.


그게 제가 찾고있는 것입니다. 하지만 내 의심은 관계 속성을 어떻게 처리 할 것인가?
Mani

1

나를 위해 마커스의 대답이 작동하지 않았습니다. 나를 위해 일한 것은 다음과 같습니다.

NSEntityDescription entityForName:@"MyEntity" inManagedObjectContext:myMOC];
NSManagedObject *unassociatedObject = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];

그런 다음 저장하기로 결정한 경우 :

[myMOC insertObject:unassociatedObjet];
NSError *error = nil;
[myMoc save:&error];
//Check the error!

우리는 또한 그것을 해제하는 것을 잊지 말아야합니다

[unassociatedObject release]

1

나는이 대답을 다시 쓰고있다 질문에 대한 신속한 리디렉션에 대한 모든 유사한 질문으로 Swift에 대한 을 있습니다.

다음 코드를 사용하여 ManagedContext없이 개체를 선언 할 수 있습니다.

let entity = NSEntityDescription.entity(forEntityName: "EntityName", in: myContext)
let unassociatedObject = NSManagedObject.init(entity: entity!, insertInto: nil)

나중에 객체를 저장하기 위해 컨텍스트에 삽입하고 저장할 수 있습니다.

myContext.insert(unassociatedObject)
// Saving the object
do {
    try self.stack.saveContext()
    } catch {
        print("save unsuccessful")
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.