2013-03-05 4 views
5

UIDocument 기반 응용 프로그램에 NSFileWrapper을 사용하여 데이터를 저장합니다. 'master'파일 랩퍼에는 문서의 다른 페이지를 나타내는 많은 추가 디렉토리 파일 랩퍼가 들어 있습니다.저장 도중 파일 래퍼를 변경하는 동안 UIDocument 및 NSFileWrapper - NSFastEnumerationMutationHandler

UIDocument이 저장 중일 때 (예 : writeContents:andAttributes:safelyToURL:forSaveOperation:error:) 문서를 변경하면 앱이 다운됩니다.

UIDocument crash stack trace

내가 UIDocument 백그라운드에서 이상 열거되는 파일 래퍼의 동일한 인스턴스를 수정하고 명확 보인다 여기에 스택 추적입니다. 사실, 데이터 모델의 스냅 샷을 contentsForType:error:에 반환 할 때 반환 된 하위 파일 래퍼는 현재 데이터 모델에서 현재 상주하고있는 (편집중인) 객체와 동일한 객체를 가리키고 사본은 가리키지 않는지 확인했습니다.

- (id)contentsForType:(NSString *)typeName error:(NSError *__autoreleasing *)outError 
{ 
    if (!_fileWrapper) { 
     [self setupEmptyDocument]; 
    } 
    return [[NSFileWrapper alloc] initDirectoryWithFileWrappers:[_fileWrapper fileWrappers]]; 
} 

이이 방법 ( WWDC 2012 Session 218 - Using iCloud with UIDocument 항)을 구현하는 방식으로 허가된다.

그럼 제가 가정 해 봅시다 : 이 접근법은 어떻게 스레드 안전 할 수 있습니까?

마스터 파일 래퍼 fileWrappers 자체가 디렉토리 파일 래퍼 일 때 상황이 어떻게 다릅니 까? 허가 된 접근 방식이 잘못 되었다면 어떻게 해야합니까?

+0

이 상황이 발생하지 않았지만 NSFileCoordinator가 작업을 수행 할 수있는 것처럼 보입니까? –

+0

@MikeM 당신은 충돌을 막을 수 있다는 것이 맞을지 모르지만, 나는 그것이 일을 정말로 늦출 가능성이 있다고 걱정합니다. 종종 앱의 업데이트는 작지만 자주 발생하며 앱이 응답하기 위해서는 최신 콘텐츠가 필요합니다. 이 접근법을 자세히 조사하고 실행 가능한지 확인해야합니다. 그러나 문제는 여전히 남아 있습니다 - UIDocument 사용에 대한 승인 된 접근 방식은 스레드로부터 안전하지 않습니까? – Stuart

답변

6

writeContents:... 메서드 중 하나를 호출하는 경우에는 안됩니다. 대신 saveToURL:forSaveOperation:completionHandler:으로 전화해야합니다. writeContents:... 메서드는 고급 서브 클래 싱을위한 것입니다. 메인 쓰레드와 (당신이 UIDocument 더 서브 클래스, 당신은 를 통해에서 일을 할 수있다)은 "UIDocument 파일 액세스"스레드 -

UIDocument는 두 개의 스레드를 사용합니다.

UIDocument의 스레드 안전성은 Objective C의 모든 것과 비슷합니다. 객체를 소유하는 스레드 만이 스레드를 수정하게합니다. 변경하려는 오브젝트를 읽은 경우, 쓰기가 완료된 후 변경하도록 대기열에 넣으십시오. 아마도 UIDocument 하위 클래스가 소유하고있는 다른 객체를 변경하고 에 새로운 NSFileWrapper으로 가져 오면됩니다. fileWrappers NSDictionary의 사본을 전달하십시오.

NSFileWrapper은 실제로 전체 문서를 메모리에로드합니다. NSFileWrapper은 실제로 readFromURL:error: 메서드의 "UIDocument 파일 액세스"스레드에서 만들어지고 loadFromContents:ofType:error: 메서드에 전달됩니다. 큰 문서가 있으면 시간이 좀 걸릴 수 있습니다.

절약 할 때 일반적으로 UIDocument이 언제이를 수행할지 결정하고 updateChangeCount: 방법 (매개 변수는 UIDocumentChangeDone)을 통해 변경된 사항을 알리려고합니다. 지금 저장 하시려면 방법을 사용하고 싶다면 saveToURL:forSaveOperation:completionHandler: 방법을 사용하십시오.

UIDocumentNSFileCoordinator을 사용할 방법을 정의하는 NSFilePresenter 프로토콜을 구현합니다. UIDocument은 서브 파일이 아닌 루트 문서에서만 쓰기 작업을 조정합니다.문서 내의 서브 파일을 조정하면 도움이 될지도 모르겠지만, 충돌은 반복되는 동안 사전 변이와 관련되어 있으므로 도움이되지 않습니다. 당신은 (1) 파일 변경에 대한 알림을 얻고 싶거나 (2) 다른 파일이나 앱이 같은 파일을 읽고 쓰고 있었다면 자신의 NSFilePresenter을 쓰는 것에 대해 걱정할 필요가 있습니다. 무슨 UIDocument 이미 잘 작동합니다. 그러나 전체 문서를 이동/삭제할 때는 NSFileCoordinator을 사용하고 싶습니다.

+0

답장을 보내 주셔서 감사합니다. 이미 언급 한 내용 중 대부분을 이미 이해하고 있습니다 (단, 여기에 간결하게 명시 해 주셔서 감사합니다). 나는'writeContents : ...'를 오버라이드하고 미리보기 저장을 구현하기 위해 슈퍼 구현을 호출하고,'updateChangeCount :'를 사용하여 필요한 저장을 표시하고 있습니다. 나는 또한'UIDocument'가 파일 조정을 처리한다는 것을 알고 있지만, 루트 파일 래퍼에 대한 조화로운 작성은 서브 파일에 대한 조정을 의미하지는 않습니까? 파일 시스템 프로그래밍 안내서 : "참고 : NSFileWrapper 인스턴스가 조정 항목으로 지정되면 파일 래퍼 내의 모든 파일 ... – Stuart

+0

...이 자동으로 해당 파일 조정의 일부가됩니다." 나는 현재 별도의 데이터 객체를 사용하여 데이터를 저장하고있다. ('UIDocument' 하위 클래스가 소유 한'Page' 인스턴스에) 데이터를 저장하고 있지만 변경이 이루어 지자 마자 루트 파일 래퍼 아래에 새로운 파일 래퍼를 넣을 것이다. 애플의 CloudNotes 샘플 애플 리케이션에서 대기하고'contentsForType :'에 추가하기보다는 완료된다. 당신이 지적했듯이, 이것은 확실히 문제입니다. 나는'UIDocument'가 스냅 샷을 요청할 때까지 루트 파일 래퍼에 대한 업데이트를 연기하고, 모든 것이 잘 작동하는지 확인한다. 다시 한번 감사드립니다. – Stuart

+0

설명서가 혼란스럽고 이전처럼 문제가있었습니다. 그래서 나는 내가 할 수있는 한 많이 커버 할 것이라고 생각했다. 미리보기를 다른 곳에 저장하고 싶을 수도 있습니다. CloudNotes는 엉뚱한 일을합니다. 미리보기를 위해 두 번째 UIDocument를 저장합니다. 각 문서의 사본을 항상 지키지 않는 경우에만 그렇게해야합니다. 예. 루트 문서를 조정하면 하위 파일에도 적용 할 수 있지만, 알고있는 한 다른 앱/개체가 루트 문서를 조정한다고 가정합니다 (iCloud 및 UIDocument가이 작업을 수행함). – Luke