continuously update an NSImageView - objective-c

I have an NSImageView that needs to redraw a constantly updating image.
I have a model object that creates the NSImage, and a controller that links this image to the NSImageView.
With multithreading, I can easily have the model object continuously update its output image in a background thread. But as UI interactions are supposed to be done on the main thread, I can't set the NSImageView's image on a background thread. If I update the NSImageView on the main thread, the program would become unresponsive

I hate to be contradictory but why do you think that updating the image on the main thread would make the program unresponsive?
If calculating the next NSImage is instantaneous then logically you should just calculate and display the last one since none of those in between will ever be perceived.
If calculating the next one costs some time then do the calculation off the main thread then push the image to the view on the main thread (eg, using performSelectorOnMainThread:...). The main thread won't become unresponsive because it has all that time while you're calculating the next image to deal with other events.
If updates are more frequent than the display's frame rate then you can probably go one better by setting yourself up with a CVDisplayLink and polling whatever is updating the image to get the latest one upon every tick of that.

Do not update NSimageView on background thread. it is not thread safe. you should use performSelectorOnMainThread:withObject:waitUntilDone:

Related

Freezing OS X Screen in Cocoa

I have two methods that modify the display of the screen. Is there a way to freeze the screen until the second method is called?
// I want to freeze the screen here
updateDisplay1(); // Change in display doesn't take effect until screen is unfrozen
updateDisplay2();
// Unfreeze screen here
In Excel VBA this would be something like screenUpdating = FALSE. Is there a similar function in Cocoa?
One possible way is to take screenshot:
// Take screenshot of the screen
// Display the screenshot image in front of the screen
updateDisplay1(); // Change is not visible
updateDisplay2();
// Remove screenshot image
But I'm afraid this is slow and takes up a lot of memory. Is there a more efficient method?
What screen are you talking about?
Standard Cocoa behaviour is:
you update the properties of the various views you are interested in;
each of those will make a call to its own setNeedsDisplayInRect. As a result of those calls, a redraw will be scheduled on the run loop;
once you've finished doing all of your updates, the run loop will be able to move onto its next item;
eventually it'll reach the redraw it scheduled and will make appropriate drawRect calls to appropriate views.
So all view changes that you make in response to an action are automatically atomic. You have to go significantly out of your own way to create a partial update.
taking screenshots with CGWindowListCreateImage takes a few milliseconds and uses roughly any memory. it's usually done directly in the graphic card.
give it a try and measure before doing any performance assumptions:-)

Movement of objects in game

I have a queston about movment of object in app (game) I am creating. I tried move ImageView with timer. So every 0.01 second object move for 1px. But movement is not smooth. So i also tried with animations. But there is problem, that if I close app and run it again (app was stil opened in background), there are problems, that picture of View stays on the end of animation. And also I want to check every 0.01 second if moving object and my character did colide, so animation is not the best option. Is there a way to move my object smooth with local time on phone? Or there is some other way to move object?
It sounds like you're not using SpriteKit or any game engine for that matter. Any game engine will come with an update loop that does all of this.
You can learn about SpriteKit here... http://www.raywenderlich.com/42699/spritekit-tutorial-for-beginners

UIView animateWithDuration: slows down animation frame rate

I am using CADisplayLink to draw frames using the EAGLView method in a game at 60 times per second.
When I call UIView animateWithDuration: the framerate drops down to exactly half, from 60 to 30 fps for the duration of the animation. Once the animation is over, the fps rises instantly back up to 60.
I also tried using NSTimer animation method instead of CADisplayLink and still get the same result.
The same behavior happens when I press the volume buttons while the speaker icon is fading out, so it may be using animateWithDuration. As I would like to be able to handle the speaker icon smoothly in my app, this means I can't just rewrite my animation code to use a different method other than animateWithDuration, but need to find a solution that works with it.
I am aware that there is an option to slow down animations for debug on the simulator, however, I am experiencing this on the device and no such option is enabled. I also tried using various options for animateWithDuration such as the linear one and the user interaction, but none had an improvement.
I am also aware I can design an engine that can still work with a frame rate that varies widely. However, this is not an ideal solution to this problem, as high fps is desirable for games.
Has someone seen this problem or solved it before?
The solution to this is to do your own animation and blit during the CADisplayLink callback.
1) for the volume issue, put a small volume icon in the corner, or show it if the user takes some predefined touch action, and give them touch controls. With that input you can use AVAudioPlayer to vary the volume, and just avoid the system control altogether. you might even be able to determine the user has pressed the volume buttons, and pop some note saying do it your way. This gets you away from any animations happening by the system.
2) When you have an animation you want to do, well, create a series of images in code (either then or before hand), and every so many callbacks in the displayLink blit the image to the screen.
Here's an old thread that describes similar drops in frame rate. In that case, the cause of the problem was adding two or more semi-transparent sprites, but I'd guess that any time you try to composite several layers together you may be doing enough work to cut the frame rate, and animateWithDuration very likely does exactly that kind of thing.
Either use OpenGL or CoreAnimation. They are not compatible.
To test this remove any UIView animation, the frame rate will be what you expect. Add back UIView animation, it will drop to 30fps.
You said:
When I call UIView animateWithDuration: the framerate drops down to exactly half, from 60 to 30 fps for the duration of the animation. Once the animation is over, the fps rises instantly back up to 60
I dont know why your not accepting my answer, this is exactly what happens when you combine UIView animation with CA animation not using a UIView.

Drawing with UIKit and preload it

I am drawing a graph with UIKIT and I want to show before it is finished a preloader (spinning circle)
Another solution should be before start drawing set the alpha of my view to 0.0 and when it's done fade it to 1.0.
Someone did this before and/or know how to do this?
If using UIKit, you could draw the path, fill and stroke, then draw another path. This is resource-intensive as you will be calling drawRect: often.
The other way is to create animation. I'll let someone else as I have no experience in creating animation in iOS.
You could add an activity indicator to the view, send the view setNeedsDisplay and remove the activity indicator at the end of the drawRect:, but I doubt you will see the activity indicator at all. Activity indicators are only useful when you are performing some lengthy operations, taking at least several seconds to complete. If drawing the graph is that long, you should either optimize it or consider drawing it on a secondary thread into a CGImage. In the latter case, I'm afraid, you restrict yourself to Core Graphics.

Repeating NSTimer locks UI thread

First of all, I know there are a few other StackOverflow questions about this subject, but I have read them all and I still am confused about what to do for my situation. I'm probably missing something obvious here, if you could help clarify that would be much appreciated!
I have a app which is doing a lot of work to animate images within a view - mainly comprised of a number of images moving in straight lines for a second or two at a time. I considered at first making them all simple, once off animations using UIView animateWithDuration for the whole duration of the movement. But I found that didn't give me a lot of power to intercept the movement or stop it or check where it was up to, so I scrapped that. My new approach is to use an NSTimer, firing 20 times per second, doing incremental movements. This way I also can intervene (almost) instantly to change the animation or stop it or update a status label based on how far through it is, etc, etc.
First of all...there probably is a better way than this. Feel free to suggest something better!
Assuming this is acceptable though, my issue now is that while these animations are happening, I can't click any of the other controls on the UI. I get no response. It's not like it's just slow or delayed either - the click never comes through. It seems that the NSTimer processing totally locks the UI - but only from new interactions. Changes I make to the UI within the timer processing method happen just fine, and are very snappy.
From what I've read this shouldn't happen. However I also saw a comment on this question saying that if the timer processing is intensive then it could lock the UI thread. I don't see my processing to be that intensive here - certainly no resource requests, just a bit of data manipulating and animating some objects - but I could be underplaying it.
What are my options here? At first I thought I might create a new thread to kick off the timer. But I remember reading that the UI updates have to happen on the main thread anyway. Why is this? And plus, would that really solve the issue? Am I just asking too much of the device to process this timer as well as UI interactions? Is there something else I'm missing?
Any and all advice would be appreciated.
Edit:
I've just found the cause of my UI blocking problem. I was using the animateWithDuration with blocks, but was not setting the options. Therefore UIViewAnimationOptionAllowUserInteraction was not set. I changed it to set this option and my UI is happily responding now.
That said, I'll still leave this question open for specific suggestions regarding my overall approach. Thanks.
I would consider using CADisplayLink. From the documentation:
A CADisplayLink object is a timer object that allows your application to synchronize its drawing to the refresh rate of the display.
Your application creates a new display link, providing a target object and a selector to be called when the screen is updated. Next, your application adds the display link to a run loop.
Once the display link is associated with a run loop, the selector on the target is called when the screen’s contents need to be updated. The target can read the display link’s timestamp property to retrieve the time that the previous frame was displayed. For example, an application that displays movies might use the timestamp to calculate which video frame will be displayed next. An application that performs its own animations might use the timestamp to determine where and how displayed objects appear in the upcoming frame. The duration property provides the amount of time between frames. You can use this value in your application to calculate the frame rate of the display, the approximate time that the next frame will be displayed, and to adjust the drawing behavior so that the next frame is prepared in time to be displayed.
Your application can disable notifications by setting the paused property to YES. Also, if your application cannot provide frames in the time provided, you may want to choose a slower frame rate. An application with a slower but consistent frame rate appears smoother to the user than an application that skips frames. You can increase the time between frames (and decrease the apparent frame rate) by changing the frameInterval property.
When your application finishes with a display link, it should call invalidate to remove it from all run loops and to disassociate it from the target.
CADisplayLink should not be subclassed.
I'm not totally sure how everything is handled in your program, but you might want to just consider having one thread/timer that controls all of the objects and their movements. There's really no need to create a separate thread/timer for every single object, as that will easily cause problems.
You can just create a class for your moving items with some variables that contain information about their direction, speed, duration, etc, and then have a controlling thread/timer calculate and move the objects. You can then intervene onto the one main controller object instead of having to deal with many other objects.
I think you'll find that even if you optimize this, timer based animation like this is not going to perform well.
You might want to ask about the specific things that you think you couldn't do with CoreAnimation. If you solve those issues, you'll end up with a much better result than trying to roll your own.