CPU-intensive thread management on iOS

Im an experienced C / C ++ programmer approaching speed on Objective-C on iPhone. I searched a lot, but the house found a satisfactory answer to the question, which should be a general question; I apologize if this is answered elsewhere, pointers will be appreciated.

My application runs very intensively on the processor. The user interface has a simple display showing the progress and the start / stop button. What is the best way to highlight the most possible processor cycles to do the work, while ensuring a constant update of the display, and the start / stop button responds? I read that you should not do the work in the main thread, but apart from this, I did not find many suggestions. In light of this, I did my job in the NSOperation queue. I also added a screen update in turn. I also liberally sprinkled code with NSThread sleepForTimeIntervals. I experimented with different sleep times from .001 to 1 ([NSThread sleepForTimeIntervals.1]). Despite this, the screen display is at best sluggish (10 seconds), and pressing the stop button emphasizes the button, but nothing happens again for 10 seconds.

1.) Are NSOperation Queues the smart choice? If not, what else? 2.) How to minimize sleep? (Obviously, I want as many cycles as possible), and I'm not sure that my dreams do anything at all for the entire user interface to update.) 3.) Is there a better technique for updating the user interface? For example, is it possible to use NSTimer or some other method to send a message to the user interface telling it to update and / or check the state of the buttons?

Thank you for your support.

+4
source share
4 answers

1.) Are NSOperation Queues the smart choice? If not, what else?

NSOperationQueue sounds like it would be sensible.

of course you have a choice: pthreads, libdispatch (aka GCD), C ++ thread libraries created on top of pthreads, etc. etc., etc., if you do not create many / many, then it just comes down to the model you like.

2.) How to reduce sleep mode? (Obviously, I want as many cycles as possible), and I'm not sure that my sleep does anything at all for the entire user interface to update.)

do not sleep =) you can use a timer for your ui elements or an explicit callback or notification to notify dependencies. if ui dependency changes are updated, then you will most likely add a message to the message queue of the main thread.

3.) Is there a better way to keep the user interface up to date? For example, is it possible to use NSTimer or some other method to send a message to the user interface telling it to update and / or check the state of the buttons?

which really depends on what you do. if you just want to update the progress bar, then you can write the value from the secondary stream and read the value from the main stream. then use the timer in the main run loop to periodically report your object to refresh its display (based on the current value). for something like an indicator of unsteady progress, this might be good.

another alternative is more useful for events or stages: it will include the publication of updates (for example, notifications or callbacks for a delegate) from the secondary stream as it moves forward (for more details see No. 2).

Update

I was not sure if this was appropriate in the iOS model, but it looks like it is.

yes, that’s fine - there are many ratings you can take. which is "best" depends on the context.

My real understanding is to run the interface in one thread (and not in the main one!),

you really do not start the user interface explicitly; the main thread (usually) is controlled by clicking events and messages on the main thread. the main thread uses a run loop and processes message / event queues at each iteration of the run loop. You can also plan these posts in the future (more on that a bit). saying that all your posts in UIKit and AppKit (if you are targeting osx) should be in the main thread (as a generalization, which you will eventually learn there are exceptions to this). if you have a specific implementation that is completely separate from the UIKit messaging methods and this program is thread safe, then you can actually execute these messages from any thread, because this does not affect the state of the UIKit implementation. The simplest example:

@interface MONView : UIView @end @implementation MONView // ... - (NSString *)iconImageName { return @"tortoise.png"; } // pure and threadsafe @end 

start my workflow, use a timer to generate a signal for the user interface to look at the progress value and update the progress bar accordingly. For the purposes of this particular application, your second-last paragraph is enough, and I don’t need to go the length of the last paragraph (at least for now). Thanks.

for this you can use an approach similar to this:

 @interface MONView : UIView { NSTimer * timer; MONAsyncWorker * worker; // << this would be your NSOperation subclass, if you use NSOperation. } @end @implementation MONView // callback for the operation 'worker' when it completes or is cancelled. - (void)workerWillExit { assert([NSThread isMainThread]); // call on main // end recurring updates [self.timer invalidate]; self.timer = nil; // grab what we need from the worker self.worker = nil; // update ui } // timer callback - (void)timerUpdateCallback { assert([NSThread isMainThread]); // call on main assert(self.worker); double progress = self.worker.progress; [self updateProgressBar:progress]; } // controller entry to initiate an operation - (void)beginDownload:(NSURL *)url { assert([NSThread isMainThread]); // call on main assert(nil == worker); // call only once in view lifetime // create worker worker = [[MONAsyncWorker alloc] initWithURL:url]; [self.operationQueue addOperation:worker]; // configure timer const NSTimeInterval displayUpdateFrequencyInSeconds = 0.200; timer = [[NSTimer scheduledTimerWithTimeInterval:displayUpdateFrequencyInSeconds target:self selector:@selector(timerUpdateCallback) userInfo:nil repeats:YES] retain]; } @end 

Please note that this is a very primitive demonstration. it is also more common to enable a timer, handle updates, and work in the view controller, rather than in a view.

+5
source

Are you doing updates to your user interface in the main thread? This is very important because UIKit is not thread safe, and using it from a secondary thread can lead to sluggish behavior (or if this happens). Normally you do not need to use sleep in your background threads / queues so that the user interface remains responsive (unless your user interface is very CPU intensive, but that doesn't seem to be the case).

You can check any of your methods that update the user interface if they work in the main thread with something like

 NSAssert([NSThread isMainThread], @"UI update not running on main thread"); 

An easy and easy way to synchronize UI updates with the main thread is to use Grand Central Dispatch:

 dispatch_async(dispatch_get_main_queue(), ^ { //do your UI updates here... }); 
+3
source

Here are my answers to your questions.

1) Since you are an experienced C programmer, you will be comfortable working with Grand Central Dispatch (GCD), the C-based API for concurrency.

2) With GCD you do not need to sleep at all. Just send asynchronously the work you need to do in the queue using the highest priority (DISPATCH_QUEUE_PRIORITY_HIGH).

3) When you need to update the interface, just send the user interface update to the main queue (in the same block doing the work using dispatch_get_main_queue ()) as necessary.

Take a look at the relevant GCD documentation here .

+2
source

I will have a model object that performs the tasks of a processor that has a delegate callback to change the output and a view controller. In viewDidLoad you set the view controller as a delegate to your model. Therefore, the model can use streams and send messages back to the main queue when the calculated data has been updated. If your case is not particularly complicated, just use Grand Central Dispatch and dispatch_async for an intensive task on another thread.

Of course, you should not call sleepForTimeInterval anywhere to achieve what you want.

+1
source

All Articles