Blocking on UIImageView animation, or, "while not finished animating, spin" - iphone

I'm currently animating many images via 4 UIImageViews, and all is well on that front. The animations complete as expected, and I am assuming that they run inside their own NSThread, as execution continues despite the animation. Of course, this is good and expected behaviour, as I definitely wouldn't want my whole app to halt until the animation finishes.
However, I need to kick off a method which needs to depend on whether the animation is running or not.
The following code is bad as I understand, as introducing loops and other delays inside the main thread causes instability.
while([self.fooImgView isAnimating])
;
This code effectively halts execution of the whole app. I need to find a way to "spin" until the animation completes, without wedging the app.
Any advice on this would be greatly appreciated.
Thanks!
sc.

If you use block animations like this one, you can use the completion block to call some delegate or execute your method

Related

UIActivityIndicator issues -- sometimes it doesn't stop

I have an activity indicator that is working fine. Most of the time. But sometimes it just keeps going. The code is pretty spread about, so I'll have to explain.
I'm doing a calculation. Sometimes it only needs updating, so it's fast. Sometimes it's lengthy, and may have to get new data from a server. When the calculation takes some time, the activity indicator works. When it's fast, though, the activity indicator will start, but not stop. Is there a minimum time for the animation? Has anyone else run into this?
I'll try writing something to gate the startAnimation based on the last time the calculation was done. Any suggestions?
UPDATE: OK. it' solved. Logging (as suggested) did show up that there was second call to startAnimating, leading to a race condition: sometimes the calculation was long enough that both calls arrived before the stop. I've now eliminated the second call and it's working!!
Are you sure that you call stopAnimating from the main thread? Changes in the UI have to be made on the main thread. Otherwise you will experience nothing at all, strange behavior or delays.
Put something like that NSLog before you call stopAnimating to make sure it is called at all and from the main thread.
NSLog(#"main thread? %#", [NSThread isMainThread] ? #"YES" : #"NO!");
Doing UI updates from another thread is often the reason for unexpected results, particularly for UIActivityIndicatorViews because they are usually used with threads.
My guess is that you call endAnimation before startAnimation or not at all. These are the most common causes for such problems...
Did you try NSLog when these two methods are called?
For these situations I like to build a sort of reference counted activity indicator. Basically every time you do something on the network, you increment the network activity count. Then when it's done you decrement. If it ever hits 0, you stop it. If it's above 0, you start it.

pausing execution for 1 second

I have an IBAction which starts a number of timers.
I would like to have a second or a pause for a certain time. How can I pause execution?
I know of the [self performSelector:#selector(someMEthod:) withObject:someObject afterDelay:1.0];
but how can I just cause a delay without calling anything?
Thanks
You can call sleep() or +[NSThread sleepForTimeInterval:] but please don't do that on the main thread. Pausing execution of the main thread means your app's UI will be blocked for that time and appear to the user as if it had crashed. If you blocked the main thread for more than a few seconds, Apple's watchdog timer would kill your app instantly.
See this blog post by Jeff LaMarche for more on this issue: http://iphonedevelopment.blogspot.com/2010/05/psa-respect-main-thread.html
You don't want to cause a delay without calling anything. It's bad for the UI, and does not fit Cocoa Touch's event driven paradigm.
Cut the routine in which you want to pause into (at least) two parts/halves. Have the first half set up a delayed call to the second half (perform selector with delay, timer, queue, etc.) and then return to the main loop. The OS will call the second part, later, after potentially doing useful stuff in the mean time (giving the user a responsive UI or saving battery life, catching up with background email, etc.)
You may have to learn how to save state between parts (loop variables, etc.), something that some new programmers seem to miss in their learning.
You can use sleep(int_No_of_Sec); // eg. sleep(1);

Running activity indicator NOW

I want to start an activity indicator before going to disk I/O.
How do I start the indicator NOW, instead of waiting for the next display loop cycle? Or how do I force the display loop before beginning the disk I/O?
Dan
If I understand correctly your IO operation takes some time, and you want the UI to update as you're performing it, right? If that's the case, you have to move your operation to a background thread for the UI to have a chance to update itself, there's no workaround. use performSelectorInBackground:withObject: to call your IO operation, use NSOperation, or blocks if you're targeting iOS 4.0+
You can't force the indicator to start now as far as I'm aware. To push a method call so that it's the next thing in the runloop, you can use:
[self performSelector:#selector(taskToDo) withObject:nil afterDelay:0]
Which will schedule 'taskToDo' (optionally with a single argument) onto the current runloop, to occur as soon as it can. Then just let that segment of code exit. An equivalent method is to schedule an NSTimer, but syntactically that's a bit more lengthy.

NSTimer Lag - iPhone SDK

I made a game that uses many timers throughout the code. However the timer has to deal with many tasks in such a small amount of time which leads to the problem where there is lag in my game. For example, my timer runs at an interval of (0.05) and it needs to draw and update many of the images on the screen. Is there any way I can distribute the work flow so that the program runs much smoother?
Thanks
Kevin
I would use an NSThread instead of an NSTimer. I have had more success in this area using NSThread because it runs on an independant thread and is not fired off your main ui thread. In the loop for the thread sleep it for 1/20 (your 0.05) of a second. Because the thread is not running on the UI thread all of its tasks should not slow your UI down. However beacsue it is not running on the UI you will have to call performSelectorOnMainThread to get the UI to update from this background thread. I put a lock on my update method (a simple boolean) that says if the last ui update has not happened, just skip this one. then if im running out of processing time i just drop a frame or two here and there. I also do a lot of checking to see if anything has actually changed before i redraw.
Simple solution: Ditch NSTimer.
Move your redrawing code to a single method, then use CADisplayLink. The issue with using your NSTimer approach is that everything is being redrawn too fast or too slow for the screen. By using CADisplayLink, you can synchronize your redraw code to the screen refresh rate. All you need to do then is touch up your code so that it can deal with not being called at a specific time.
And yes, check to make sure you don't need to redraw as Aran Mulholland said above. Just make sure the checks don't take as long as a redraw.
And remember to optimize your code. A lot. Use ivars to access objects, but the whole property (self.myObject =) to set your objects.

Does it help to start intensive core animation blocks in another thread?

I have an scroll view with some sophisticated animations happening during scrolling. Although after 2 weeks of finetuning the performance is acceptable now, the scrolling is not 100% smooth when the animations happen.
I know that core animation does animations in a background thread. But I wonder if it would help to split those animation blocks (10 of them at pretty much the same time) into threads.
There are a few methods that look interesting:
– performSelector:onThread:withObject:waitUntilDone:
– performSelectorInBackground:withObject:
or is that nonsense to do?
No, it won't help. As you correctly stated yourself, Core Animation already runs in a seperate thread. Core Animation is smart enough to handle animation blocks as efficiently as possible. I wouldn't advise interfering with it.
The Core Animation Programming Guide says:
An abstract animation interface that
allows animations to run on a separate
thread, independent of your
application's run loop. Once an
animation is configured and starts,
Core Animation assumes full
responsibility for running it at frame
rate.
Are you sure the choppy behavior is really from CA? Do you have anything else going on?
If you have any background network access, consider moving that into a separate thread - the time taken to service those calls takes away from time the UI spends updating the screen as you scroll.