2013-10-07 10 views
13

파일 래퍼를 사용하여 데이터를 저장하고로드하는 NSDocument 기반 응용 프로그램이 있습니다. 문서에 모든 종류의 리소스가있을 수 있으므로 모든 것을 메모리에로드하고 싶지는 않습니다. 나는 근본적으로 잘못된 것을하고 있을지 모르지만, 하나의 (내부) 파일을 변경하고 저장하면 바로 메모리에로드되지 않은 파일을 읽을 수 없습니다.NSFileWrapper, 지연로드 및 저장

이 문제를 재현하기 위해 관련 코드를 별도의 프로젝트로 구분했으며 동일한 결과를 얻었습니다. 기본 흐름은 다음과 같습니다.

  • 디스크에서 기존 문서를로드합니다. 주 fileWrapper는 두 개의 다른 파일 래퍼 (sub1sub2)가 포함 된 디렉토리 파일 래퍼입니다 (메인). 두 개의 내부 파일 래퍼는 이 아니고 현재이 아닙니다.
  • 사용자가 하위 1을 편집하려고하면 디스크에서로드됩니다. 사용자가 다른 파일 (SUB2)을 편집하고자하는 경우
  • 사용자가 문서를
  • 을 저장, 그것은로드 할 수 없습니다. 나타나는 오류 : 여기

    -[NSFileWrapper regularFileContents] tried to read the file wrapper's contents lazily but an error occurred: The file couldn’t be opened because it doesn’t exist. 
    

내 프로젝트의 관련 코드입니다 :

이 코드는이 요점에서 쉽게 읽을 수 있습니다 : https://gist.github.com/bob-codingdutchmen/6869871

#define FileName01 @"testfile1.txt" 
#define FileName02 @"testfile2.txt" 

/** 
* Only called when initializing a NEW document 
*/ 
-(id)initWithType:(NSString *)typeName error:(NSError *__autoreleasing *)outError { 
    self = [self init]; 
    if (self) { 
     self.myWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil]; 

     NSLog(@"Initializing new document..."); 

     NSString *testString1 = @"Lorem ipsum first sub file"; 
     NSString *testString2 = @"This is the second sub file with completely unrelated contents"; 

     NSFileWrapper *w1 = [[NSFileWrapper alloc] initRegularFileWithContents:[testString1 dataUsingEncoding:NSUTF8StringEncoding]]; 
     NSFileWrapper *w2 = [[NSFileWrapper alloc] initRegularFileWithContents:[testString2 dataUsingEncoding:NSUTF8StringEncoding]]; 

     w1.preferredFilename = FileName01; 
     w2.preferredFilename = FileName02; 

     [self.myWrapper addFileWrapper:w1]; 
     [self.myWrapper addFileWrapper:w2]; 

    } 
    return self; 
} 

-(NSFileWrapper *)fileWrapperOfType:(NSString *)typeName error:(NSError *__autoreleasing *)outError { 

    // This obviously wouldn't happen here normally, but it illustrates 
    // how the contents of the first file would be replaced 
    NSFileWrapper *w1 = [self.myWrapper.fileWrappers objectForKey:FileName01]; 
    [self.myWrapper removeFileWrapper:w1]; 

    NSFileWrapper *new1 = [[NSFileWrapper alloc] initRegularFileWithContents:[@"New file contents" dataUsingEncoding:NSUTF8StringEncoding]]; 
    new1.preferredFilename = FileName01; 

    [self.myWrapper addFileWrapper:new1]; 

    return self.myWrapper; 
} 

-(BOOL)readFromFileWrapper:(NSFileWrapper *)fileWrapper ofType:(NSString *)typeName error:(NSError *__autoreleasing *)outError { 
    self.myWrapper = fileWrapper; 
    return YES; 
} 

- (IBAction)button1Pressed:(id)sender { 
    // Read from file1 and show result in field1 
    NSFileWrapper *w1 = [[self.myWrapper fileWrappers] objectForKey:FileName01]; 
    NSString *string1 = [[NSString alloc] initWithData:w1.regularFileContents encoding:NSUTF8StringEncoding]; 
    [self.field1 setStringValue:string1]; 
} 

- (IBAction)button2Pressed:(id)sender { 
    // Read from file2 and show result in field2 
    NSFileWrapper *w2 = [[self.myWrapper fileWrappers] objectForKey:FileName02]; 
    NSString *string2 = [[NSString alloc] initWithData:w2.regularFileContents encoding:NSUTF8StringEncoding]; 
    [self.field2 setStringValue:string2]; 
} 

아래 두 가지 방법은 UI를 업데이트하기위한 것이므로 어떤 일이 발생하는지 볼 수 있습니다.

  • 파일 내용을 변경하려면 기존 FileWrapper를 제거하고 새 파일을 추가하십시오. 이것은 내가 파일의 내용을 바꾸는 것을 발견 한 유일한 방법이며 다른 SO 응답에서 본 것을 본 방식입니다. 문서가 디스크에서로드

  • , 나는 애플의 문서가 NSFileWrapper 게으른 로딩을 지원하는 것을 말한다

(위의 코드에 myWrapper라고도 함) 내가 사용할 수 있도록 주위에 fileWrapper을 유지 증분 절약, 그래서 내 코드는 내가 볼 수없는 근본적인 결함이 있다고 가정합니다.

+0

문서가 버전 관리를 지원합니까? –

+0

나는 잘 모르겠다. 나는 그렇게 생각하지 않는다. 나는 그것을 지원하기 위해 아무것도하지 않았다. 그것은 아무것도 바꿀까요? 나중에 다시 살펴 보겠습니다. –

+1

NSDocument 설정을 사용하면서 버전 관리를 지원하고있었습니다. 나는 끄기 위해 노력했지만 결과는 동일합니다 –

답변

1

NSFileWrapper는 본질적으로 유닉스 파일 노드를 둘러싼 래퍼입니다. 파일이 이동되면 랩퍼는 계속 유효합니다.

요즘 문제는 저장하는 동안 새 파일 래퍼를 만드는 것이 새로운 폴더라는 것입니다. 그리고 시스템은 sub2을 포함하여 이전 랩퍼를 h 제합니다.

증분 저장 (예 : 변경된 부품 만 제자리에 저장)으로 변경해야하는 항목을 얻으려면 NSDocument에서 "제자리에 저장"을 참조하십시오.

1

-fileWrapperOfType:error: 메서드에서 변경된 멤버에 대한 새 내용이 포함 된 새 파일 래퍼를 작성하고 변경되지 않은 멤버에 대한 이전 파일 래퍼를 참조하십시오. addFileWrapper에 문서에 따라

0

: 파일 이름 1 디렉토리/파일 이름 1/

  • addfileWrapper : 당신이 아이 (하위 디렉토리)를 추가 그것에는

    디렉토리/

    1. addfileWrapper을 의미 fileName2을 디렉토리/fileName1/fileName2 해당 파일이 존재하지 않습니다. preferredFilename : 대신

    당신은 addRegularFileWithContents을 사용해야합니다.