Search code examples
iosmemory-managementsynchronizationiclouduidocument

Large array of UIDocuments for iCloud


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.


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 :>)