UIActivityIndicatorView not staring - ios

I am trying to set a 'UIActivityIndicatorView' as an accessoryView in one of my 'UITableViewCell', in a such way as, the ActivityIndicator start animating when the user touch this cell. I add the following code at 'didSelectRowAtIndexPath' method:
UITableViewCell * cell = [tableView cellForRowAtIndexPath:indexPath];
UIActivityIndicatorView * activity = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
NSThread * newThread1 = [[NSThread alloc]initWithTarget:self selector:#selector(carregarNoticias) object:nil];
switch (indexPath.row) {
case 0:
cell.accessoryView = activity;
[activity startAnimating];
sleep(0.01);
[newThread1 start];
while (![newThread1 isFinished]) {
//waiting for thread
}
[activity stopAnimating];
[self.navigationController pushViewController:noticias animated:YES];
break;
I was expecting 'UIActivityIndicatorView' animating while the newthread1 is running. However, the animating only start when the newThread1 finish (and therefore I don't want the animation anymore). I added 0.01 seconds as sleep time to give time to the animation start. Nevertheless, this also did't solve.
Does anyone know what my error is? I appreciate any help!

I dont really know what you are trying to do adding delay like that.. try this line below, might be the one your look for.. and another thing.. please dont block the main thread like sleep(0.01); that, users wont like it..
cell.accessoryView = activity;
[activity startAnimating];
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
// the system will wait until this
dispatch_async(dispatch_get_main_queue(), ^(void){
[newThread1 start];
});
// is finished, maybe you dont need the `[NSThread sleepForTimeInterval:3];`
// pick the one that suits your implementation..
[NSThread sleepForTimeInterval:3];
dispatch_async(dispatch_get_main_queue(), ^(void){
[activity stopAnimating];
[self.navigationController pushViewController:noticias animated:YES];
});
});
[NSThread sleepForTimeInterval:3] sleep the thread like the one you have sleep(0.01);
But using it inside
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ });
makes it async. and wont block the main thread..
while the dispatch_async(dispatch_get_main_queue(), ^(void){ fires your code at the main thread..
Happy coding, cheers! :)

Related

UIScrollView setContentOffset:animated must be used from main thread only

I'm performing an action in tab bar, i.e. (when the button is tapped twice) it should perform,
[root.FeedTableView setContentOffset:CGPointZero animated:YES];
but I'm unable to perform it in the,
dispatch_async(dispatch_get_main_queue(), ^{
});
as nothing happens, so I tried using,
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
});
and it worked fine expect in this case the threading runtime error pops up.
Inspect the code below and suggest a remedy, for tackling this threading issue which happens at
[root.FeedTableView setContentOffset:CGPointZero animated:YES];
(void)processBtn:(UIButton *)sender {
NSLog(#"sender:%li",(long)sender.tag);
if (self.selectedViewController==self.viewControllers[0] && sender.tag==1){
NewsFeedViewController * root = [newsFeedSceneController.viewControllers firstObject];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[root.FeedTableView setContentOffset:CGPointZero animated:YES];
dispatch_async(dispatch_get_main_queue(), ^{
if(!root.isUpdatingTableView)
[root.refreshControl endRefreshing];
});
});
}
As Jon Rose noted, scroll view line:
[root.FeedTableView setContentOffset:CGPointZero animated:YES];
and UIrefreshcontrol line:
[root.refreshControl endRefreshing]; were the main conflict.
All that needed to be done was to remove UIrefreshcontrol line and add non UI dependent line[root RefreshView];

iOS: how to properly stop an Activity Indicator?

I'd like to stop the animation of the indicator within a method called by default NSNotificationCenter with a postNotificationName.
So I'm doing this on Main Thread
-(void)method
{
...
[ind performSelectorOnMainThread:#selector(stopAnimating) withObject:nil waitUntilDone:NO];
}
It does'n work. Method is called correctly, any other called selectors do their job but not stopAnimating.
I put [ind stopAnimating] in another function and then called it via performSelectorOnMainThread but it still didn't worked.
Try this...
Create a method that stops your animation
-(void)stopAnimationForActivityIndicator
{
[ind stopAnimating];
}
Replace your method like this -
-(void)method
{
...
[self performSelectorOnMainThread:#selector(stopAnimationForActivityIndicator) withObject:nil waitUntilDone:NO];
}
Should do the magic...
You can also use the below method which starts and stops the activity indicator on main thread in a single method, also provides you to execute your code asynchronously as well-
- (void)showIndicatorAndStartWork
{
// start the activity indicator (you are now on the main queue)
[activityIndicator startAnimating];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// do your background code here
dispatch_sync(dispatch_get_main_queue(), ^{
// stop the activity indicator (you are now on the main queue again)
[activityIndicator stopAnimating];
});
});
}
Try :
-(void)method
{
dispatch_async(dispatch_get_main_queue(), ^{
[ind stopAnimating];
});
}

Why does the UIButton never hide, and then come back unhidden?

So self.pic is the UIButton that I want to hide. But it never actually hides it for some reason.
Please Help
- (void)tick:(NSTimer*)time
{
self.pic.hidden = YES;
[NSThread sleepForTimeInterval:1];
self.pic.hidden = NO;
[self.pic setEnabled:NO];
if (self.checkPic == YES)
{
self.lives--;
self.livesLabel.text = [NSString stringWithFormat:#"Lives : %d", self.lives];
}
[self.pic setImage:[self backgroundImageForGame] forState:UIControlStateNormal];
[self check];
self.pic.enabled = YES;
}
Just to elaborate on what #rmaddy said in his comment, you shouldn't ever sleep the main (or UI) thread. When you do this, you're blocking the thread that is responsible for making the visual changes to the button, like whether or not it is hidden. The solution is to do the waiting asynchronously, and GCD has a built in function that makes this painless.
dispatch_after() allows you to create a block that will be executed after a specified delay, on a queue of your choosing. Since you want to update the UI, you'll want to come back to the main queue to make the changes to the on screen button. Here's an example:
self.pic.hidden = YES;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
self.pic.hidden = NO;
});

MBProgressHUD fades / lightens when triggered by this button

What is going on here?
http://screencast.com/t/WACeaQP00iqb
Here's the code for that button (the three method calls spawn 3 (yes 3; i didn't write the server :D) asynchronous data tasks that take some time to finish):
- (IBAction)didTouchClockButton:(id)sender {
[self.dr isUserClockedIn];
hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.dimBackground = NO;
// hail mary
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantPast]];
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
// Do something...
if (![self.dr isNetworkDead])
if ([self.dr isUserClockedIn]) { // add clock in / clock out function to this button
hud.labelText = #"Clocking Out..";
[self.dr clockOut];
} else {
hud.labelText = #"Clocking In..";
[self.dr clockIn];
}
});
}
I put the hud dismissal inside a KVO callback, which isn't working yet but first things first.
You don't want to do anything related to the UI on a background thread. Dispatch the MBProgressHUD code on the main thread and see if that solves the issue. Try:
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
// Do something...
if (![self.dr isNetworkDead])
if ([self.dr isUserClockedIn]) { // add clock in / clock out function to this button
dispatch_async(dispatch_get_main_queue(), ^{
hud.labelText = #"Clocking Out..";
});
[self.dr clockOut];
} else {
dispatch_async(dispatch_get_main_queue(), ^{
hud.labelText = #"Clocking Out..";
});
[self.dr clockIn];
}
});
I ended up dismissing the HUD the line before I call the method that updates the other view elements. Right now they're both happening near instantaneously so it's fine, although if the view was still updating after the HUD went down that would be lame. So the solution is to not mess with the view while your HUD is active. A messy solution, so if anyone has a better one I'm all ears.

Delay between animations on a UIImageView in iOS

I have an animation which is made up of an array of images, on which I then run
[myUIImageView startAnimating]
I want the animation to run once, then stop for 3 seconds, then repeat.
I need to run this animation in a separate thread so I have
NSThread *animationThread = [[NSThread alloc] initWithTarget:self selector:#selector(startAnimTask) withObject:nil waitUntilDone:NO];
[animationThread start];
in my viewDidLoad, and then
-(void) startAnimTask {
//create array of images here; animationDuration (3) and animationRepeatCount (1)
[self setUpAnimation];
while (true){
[myUIImageView startAnimating];
usleep(3);
[myUIImageView stopAnimating];
usleep(3);
}
}
Using this method, I receive a memory warning. I've also tried running the start and stop on the MainThread with no luck.
Any ideas?
Do this:
[myUIImageView startAnimating];
[self performSelector:#selector(startAnimTask)
withObject:nil
afterDelay:(myUIImageView.animationDuration+3.0)];
Now selector is:
-(void)startAnimTask
{
[myUIImageView startAnimating];
//repeat again then add above selector code line here
}
UI is not thread safe, so UI calls should be executed only in main thread, maybe this is the case.
I think you can go with this:
[self performSelector:#selector(startAnimTask)
withObject:nil
afterDelay:0.1];
[self performSelector:#selector(startAnimTask)
withObject:nil
afterDelay:3.0];
In startAnimTask method write your animation logic code.
Enjoy Coding :)
Try this approach to complete your task:
[self performSelector:#selector(myTask)
withObject:nil
afterDelay:3.0];
-(void)myTask{
//Write your logic for animation
}

Resources