2012-10-16 20 views
9

Sto usando NSFileWrapper per il mio documento del pacchetto. A volte, quando richiedo i dati di un file all'interno del pacchetto ottengo nil.NSFileWrapper restituisce nil, a volte

Questo è quanto ho interrogare i dati di un file all'interno del pacchetto:

- (NSData*) dataOfFile(NSString*)filename { 
    NSFileWrapper *fileWrapper = [self.documentFileWrapper.fileWrappers objectForKey:filename]; 
    return fileWrapper.regularFileContents; // This returns nil sometimes. Why? 
} 

Questo metodo finalmente inizia il ritorno a zero per alcuni file (non tutti). Purtroppo, non sono riuscito a riprodurre il problema in modo coerente.

In caso aiuta, questo è come apro il pacchetto:

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

Questo è quanto ho aggiornare i dati di un file all'interno del pacchetto:

- (void) updateFile:(NSString*)filename withData:(NSData*)data { 
    SBFileWrapper *fileWrapper = [self.documentFileWrapper.fileWrappers objectForKey:filename]; 
    if (fileWrapper) { 
     [self.documentFileWrapper removeFileWrapper:fileWrapper]; 
    } 
    NSFileWrapper *fileWrapper = [[SBFileWrapper alloc] initRegularFileWithContents:data ]; 
    fileWrapper.preferredFilename = filename; 
    [self.documentFileWrapper addFileWrapper:fileWrapper]; 
} 

Questo è il modo risparmio il pacchetto:

- (NSFileWrapper*) fileWrapperOfType:(NSString *)typeName error:(NSError *__autoreleasing *)outError { 
    return self.documentFileWrapper; 
} 

Perché questo può accadere? C'è un modo per prevenirlo?

La documentazione di regularFileContents sembra di parlare di questo problema:

This method may return nil if the user modifies the file after you call readFromURL:options:error: or initWithURL:options:error: but before NSFileWrapper has read the contents of the file. Use the NSFileWrapperReadingImmediate reading option to reduce the likelihood of that problem.

Ma io non capisco cosa deve essere cambiato nel codice qui sopra per evitare questa situazione.

esperimenti falliti

Ho cercato di salvare il documento se regularFileContents ritorno pari a zero, ma restituisce comunque pari a zero in seguito. In questo modo:

- (NSData*) dataOfFile(NSString*)filename { 
    NSFileWrapper *fileWrapper = [self.documentFileWrapper.fileWrappers objectForKey:filename]; 
    NSData *data = fileWrapper.regularFileContents; 
    if (!data) { 
      [self saveDocument:nil]; 
      fileWrapper = [self.documentFileWrapper.fileWrappers objectForKey:filename]; 
      data = fileWrapper.regularFileContents; 
    } 
    return data; 
} 
+0

Questa è una ipotesi pazzesca, ma mi chiedo se riflettori stia modificando gli attributi del file dopo il salvataggio (come reindicizza il file o qualcosa del genere)? Sono un po 'curioso perché stai salvando dopo che fallisce; perché non riaprirlo invece? Sto solo cercando di darti qualche idea. – Dad

+0

Immaginazione selvaggia, ma penso che il tuo oggetto venga rilasciato. Forse qualcosa va storto con l'alloc. Hai provato un'analisi? Fai attenzione con alloc e init (e self. + Autorelease e release). – Roger

risposta

3

Non c'è abbastanza codice per vedere cosa sta realmente accadendo. Tuttavia, la causa principale è che NSFileWrapper è esattamente ciò che implica il nome: un oggetto che rappresenta un file o una directory. Pertanto, il file o la directory corrente possono facilmente ottenere "fuori sincronia" con l'oggetto, che vive nella memoria. Ogni volta che NSFileWrapper determina che ciò si è verificato, restituisce nil per determinate operazioni. La soluzione è rendere gli oggetti NSFileWrapper di breve durata. Crea e apri quando ne hai bisogno, quindi salva e chiudi il prima possibile.

In particolare, sembra che il codice stia mantenendo un puntatore su un wrapper di directory di pacchetti per un lungo periodo e presupponendo che sia sempre valido. Se la directory cambia per qualsiasi motivo, questo non è il caso. Ricodifica in modo da ottenere un nuovo wrapper di directory del pacchetto ogni volta che ne hai bisogno e il problema dovrebbe scomparire.

0

Se il file cambia su disco, si otterrà zero (come dice @Gene). Tuttavia, è possibile controllare questo utilizzando matchesContentsOfURL: metodo:

determines whether a disk representation may have changed, based on the file attributes stored the last time the file was read or written. If the file wrapper’s modification time or access permissions are different from those of the file on disk, this method returns YES. You can then use readFromURL:options:error:

Questo dal Working with File Wrappers documentazione Apple.

Nota questo dal intro a quella sezione:

Because the purpose of a file wrapper is to represent files in memory, it’s very loosely coupled to any disk representation. A file wrapper doesn’t record the path to the disk representation of its contents. This allows you to save the same file wrapper with different URLs, but it also requires you to record those URLs if you want to update the file wrapper from disk later.

quindi dovrete salvare l'URL del file originale, se si desidera/bisogno di rileggerlo.

Essere interessanti per sapere cosa restituisce matchesContentsofURL: quando si visualizzano risultati nulli.