0

I've been trying to figure this out for 2 days now, and before anyone posts another stackoverflow question, I've read them all and none of them cover my problem exactly:

I have a CoreData app that updates dynamically. Now during the update I want an UIAlertView to pop up saying that an update is being downloaded.

So here's the important code:

AppDelegate:

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    [myUpdater checkForUpdatesInContext:self.managedObjectContext];    
}

_

Updater Class:

- (void)checkForUpdatesInContext:(NSManagedObjectContext *)myManagedObjectContext
{
    [self loadUpdateTime];
    NSLog(@"Update start");
    NSDate *now = [NSDate dateWithTimeIntervalSinceNow:[[NSTimeZone localTimeZone] secondsFromGMT]];
    if ([now timeIntervalSinceDate:updateTime] < UPDATE_TIME_INTERVAL)
    {
        return;
    }
    [self showAlertViewWithTitle:@"Update"];
    ... //updating process
    [self.alertView dismissWithClickedButtonIndex:0 animated:YES];
    NSLog (@"Update done");
}

- (void) showAlertViewWithTitle:(NSString *)title
{
    self.alertView = [[UIAlertView alloc] initWithTitle:title message:@"Daten werden aktualisiert..." delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
    ... //design the alertView
    [self.alertView show];
    NSLog (@"AlertView shows");
}

So here is what happens when I run this:

  1. Launch image shows
  2. NSLog "Update starts" fires
  3. NSLog "AlertView shows" fires
  4. Screen dims but no AlertView is shown
  5. Update is running
  6. NSLog "Update done" fires
  7. Launch image goes away and TabBarController shows up
  8. UIAlertView shows up and is dismissed right away and the dimmed screen returns to normal

What I would like to have happen:

  1. Launch image
  2. TabBarController shows up
  3. Screen dims and UIAlertView shows
  4. Update is running
  5. UIAlertView gets dismissed and dimmed screen returns to normal

I know it's something with the UI Thread and the main Thread and stuff.. But I tried every combination it seems but still not the expected result. Please help :)

EDIT:

HighlightsViewController Class:

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.updater = [[Updater alloc] init];
    [updater checkForUpdatesInContext:self.managedObjectContext];

    ... // other setup stuff nothing worth mentioning
}

Is this the right place to call [super viewDidLoad]? Because it still doesn't work like this, still the update is being done while the Launch Image is showing on the screen. :-(( I'm about to give this one up..

Octoshape
  • 1,131
  • 8
  • 26
  • Does `... //updating process` is running in separate thread? – Nekto Oct 06 '11 at 08:52
  • No, everything is run in there. I want the user not to be able to do anything during the update, hence the UIAlertView – Octoshape Oct 06 '11 at 08:53
  • I think that is where you have a problem. – Nekto Oct 06 '11 at 08:56
  • Hmm I think I have tried that before.. let me change my code, and I'll post as an edit to see if that's what you meant .. – Octoshape Oct 06 '11 at 08:59
  • If I add the BOOL it's back to the old behavior again, but I think Totumus Maximus has found the problem. Since I use applicationDidBecomeActive there is no view that can show the UIAlertView so it is actually showing but the user cant see it yet because there is no view on the screen – Octoshape Oct 06 '11 at 09:10

3 Answers3

1

Here you go, in this prototype things work exactly how you want them to.

Header:

#import <UIKit/UIKit.h>

@interface AlertViewProtoViewController : UIViewController
{

}

- (void) showAlertViewWithTitle:(NSString *)title;
- (void) checkForUpdatesInContext;
- (void) update;
- (void)someMethod;
- (void)someOtherMethod;

@end

#import "AlertViewProtoViewController.h"

Class:

@implementation AlertViewProtoViewController

UIAlertView *alertView;
bool updateDone;
UILabel *test;
bool timershizzle;

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    self.view.backgroundColor = [UIColor yellowColor];

    UILabel *test = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 500, 500)];
    test.backgroundColor = [UIColor blueColor];
    [self.view addSubview:test];

    [self performSelector:@selector(checkForUpdatesInContext) withObject:nil afterDelay:0.0];
}


- (void)update
{
    //NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; //commented for auto ref counting
    NSLog(@"update start");
    //your update stuff
    NSLog(@"update end");
    updateDone = YES;
    //[pool release];
}

- (void)checkForUpdatesInContext//:(NSManagedObjectContext *)myManagedObjectContext
{
    //[self loadUpdateTime];

    NSLog(@"Update start");

    NSDate *now = [NSDate dateWithTimeIntervalSinceNow:[[NSTimeZone localTimeZone] secondsFromGMT]];
    //    if ([now timeIntervalSinceDate:updateTime] < UPDATE_TIME_INTERVAL)
    //    {
    //        return;
    //    }
    [self showAlertViewWithTitle:@"Update"];
    //[self setManagedObjectContext:myManagedObjectContext];

    [self performSelector:@selector(someMethod) withObject:nil afterDelay:0.0];

    [self performSelector:@selector(someOtherMethod) withObject:nil afterDelay:0.0];
}

-(void)someOtherMethod
{
    while (!updateDone) {
        //        NSLog(@"waiting...");
    }

    [alertView dismissWithClickedButtonIndex:0 animated:YES];
    NSLog (@"Update done");
    self.view.backgroundColor = [UIColor greenColor];
}

-(void)someMethod
{
    [self performSelectorInBackground:@selector(update) withObject:nil];
}

- (void) showAlertViewWithTitle:(NSString *)title
{
    alertView = [[UIAlertView alloc] initWithTitle:title message:@"Daten werden aktualisiert..." delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
    alertView.frame = CGRectMake(100, 100, 200, 200);
    alertView.backgroundColor = [UIColor whiteColor];

    [self.view addSubview:alertView];

    [self.view setNeedsDisplay];

    NSLog (@"AlertView shows");
}

@end

You should adjust were needed for your own purposes but it works.

dandan78
  • 13,328
  • 13
  • 64
  • 78
Totumus Maximus
  • 7,543
  • 6
  • 45
  • 69
  • I just got done and it works too.. oh the irony! But instead of the while loop for waiting I'm using NSNotification to trigger the dismissal of the `UIAlertView` but without your help I wouldn't have been able to find out that the underlying issue was the missing view for the AlertView to show up! Thank you so much for all your effort! A really well deserved correct answer! – Octoshape Oct 06 '11 at 13:29
  • Like Paul said tight loops for delays should be avoided, and the `NSNotification` system is quite easy to use once you gotten used to it. You should check it out yourself! I mainly used [this](http://stackoverflow.com/questions/2191594/how-to-send-and-receive-message-through-nsnotificationcenter-in-objective-c/2191802#2191802) example! – Octoshape Oct 06 '11 at 13:31
0

You are doing a:

- (void)applicationDidBecomeActive:(UIApplication *)application

Isn't it so that the alertview you want to show needs a view to be loaded which isn't active yet at this point? See: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIAlertView_Class/UIAlertView/UIAlertView.html

Similar question? UIAlertView starts to show, screen dims, but it doesn't pop up until it's too late!

Community
  • 1
  • 1
Totumus Maximus
  • 7,543
  • 6
  • 45
  • 69
  • That sounds like the right idea. Do you know if there is a way to get around this then? The problem is: I want to check regularly for an update, and in the update method itself, I check whether it's been a day already. So I figured I put the update checking into the DidBecomeActive method so it gets called every time the user opens the app (again or from scratch) – Octoshape Oct 06 '11 at 09:12
  • About the similar question, it is the right/"same" question but apparently I'm dealing with a view issue here because of the DidBecomeActive method – Octoshape Oct 06 '11 at 09:13
  • well since you want the alertview to show during the update I would put the whole function in the viewdidload-method. You will keep getting back to the same view issue everytime you restart your app. In your case you could make a view inbetween you splash and your main-app to cover for this problem. You could make it have the same background as your splashscreen so the user won't notice the difference between them. When this inbetweenView has loaded you can safely show your alertview. – Totumus Maximus Oct 06 '11 at 09:21
  • Hmm .. that was my idea too, so I tried putting the update into the first view controller that is showing in my tabbarcontroller and I put it into the `viewDidLoad` method but the update is still running during the launch image, and it's not called anywhere else, because if I comment that call in the `viewDidLoad` method, the update doesn't run at all. I also tried putting it into `viewDidAppear` but still it runs on the Launch Image.. why are those methods called before the actual view appears? this seems like a bug? – Octoshape Oct 06 '11 at 09:29
  • have you tried loadView? And have you done the call to its super (like this: [super viewDidLoad]; properly?) Have you checked the UIViewController part of you iOS lib? – Totumus Maximus Oct 06 '11 at 09:38
  • forgot the call to its super.. what do you mean by tried loadView? – Octoshape Oct 06 '11 at 09:40
  • did the call to its super, still no change – Octoshape Oct 06 '11 at 09:41
  • Kick off the update in the viewDidLoad of your first view controller; that should resolve the issues of the alert displaying. – Paul Lynch Oct 06 '11 at 10:03
  • paul: That's what I said^^ --- octo: have you put that call to the super at the proper place? – Totumus Maximus Oct 06 '11 at 10:09
  • I am confused.. I did this ! .. check my question again, I'll change the edit and add the code of my first `UIViewController` – Octoshape Oct 06 '11 at 10:49
  • ok im making a prototype project for this. hang on its almost working. – Totumus Maximus Oct 06 '11 at 11:05
  • I cant get it to work for now. Something with the update firing before the actual first draw on the view. Could you try to add your alertview as a subview rather then using the show-method and see what it results in for you? – Totumus Maximus Oct 06 '11 at 11:56
  • It doesn't seem to change a thing .. but I mean what is it with the viewDIDload method anyways? Why is that code being executed BEFORE the view is actually showing :-( this just doesn't make any sense... I think I'll put another question on here.. – Octoshape Oct 06 '11 at 12:47
  • It is mostlikely because the drawing of the view takes longer then executing the next set of lines. He puts the draw somewhere in the background and only draws when the operations are done. Faced that in the prototype as well. Perhaps an NSTimer could fix it but I wouldnt recomment it – Totumus Maximus Oct 06 '11 at 12:53
  • I found something .. : [link](http://stackoverflow.com/questions/4297436/why-does-viewdidappear-in-uitabbarcontroller-exec-before-the-view-appears) I added the work around they provided there, and now the screen dims actually after showing the view, but the alertview still only shows up after the update is done and only "flashes" up and is dismissed right away :D so we're back to the original problem at least ^^ – Octoshape Oct 06 '11 at 13:01
  • m8 i got your solution;) lemme post it in a new answer for visibility:D – Totumus Maximus Oct 06 '11 at 13:19
0

You are starting a background thread and then dismissing the alert immediately. I would suggest that you might use an NSNotification, posted from the background task, and received in whichever controller starts the alert, triggering a method that dismissed the alert.

I find the UIAlertView interface unsuitable for this type of user notice, and prefer to use a semi-transparent overlay view with a UIActivityIndicatorView, plus an informing message for the user.

Paul Lynch
  • 19,769
  • 4
  • 37
  • 41
  • I am using an `UIActivityIndicatorView` in my `UIAlertView` and the issue shifted. The code in my question is actually not accurate anymore. Let me change it real quick to fill you in.. – Octoshape Oct 06 '11 at 09:53
  • I changed the code in the edit now, so I am indeed waiting for the update to end before dismissing the `UIAlertView` but the problem is: There is no view loaded, so the user can't see the `UIAlertView`. Read the comments on Totumus Maximus' answer. We're still working on it, would be awesome if you had more ideas. – Octoshape Oct 06 '11 at 09:56
  • Please, don't use a tight loop for a delay. It is far better to use a notification, or even a delegate protocol/method, as I suggested. – Paul Lynch Oct 06 '11 at 10:01
  • Yes I was about to ask about this.. How would I implement a `NSNotification` in this case? I've never used this before. – Octoshape Oct 06 '11 at 10:45