views:

251

answers:

4

I have a UIScrollView where a lot of objects appear (UIImageView's) during scrolling. However, when the user is scrolling, I want to fire messages to all these objects, in order to tell them that they shall not do anything stupid. When the UIScrollView decelerates, some animations happen at the visible objects. When the user moves on fast (pagingEnabled=YES), more and more objects are still animating, which will result in horrible scroll performance.

I want to tell them all to immediately stop and do nothing as soon as the user is scrolling. So, what can I do? A for-loop is bad for performance upon scrolling. It will jerk for a small moment, but that's enough to make the user very very mad.

+4  A: 

Put them all in an array, and use [NSArray makeObjectsPerformSelector:]. That's the most concise way to do it, but I'm not sure it's any more efficient than using a for loop...

I'm not sure how you're animating your views, but you might want to use the UIScrollView's delegate functions to maintain a subarray of visible items and limit your animations to those. For instance, whenever the visible rectangle changes, you could look at your existing list of visible views and see if any are completely offscreen. You could stop animating those. You could then look for views that were on-screen but not in the list and begin animations on them. I've done something like this before, and it helped improve performance substantially!

Then if you want to freeze all the running animations, you've got an array of the animating ones and it's relatively short.

Hope that helps!

Ben Gotow
-makeObjectsPerformSelector: will use an for-loop internally, and has the disadvantage that the called method must take no parameter. I'm already doing something similar, where I only kick off animations at those objects that are on the current visible page. That is, the rectangle that's an multiple of the scrollView's frame width. The problem is when the user proceeds too fast. Then old animations still run while new ones start. My animations get more complex, the more the user accelerates the scrollView. So things add up quickly ;)
Thanks
I also thought about just stopping everything that's offscreen, but the problem is: User scrolls right, quickly back to left. And then he/she expects that animations are still "decelerating". So I have to keep a range of at least 0,5 pages around the scrollView's viewport active, but cancel any animation outside that range.
Thanks
There is a makeObjectsPerformSelector:withObject method if you need to supply arguments
monowerker
+1  A: 

Try to Perform each message on a different thread. Of course all UI updates have to be on the main thread, but if you can do some work in a background thread, maybe it will reduce some lag. (I can't say how feasible this is for 30+ objects however)

Corey Floyd
+2  A: 

Also remember that the computers can only do things in a linear fashion. So no matter what you do you will have to use some sort of loop control structure.

perhaps kick off a thread that contains the loop. and the loop will call the

perfomrselectoronmainthread:

selector for each object. (remember for UI stuff it has to be executed on the main thread.)

and i asume you are using

+ (void)setAnimationsEnabled:(BOOL)enabled

To stop the animation.

if this is still not fast enough you will have to look at Core Animations, these will have extra efficiencies that will allow this to happen.

Bluephlame
Thats a sweet solution. Thats about as close as "simultaneous" as it will get.
Naren
+2  A: 

I would use notifications. This has the advantage that you can notify all of your objects passing them all of the information required. It is also a simple, yet powerful mechanism, allowing asynchronous communication.

See Introduction to Notification Programming Topics:

http://developer.apple.com/documentation/Cocoa/Conceptual/Notifications/Introduction/introNotifications.html

unforgiven