1

I would like when my app starts for it to show an Alert view for about 5 seconds, then depending on the outcome of a background process, it will show another Alert view.

The problem I am experiencing is that when I try to use Sleep to wait for a background process to occur. The first Alert does not show and wait the 5 seconds. The app shows the first view of the app, and then after 5 seconds the first Alert shows briefly.

What do I need to do to perform what I wish.

Here is my code.

- (void)viewDidAppear:(BOOL)animated
{
    SSGlobalSettings *connSettings = [SSGlobalSettings sharedManager];

    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Connecting" message:@"Please wait, while your device connects" delegate:Nil cancelButtonTitle:nil otherButtonTitles: nil];
    [alertView show];

    [NSThread sleepForTimeInterval:5.0f];

    [alertView dismissWithClickedButtonIndex: alertView.cancelButtonIndex animated: YES];

    if ([connSettings.connectionStatus  isEqual: @"Not Found"])
    {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Connection Failed" message:@"Cannot find your device on the network" delegate:Nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
        [alertView show];
    }
    else
    {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Connection Success" message:@"WYour device has been found on the network" delegate:@"OK" cancelButtonTitle:nil otherButtonTitles: nil];
        [alertView show];
    }
}
Gavin
  • 8,204
  • 3
  • 32
  • 42
Remixed123
  • 1,575
  • 4
  • 21
  • 35
  • Because you are setting the alert to run on another thread not the main thread which the `UIAlertView` will be running on. To make the main thread sleep just call `sleep(5)` – Popeye Jan 13 '14 at 15:42
  • Exact same result. I believe that [NSThread sleepForTimeInterval:5.0f] does block the same UI thread. Well it states as such here - http://stackoverflow.com/questions/2232366/waiting-for-a-specified-duration-in-cocoa#comment2187793_2232396 – Remixed123 Jan 13 '14 at 15:51
  • As `DuncanC` has said you shouldn't blocking the main thread anyway. I wouldn't even recommend using `sleep(5);` this is why I didn't add it as an answer. – Popeye Jan 13 '14 at 16:07

4 Answers4

3

Don't use sleep on the main thread. Ever. Also don't update UI from a background thread.

What you want to do is to display your alert on the main thread and return.

Then, when your networking code completes, have it send a message to the main thread. In the main thread, when you receive a notice that it's done, remove the alert.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
1

It's not working right because you are trying to tell the main thread of the app to sleep. If you are telling that thread to sleep, then you're most likely not going to allow any UI updating to occur during that time, because all UI updating happens on the main thread.

What you need to do is move the code for showing the second UIAlertView to a second method, and then call the method - (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay, passing it that second method for the selector, and giving it a delay of 5 seconds. Make sure you remove the call to sleep the main thread.

However, this still seems like a bad practice, because this action should be occurring as a result of your background task completing. So if you can, you should be running the code to show the second alert view upon completion of that task, which most likely could finish in varying amounts of time.

Gavin
  • 8,204
  • 3
  • 32
  • 42
  • Yes, I did first try to get it to perform the action dependent on the background task completing. But this happens as a result of a response to a network broadcast packet that happens asynchronously. And it is on another thread. Also, I am trying to avoid having UI code inside my network connection code. So instead I update a shared value which the app uses throughout to determine the state of the connection. – Remixed123 Jan 13 '14 at 15:58
  • You can use `- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait`, specifying the main thread, to make it perform it on the main thread. You could also use Grand Central Dispatch, which would be the preferred way. But just having a hard-coded delay seems like a really bad idea, and it is standard for UI changes to happen as a result of completion of network requests. If you want to keep things separate, you could make your own delegate protocol for your network connection code, so that your UI code remains with the rest of your UI code. – Gavin Jan 13 '14 at 16:46
  • Thanks Gavin, what can I do when I do not receive a response from the network. My app sends a broadcast packet out, which asks the device to respond with a "hey I am here" packet. But if the device is not present, no packet is received by my app. So I need to either wait or timeout after a period. So then my user can perform another action. – Remixed123 Jan 13 '14 at 16:51
  • What happens now? Is there some timeout in your network code already? Are you able to specify a timeout of your choice? If you can specify a timeout, choose something reasonable for the user to have to wait (that ensures that if it's present, you'll receive a response in time), and set up a delegate protocol for your network code that has delegate methods for success and failure. Then implement those methods in your UI code and make that the delegate of your network code. You should easily be able to handle both cases of success and failure this way. – Gavin Jan 13 '14 at 16:56
  • There is no timeout in my code. I either receive a response or I do not receive a response. Basically it is a UDP listener that will receive the response. It will usually take less than a second for the response to come back. I am using CoacaAsyncSockets - https://github.com/robbiehanson/CocoaAsyncSocket . I do not believe there is any timeout feature available. I could start up another thread that is the timeout, and then calls the performSelector. – Remixed123 Jan 13 '14 at 17:10
1

you block the main thread in you way.

i think it seems that you just want the user not to do anything before the first 5 sec(to let you connection connect successfully?), if so, lots ways could do that, e.g. just show a view on the top of the window, until you want the user can do something, you can show the disappear button on that view or just disappear it immediately.

XiaoSeng
  • 11
  • 3
  • Yes, this is pretty much what I am doing. My app sends a UDP broadcast packet to a device, this device then responds with information about its self. If the device is found then it updates the shared value with this information, if not found, then this shared value remains as "Not Found". – Remixed123 Jan 13 '14 at 16:02
  • if so, i think by using alert view, it's a bad way, you can easy to cover a view on all ui, then user can only do some interactions on this view, maybe you can input a waiting animation to let the user to wait patiently. until you connect successfully, post a notification, let you waiting view to catch this notification, then disappear this view to let the user known you connect successfully! – XiaoSeng Jan 13 '14 at 16:08
  • mostly,dev will post notification when connect successfully, that will easy to control the app, be carefully to post notification on main thread so that you can do some ui works when you receive this notification, otherwise you should dispatch to main thread to update ui – XiaoSeng Jan 13 '14 at 16:10
  • My situation is that I am sending broadcast packet, that is asking if my hardware device is on the network. If the device is not on the network, then no response will be received. So I need some sort of waiting or timeout feature, so if the device doesn't respond, I can provide details to the user. – Remixed123 Jan 13 '14 at 16:15
0

You can use performSelector:withObject:afterDelay: method instead.

vburojevic
  • 1,666
  • 5
  • 24
  • 34