Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Dman90

macrumors newbie
Original poster
Jun 25, 2011
22
0
Hi Guys,

I have an activity indicator in my application in a number of places and I am having the same problem everywhere.

In the login page, when the user enters their details, and presses the login button, a method is called that checks if the details are right or not. While this method is being called an activity indicator is meant to show on the screen.

My problem is that the indicator shows at the end, just before the new view is loaded, rather then when the login credentials are being checked.

How can I activate it as soon as the button is pressed.

This is the method that is called when the login button is pressed:
Code:
{
     self.spinner.hidden = NO;
                                    
    [spinner startAnimating];

    URL connection to the database

    if statement check the reply for the database

   if credentials are correct new page is loaded.
}

As you can see from the method, I activate the spinner as soon as the method is called.

Any help would be greatly appreciated.

Thanks.
 
Hi Guys,

I have an activity indicator in my application in a number of places and I am having the same problem everywhere.

In the login page, when the user enters their details, and presses the login button, a method is called that checks if the details are right or not. While this method is being called an activity indicator is meant to show on the screen.

My problem is that the indicator shows at the end, just before the new view is loaded, rather then when the login credentials are being checked.

How can I activate it as soon as the button is pressed.

This is the method that is called when the login button is pressed:
Code:
{
     self.spinner.hidden = NO;
                                    
    [spinner startAnimating];

    [B]URL connection to the database

    if statement check the reply for the database

   if credentials are correct new page is loaded.[/B]
}

As you can see from the method, I activate the spinner as soon as the method is called.

Any help would be greatly appreciated.

Thanks.


I'm going to take a shot in the dark and say you're hanging the main thread in the code (bold).

Edit: You can quickly check this out if you comment out the code above. Also if your url connection to the database isn't on a separate thread it should be.
 
Oddly enough I had this happen last week working on my app. I fixed it by using the NSThread which allows you to break off the selected method and run it on the background. This allowed the indicator to spin until the process was finished.

The trick for me was to start it spinning [spinner startAnimating]; the the next line was the NSThread to process something like someMethod. Then at the end of someMethod just before it returned I used the code [spinner stopAnimation];

It was this code basicly
Code:
     }
    }
    [activityIndicator startAnimating];
    
    [NSThread detachNewThreadSelector:@selector(backgroundThreadLoad) toTarget:self withObject:nil];


-(void)backgroundThreadLoad{
        @autoreleasepool {
process this data....
        }
[activityIndicator stopAnimating];
}
 
I tried to do that for my code but I got the following error.

2012-04-10 00:40:49.811 In4merz[2939:380b] void _WebThreadLockFromAnyThread(bool), 0x21f1d0: Obtaining the web lock from a thread other than the main thread or the web thread. UIKit should not be called from a secondary thread.
2012-04-10 00:40:52.920 In4merz[2939:380b] bool _WebTryThreadLock(bool), 0x21f1d0: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
1 _ZL17_WebTryThreadLockb
2 WebThreadLock
3 -[UITextRangeImpl isEmpty]
4 -[UITextRange(UITextSelectionAdditions) _isCaret]
5 -[UITextSelectionView setCaretBlinks:]
6 -[UIKeyboardImpl setCaretBlinks:]
7 -[UIKeyboardImpl setDelegate:force:]
8 -[UIPeripheralHost(UIKitInternal) _reloadInputViewsForResponder:]
9 -[UINavigationController navigationTransitionView:didStartTransition:]
10 -[UINavigationTransitionView transition:fromView:toView:]
11 -[UINavigationTransitionView transition:toView:]
12 -[UINavigationController _startTransition:fromViewController:toViewController:]
13 -[UINavigationController _startDeferredTransitionIfNeeded]
14 -[UINavigationController pushViewController:transition:forceImmediate:]
15 -[UINavigationController pushViewController:animated:]
16 -[login validateLogin:]
17 -[login backgroundThreadLoad]
18 -[NSThread main]
19 __NSThread__main__
20 _pthread_start
21 thread_start
(lldb)



Oddly enough I had this happen last week working on my app. I fixed it by using the NSThread which allows you to break off the selected method and run it on the background. This allowed the indicator to spin until the process was finished.

The trick for me was to start it spinning [spinner startAnimating]; the the next line was the NSThread to process something like someMethod. Then at the end of someMethod just before it returned I used the code [spinner stopAnimation];

It was this code basicly
Code:
     }
    }
    [activityIndicator startAnimating];
    
    [NSThread detachNewThreadSelector:@selector(backgroundThreadLoad) toTarget:self withObject:nil];


-(void)backgroundThreadLoad{
        @autoreleasepool {
process this data....
        }
[activityIndicator stopAnimating];
}
 
From within my backGroundThreadLoad Method I do have a few [self someMethods]; that execute. One of them first tests to see if the file it is looking for even exists before continuing. I use this Method to test to see if the file exists first before I do anything. It uses the NSURLConnection that Dejo (whom has helped me countless times understand all of this as I also learn). I wrap it up in a if statement

if ([self webFileExists: @"www.site/dir/blah.txt]") {
do this....
}
else{
do this....
}



Code:
-(BOOL) webFileExists:(NSString *) address {
    
    NSString *url = address;
    
    NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString: url] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0];
    NSHTTPURLResponse* response = nil;
    NSError* error = nil;
    [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    
    if ([response statusCode] == 404)
        return NO;
    else
        return YES;
}

Please take all of this with a grain of salt. I just started to learn about NSThreads a month ago.
 
I'd recommend using NSURLConnection instead of NSThread for this kind of work.


I would either use [NSURLConnection sendAsynchronousRequest:queue:completionHandler:]; In the completionHandler stop your animation then push the new controller.

or

Wrap your everything inside of two blocks. The first block would use a background thread to call network stuff, then a second block on the main thread to update UI objects, think UIKIT.

Code:
dispatch_queue_t backgroundQueue = dispatch_queue_create("com.appName.taskNameHere",NULL);
dispatch_async(backgroundQueue, ^{
    //do networking stuff here
   //do networking stuff here

dispatch_async(dispatch_get_main_queue(), ^{
        //stop animation
       //update other UI related stuff
       //even push your view controller if needed.
    });

});
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.