0

I am trying to open several UIDocument instances in a loop, using - (void)openWithCompletionHandler:(void (^)(BOOL success))completionHandler.

To be precise, I am loading a file list from the document folder, and each file representing a user which can log in into my app. Now, obviously I want to show my login dialog after all the users / UIDocument were opened. Unfortunately I can't seem to come up with a good approach for this. What I am having is:

 -(void)reloadUsers
 {
     __block int cnt= 0;

     NSArray* localDocuments = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[[AppDelegate localDocumentsDirectoryURL] path] error:nil];

     for (NSString* document in localDocuments)
     {
        if (![document hasSuffix:@".user"])
           continue;

        // User beeing UIDocument subclass

        User* user=[[[User alloc] initWithFileURL:[NSURL fileURLWithPath:[[[AppDelegate localDocumentsDirectoryURL] path]
                                                                       stringByAppendingPathComponent:document]]] autorelease];

        NSLog(@"Opening user document at url '%@'/'%@' ...", [AppDelegate localDocumentsDirectoryURL], document);

        [user openWithCompletionHandler:^(BOOL success)
        {
           [self.userList addObject:user];

           cnt++;
        }];
     }

     NSLog(@"Loaded %d local users", cnt);
  }

Question 1: will the NSLog at the end even work and show the actual number of users loaded, or will it be a random value since the cnt++ is done asynchroneously?

Question 2: How can I change the above function so that I can safely do the following:

 {   // app finished loading

    [MyClass reloadUsers];

    [LoginDialog show];    // this shall happen AFTER reloadUsers has loaded ALL documents
 }
rmaddy
  • 314,917
  • 42
  • 532
  • 579
user826955
  • 3,137
  • 2
  • 30
  • 71
  • You could use a delegate method. When `cnt` (actually, doing the NSLog in the blog could be a better thing for understanding) is equal to the number of files you want to open, you could tell your object to do `[LoginDialog show]`. Not that in your block you should read the `success` bool value. – Larme Apr 13 '14 at 15:43
  • I found this http://jamiepinkham.com/post/9046964416/synchronizing-asynchronous-tasks-in-objective-c-using, but actually I am pretty confused why he calls `dispatch_group_wait` in a loop, rather then once in the end?! – user826955 Apr 14 '14 at 16:40

1 Answers1

1

I find that turning loops into recursions is a useful method for serializing async operations. For example (this is some notepad programming and may not compile, but you get the idea):

This function loads all the documents recursively and then calls a completion handler:

- (void)loadDoc:(int)doc in:(NSArray*)localDocuments withCompletion:(void(^)(void))completion
{
    if (doc == [localDocuments count])
    {
        completion();
    }
    else
    {
        NSString* document = localDocuments[doc];

        if (![document hasSuffix:@".user"])
        {
            [self loadDoc:doc + 1 in:localDocuments withCompletion:completion];
        }
        else 
        {

            User* user=[[[User alloc] initWithFileURL:[NSURL fileURLWithPath:[[[AppDelegate localDocumentsDirectoryURL] path]
                                                                           stringByAppendingPathComponent:document]]] autorelease];
            [user openWithCompletionHandler:^(BOOL success)
            {
                [self.userList addObject:user];
                [self loadDoc:doc + 1 in:localDocuments withCompletion:completion];
            }];
        }
    }
}

For convenience:

-(void)reloadUsersWithCompletion:(void(^)(void))completion
{

    NSArray* localDocuments = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[[AppDelegate localDocumentsDirectoryURL] path] error:nil];
    [self loadDoc:0 in:localDocuments withCompletion:completion];
}

And your showing your dialog:

{   // app finished loading

    [MyClass reloadUsersWithCompletion:^(void) {

        [LoginDialog show];    // this shall happen AFTER reloadUsers has loaded ALL documents
    }];
}

Of course there are other methods involving threading and synchronization mechanisms, but they are not as simple in my opinion.

Hila
  • 1,080
  • 1
  • 9
  • 22