2012-04-04 19 views
2

Ich arbeite an meiner ersten iCloud App. Nach einiger Zeit kann die App aufgrund eines "UIDocumentStateSavingError" nicht mehr auf ein UIManagedDocument zugreifen. Gibt es eine Möglichkeit, herauszufinden, welcher Fehler aufgetreten ist?UIManagedDocument - Wie behandelt man UIDocumentStateSavingError?

Dies ist mein Code die UIManagedDocument zu erstellen:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    iCloudURL = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil]; 

    if (iCloudURL == nil) { 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      [self iCloudNotAvailable]; 
     }); 
     return; 
    } 


    iCloudDocumentsURL = [iCloudURL URLByAppendingPathComponent:@"Documents"]; 
    iCloudCoreDataLogFilesURL = [iCloudURL URLByAppendingPathComponent:@"TransactionLogs"]; 

    NSURL *url = [iCloudDocumentsURL URLByAppendingPathComponent:@"CloudDatabase"]; 
    iCloudDatabaseDocument = [[UIManagedDocument alloc] initWithFileURL:url]; 

    NSMutableDictionary *options = [NSMutableDictionary dictionary]; 

    NSString *name = [iCloudDatabaseDocument.fileURL lastPathComponent]; 
    [options setObject:name forKey:NSPersistentStoreUbiquitousContentNameKey]; 
    [options setObject:iCloudCoreDataLogFilesURL forKey:NSPersistentStoreUbiquitousContentURLKey]; 

    iCloudDatabaseDocument.persistentStoreOptions = options; 

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(documentContentsChanged:) name:NSPersistentStoreDidImportUbiquitousContentChangesNotification object:iCloudDatabaseDocument.managedObjectContext.persistentStoreCoordinator]; 
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(documentStateChanged:) name:UIDocumentStateChangedNotification object:iCloudDatabaseDocument]; 


    if ([[NSFileManager defaultManager] fileExistsAtPath:[iCloudDatabaseDocument.fileURL path]]) { 
     // This is true, the document exists. 
     if (iCloudDatabaseDocument.documentState == UIDocumentStateClosed) { 
      [iCloudDatabaseDocument openWithCompletionHandler:^(BOOL success) { 
       if (success) { 
        dispatch_async(dispatch_get_main_queue(), ^{ 
         [self documentConnectionIsReady]; 
        }); 
       } else { 
        dispatch_async(dispatch_get_main_queue(), ^{ 
         [self connectionError:iCloudConnectionErrorFailedToOpen]; 
        }); 
       } 
      }];      
     } else if (iCloudDatabaseDocument.documentState == UIDocumentStateNormal) { 
      ... 
     }  
    } else { 
     ...    
    }   
}); 

Das Dokument ist bereits vorhanden und somit openWithCompletionHandler: auf dem Dokument genannt. Dies schlägt fehl, und die UIDocumentStateChangedNotification wird ausgelöst, die ein Dokument Zustände von 5 zeigt: UIDocumentStateClosed und UIDocumentStateSavingError

Danach wird der Abschluss Block aufgerufen wird. Was ist der richtige Weg, um von hier fortzufahren? Gibt es eine Möglichkeit herauszufinden, was schief gelaufen ist und welche Art von Fehler aufgetreten ist?

Ich habe versucht, das Dokument im Completion-Block erneut zu öffnen, aber das Ergebnis ist das gleiche.

Ich denke, ich könnte das Problem lösen, indem Sie einfach die Datei löschen und neu erstellen. Aber das ist natürlich keine Option, sobald die App im Laden ist. Ich würde gerne wissen, was schief läuft und dem Benutzer eine Möglichkeit geben, mit dem Problem umzugehen.

Ich habe bereits andere Fragen hier mit der UIDocumentStateSavingError (es gibt nicht viele) überprüft, aber die scheinen nicht für das Problem hier anwendbar.

Irgendeine Idee, wie ich herausfinden kann, was das Problem ist? Ich kann nicht glauben, dass die API Ihnen sagt: "Beim Speichern ging etwas schief, aber ich werde Ihnen nicht sagen, was!"

Antwort

5

Sie können den DocumentState im Beendigungshandler abfragen. Leider, wenn Sie die genauen Fehler wollen, bekommt die einzige Art und Weise ist es handleUnterKlasse und überschreibt: userInteractionPermitted:

Vielleicht so etwas wie dies helfen würde (typisierte freihändig ohne Compiler) ...

@interface MyManagedDocument : UIManagedDocument 
- (void)handleError:(NSError *)error 
     userInteractionPermitted:(BOOL)userInteractionPermitted; 
@property (nonatomic, strong) NSError *lastError; 
@end 

@implementation MyManagedDocument 
@synthesize lastError = _lastError; 
- (void)handleError:(NSError *)error 
     userInteractionPermitted:(BOOL)userInteractionPermitted 
{ 
    self.lastError = error; 
    [super handleError:error 
      userInteractionPermitted:userInteractionPermitted]; 
} 
@end 

dann können Sie es wie folgt erstellen können ...

iCloudDatabaseDocument = [[UIManagedDocument alloc] initWithFileURL:url]; 

und verwenden Sie es im Abschluss-Handler wie folgt ...

 [iCloudDatabaseDocument openWithCompletionHandler:^(BOOL success) { 
      if (success) { 
       dispatch_async(dispatch_get_main_queue(), ^{ 
        [self documentConnectionIsReady]; 
       }); 
      } else { 
       dispatch_async(dispatch_get_main_queue(), ^{ 
        [self connectionError:iCloudConnectionErrorFailedToOpen 
           withError:iCloudDatabaseDocument.lastError]; 
       }); 
      } 
     }];      
1

Basierend auf @ JodyHagins Excellent Snippet, habe ich eine UIDocument-Unterklasse erstellt.

@interface SSDocument : UIDocument 
- (void)openWithSuccess:(void (^)())successBlock 
      failureBlock:(void (^)(NSError *error))failureBlock; 
@end 


@interface SSDocument() 
@property (nonatomic, strong) NSError *lastError; 
@end 

@implementation SSDocument 

- (void)handleError:(NSError *)error userInteractionPermitted:(BOOL)userInteractionPermitted { 
    self.lastError = error; 
    [super handleError:error userInteractionPermitted:userInteractionPermitted]; 
} 

- (void)clearLastError { 
    self.lastError = nil; 
} 

- (void)openWithSuccess:(void (^)())successBlock failureBlock:(void (^)(NSError *error))failureBlock { 
    NSParameterAssert(successBlock); 
    NSParameterAssert(failureBlock); 
    [self clearLastError]; 
    [self openWithCompletionHandler:^(BOOL success) { 
     if (success) { 
      successBlock(); 
     } else { 
      NSError *error = self.lastError; 
      [self clearLastError]; 
      failureBlock(error); 
     } 
    }]; 
} 

@end 
Verwandte Themen