Question

I have a project with iCloud sync, but it doesn't work correctly at all. At first, I get an array of changed objects, then I convert them to CSV strings (which will be the contents of UIDocuments in cloud) and then I upload them to iCLoud. If I have less than 400 objects, everything is OK, but if I have more - app hangs.

I've tried to use local autorelease pool, I've split up large array to smaller ones. But it didn't help.

What is the best way for uploading a lot of UIDocuments into iCloud? My uploading method:

- (void)pushChangesToCloud:(NSArray *)changedObjects {

    for (ObjectClass *someObject in changedObjects) {
        NSURL *pathToSyncDoc = [[self urlForDocumentsFolderIniCloud] URLByAppendingPathComponent:someObject.name];

        CustomUIDocument *syncDoc = [[[CustomUIDocument alloc] initWithFileURL:pathToSyncDoc] autorelease];
        //   converting object to CSV string
        NSString *csvContents = [SomeClass convertObjectToCSV:someObject];      
        syncDoc.documentContent = csvContents;

        [syncDoc saveToURL:[syncDoc fileURL] 
          forSaveOperation:UIDocumentSaveForCreating 
         completionHandler:^(BOOL success) {
             if (success) {
                 NSLog(@"YAY!");
             } else {
                 NSLog(@" D: "); 
             }
         }];
    }
}

Thanks in advance and sorry for my English.

Was it helpful?

Solution

I finally figured out my problem, thanks to @Eimantas for his help. He was right about overloaded queue. Since "saveToUrl:forSaveOperation:completionHandler:" is i/o operation, queue created a lot of threads (for each UIDocument) and app hangs.

I overloaded "saveToUrl:forSaveOperation:completionHandler:" method in my custom UIDocument (to avoid saving docs in concurrent threads):

- (void)saveToURL:(NSURL *)url forSaveOperation:(UIDocumentSaveOperation)saveOperation completionHandler:(void (^)(BOOL))completionHandler {
NSError *contentsError = nil;
NSError *attributesError = nil;
NSError *savingError = nil;

[self writeContents:[self contentsForType:self.fileType error:&contentsError] andAttributes:[self fileAttributesToWriteToURL:url forSaveOperation:saveOperation error:&attributesError] safelyToURL:url forSaveOperation:saveOperation error:&savingError];

NSLog(@"SAVING ERRORS: contents error - %@, attributes error - %@, saving error - %@",[contentsError localizedDescription],  [attributesError localizedDescription], [savingError localizedDescription]);
}

Then I used my own serial queue to execute all save operations. At first, you need to add it like an iVar:

dispatch_queue_t mySerialQueue;

Then create it in init method:

myCustomQueue = dispatch_queue_create("com.whatever.MyAwesomeQueue", DISPATCH_QUEUE_SERIAL);

use it for saving:

dispatch_async(mySyncQueue, ^{
    // do saving stuff
});

and then release it in dealloc:

dispatch_release(mySyncQueue);

After this changes I don't have any problems with it.

Hope this helps! (and sorry for my English :>)

OTHER TIPS

Dmitry, the way that you override saveToURL: is unsafe. The default implementation of UIDocument saveToURL will use file coordination to make sure that the ubiquity daemon knows what and when you're writing to disk. Your implementation does no file coordination, unless you're file coordinating in writeContents:, (which you shouldn't be).

See the discussion section of UIDocument's saveToURL docs at: https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIDocument_Class/UIDocument/UIDocument.html#//apple_ref/occ/instm/UIDocument/saveToURL:forSaveOperation:completionHandler:

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top