1

I have an import sequence that reads from an archive, unzips the containing files and creates corresponding core data entities for each. This entire process happens in the background and a separate context has been created for each thread etc. so it all works fine.

It turns out that a desirable feature of this particular import sequence is that we allow any of the input files to be password protected (there are several of them included in an archive) so I need to check whether a file is password protected in which case the user will be prompted to enter the password via a UIAlertView.

This is where my problem starts.

I send the UIAlertView prompt to the main thread as I should, assign my Importer object as the delegate and wait for the user input.

When the user enters the password and taps OK/Cancel the delegate callback is still on the main thread so I am unable to manipulate my corresponding core data entity anymore without a lot of work (i.e. storing references to the managed object ID etc, creating new context etc).

My question:

Is it possible to go back my original background thread where the import process is working? How would I go about it?

Thanks, Rog

Haroldo Gondim
  • 7,725
  • 9
  • 43
  • 62
Rog
  • 18,602
  • 6
  • 76
  • 97
  • Could your importer keep a reference to its thread using `[NSThread currentThread]` and then, in the delegate callback, use `performSelector:onThread:withObject:waitUntilDone:` to pass the password back to the importer's thread? – Christopher Pickslay Oct 19 '12 at 06:01
  • 1
    I would check all of the files for passwords before I started to process them, and ask for the passwords up front. That way, if I am doing a long import, I can start it and walk away without coming back an hour later expecting it to be done, and find it is on the third file waiting for me to enter a password.... – lnafziger Oct 21 '12 at 19:21

1 Answers1

3

I'd try using a dispatch semaphore. Save it in an instance variable.

@interface MyClass ()
{
    dispatch_semaphore_t dsema;
}
@end

Then, in the background thread method:

// this is the background thread where you are processing the archive files
- (void)processArchives
{
    ...
    self.dsema = dispatch_semaphore_create(0);
    dispatch_async(dispatch_get_main_queue(), ^{
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle: @"Title"
                                                                ...
                                                           delegate: self
                                                                ...
        ];
        [alertView show];
    });

    dispatch_semaphore_wait(self.dsema, DISPATCH_TIME_FOREVER);
    // --> when you get here, the user has responded to the UIAlertView <--

    dispatch_release(self.dsema);
    ...
}

The UIAlertView will invoke this delegate method:

// this is running on the main queue, as a method on the alert view delegate
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    // do stuff with alertView
    if (buttonIndex == [alertView firstOtherButtonIndex]) {
        ...
        // when you get the reply that should unblock the background thread, unblock the other thread:
        dispatch_semaphore_signal(self.dsema);
        ...
    }
}
Poulsbo
  • 648
  • 5
  • 18