How to put for loop to a separate thread - iphone

I have for loop that can read up to 100k rows.
When I start this function it block my UI until its done.
for (Item* sp in items){
data = [data stringByAppendingFormat:#"\"%#\",\"%#\","\n", ....];
}
How can I put this to separate thread so it doesn't block UI?

I don't think you've provided a complete example, but the simple use of Grand Central Dispatch should do the trick:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (Item* sp in items){
data = [data stringByAppendingFormat:#"\"%#\",\"%#\","\n", ....];
}
// Then if you want to "display" the data (i.e. send it to any UI-element):
dispatch_async(dispatch_get_main_queue(), ^{
self.someControl.data = data;
});
// else simply send the data to a web service:
self.webService.data = data;
[self.webService doYourThing];
});

This may suits you
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
for(Item* sp in items)
{
data = [data stringByAppendingFormat:#"\"%#\",\"%#\","\n", ....];
}
dispatch_async(dispatch_get_main_queue(), ^{
//UI updates using item data
});
});

Best way to use NSInvocationOperation.
NSOperationQueue *OperationQueue=[[NSOperationQueue alloc] init];
NSInvocationOperation *SubOperation=[[NSInvocationOperation alloc] initWithTarget:self selector:#selector(LoopOperation) object:nil];
[SubOperation setQueuePriority:NSOperationQueuePriorityVeryHigh]; //You can also set the priority of that thread.
[OperationQueue addOperation:SubOperation];
-(void)LoopOperation
{
for (Item* sp in items)
{
data = [data stringByAppendingFormat:#"\"%#\",\"%#\","\n", ....];
}
dispatch_async(dispatch_get_main_queue(), ^{
//UI updates using item data
});
}

If order doesn't matter in your loop I prefer to use dispatch_apply() inside of dispatch_async(). The difference is that a traditional for(...) loop will put all of the work on a single thread, while dispatch_apply() will perform the individual iterations in parallel on multiple threads, but as a whole the loop is synchronous, where the loop will not exit until all of the processing is complete.
A good test to see if order matters in your loop is whether the loop can be performed backwards with the same results.

Related

Updating label on the main thread is not working

I'm trying to update a label while different tasks are proceeding. I searched and used different options and endup using this way but it still doesn't work:
[processStatusLable performSelectorOnMainThread:#selector(setText:) withObject:#"Creating your account..." waitUntilDone:NO];
DCConnector *dccon = [DCConnector new];
ContactsConnector *conCon = [ContactsConnector new];
if (![dccon existUsersData]) {
[dccon saveUsersInformation:device :usDTO];
//created account
//get friends -> Server call
[processStatusLable performSelectorOnMainThread:#selector(setText:) withObject:#"Checking for friends..." waitUntilDone:NO];
NSMutableArray *array = [conCon getAllContactsOnPhone];
// save friends
[processStatusLable performSelectorOnMainThread:#selector(setText:) withObject:#"Saving friends.." waitUntilDone:NO];
if ([dccon saveContacts:array]) {
[processStatusLable performSelectorOnMainThread:#selector(setText:) withObject:#"Friends saved successfully.." waitUntilDone:NO];
}
}
The last performSelector is getting executed (at least I see the label text changed on the view), but all other selectors are not working. Any idea why?
EDIT 1
- (void)updateLabelText:(NSString *)newText {
processStatusLable.text = newText;
}
we can use the following code to run something on the main thread,
dispatch_async(dispatch_get_main_queue(), ^{
//set text label
});
Using that we can write a method like this,
- (void)updateLabelText:(NSString *)newText {
dispatch_async(dispatch_get_main_queue(), ^{
processStatusLable.text = newText;
});
}
Finally, you can use change your code this way,
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self updateLabelText:#"Creating your account..."];
DCConnector *dccon = [DCConnector new];
ContactsConnector *conCon = [ContactsConnector new];
if (![dccon existUsersData]) {
[dccon saveUsersInformation:device :usDTO];
//created account
//get friends -> Server call
[self updateLabelText:#"Checking for friends..."];
NSMutableArray *array = [conCon getAllContactsOnPhone];
// save friends
[self updateLabelText:#"Saving friends.."];
if ([dccon saveContacts:array]) {
[self updateLabelText:#"Friends saved successfully.."];
}
}
});
How fast do you run through this sequence of updates? If it is faster than a second, you aren't likely going to see all of 'em.
Making them wait until done is unlikely to impact anything as the drawing is done asynchronously anyway.
Note that your method names are unconventional; methods shouldn't be prefixed with get and saveUsersInformation:: is discouraged (try something like saveUsersInformationToDevice:usingDTO:).
How much time elapses between the calls to update the text field? The whole process takes a minute, but how is that time divided?
What is your main event loop doing otherwise? Running modally or running normally?

GCD flow how to write

I am trying to make screen shot of avplayer when video start playing so i need to run this code in fast in background so it will not block main thread and other controls run fast simultaneous,trying to run that code GCD format i am not able to run please help me to do that it stops at where i add into my array(in array i am adding UIImage Object)...
if (isCaptureScreenStart)
{
if (CMTimeGetSeconds([avPlayer currentTime])>0)
{
if (avFramesArray!=nil)
{
queue = dispatch_queue_create("array", NULL);
dispatch_sync(queue, ^{
[avFramesArray addObject:[self screenshotFromPlayer:avPlayer maximumSize:avPlayerLayer.frame.size :CMTimeGetSeconds([avPlayer currentTime])]];//stop at this line
NSLog(#"count:%d",[avFramesArray count]);
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(#"Frame are created:%d",[avFramesArray count]);
if ([avFramesArray count]==0)
{
NSLog(#"Frame are over");
}
});
});
}
}
}
dispatch_release(queue);
Edit:
I think i need to use dispatch_group_async this block now..please give some guideline that how to use:
if (isCaptureScreenStart)
{
if (CMTimeGetSeconds([avPlayer currentTime])>0)
{
if (avFramesArray!=nil) {
dispatch_group_async(serial_group1, serial_dispatch_queue1, ^{
[avFramesArray addObject:[self screenshotFromPlayer:avPlayer maximumSize:avPlayerLayer.frame.size :CMTimeGetSeconds([avPlayer currentTime])]];
});
}
}
dispatch_group_notify(serial_group1, serial_dispatch_queue1, ^{
NSLog(#"task competed");
});
}
Now I am using this block but above execution is contentious running and if i use dispatch_suspend(serial_dispatch_queue1); its stop but again i need to start block execution then what i need to use i have also try with dispatch_resume(serial_dispatch_queue1); again load but system show me crash
dispatch_release(queue); don't do it there, the dispatch queue that you are calling its going to a backThread, so wat is happening is :-
your queue is getting released before the block of code executes.
since your queue looks like an ivar, release it in dealloc. Rest, your code looks fine ..put a breakpoint inside and check if the block is executing.
EDIT
I dont understand, what u are trying to achieve by suspending the queue, there is no need to do it. You dont need to check whether the block has finished executing. The block will finish and then call the dispatch_async , get the main queue and update the UI from there.
Now, when you are creating the queue, create it lazily in your method. take the queue as an ivar in header file:
#interface YourFileController : UIViewController {
dispatch_queue_t queue;
}
Then in your method modify it as such:
if (isCaptureScreenStart)
{
if (CMTimeGetSeconds([avPlayer currentTime])>0)
{
if (avFramesArray!=nil)
{
if (!queue)
queue = dispatch_queue_create("array", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
[avFramesArray addObject:[self screenshotFromPlayer:avPlayer maximumSize:avPlayerLayer.frame.size :CMTimeGetSeconds([avPlayer currentTime])]];//stop at this line
NSLog(#"count:%d",[avFramesArray count]);
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(#"Frame are created:%d",[avFramesArray count]);
if ([avFramesArray count]==0)
{
NSLog(#"Frame are over");
}
});
});
}
}
}
NOTE : DISPATCH_QUEUE_SERIAL creates a serial queue, meaning all the blocks submitted to it will execute serially in First in First Out order. Once all the blocks submitted get executed, the queue stays ;) ..submit another block to it and it executes the block :D
this represents one whole block:-
[avFramesArray addObject:[self screenshotFromPlayer:avPlayer maximumSize:avPlayerLayer.frame.size :CMTimeGetSeconds([avPlayer currentTime])]];//stop at this line
NSLog(#"count:%d",[avFramesArray count]);
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(#"Frame are created:%d",[avFramesArray count]);
if ([avFramesArray count]==0)
{
NSLog(#"Frame are over");
}
});

GCD, Threads, Program Flow and UI Updating

I'm having a hard time figuring out how to put this all together.
I have a puzzle solving app on the mac.
You enter the puzzle, press a button, and while it's trying to find the number of solutions,
min moves and such I would like to keep the UI updated.
Then once it's finished calculating, re-enable the button and change the title.
Below is some sample code from the button selector, and the solving function:
( Please keep in mind I copy/paste from Xcode so there might be some missing {} or
some other typos.. but it should give you an idea what I'm trying to do.
Basicly, user presses a button, that button is ENABLED=NO, Function called to calculate puzzle. While it's calculating, keep the UI Labels updated with moves/solution data.
Then once it's finished calculating the puzzle, Button is ENABLED=YES;
Called when button is pressed:
- (void) solvePuzzle:(id)sender{
solveButton.enabled = NO;
solveButton.title = #"Working . . . .";
// I've tried using this as a Background thread, but I can't get the code to waitTilDone before continuing and changing the button state.
[self performSelectorInBackground:#selector(createTreeFromNode:) withObject:rootNode];
// I've tried to use GCD but similar issue and can't get UI updated.
//dispatch_queue_t queue = dispatch_queue_create("com.gamesbychris.createTree", 0);
//dispatch_sync(queue, ^{[self createTreeFromNode:rootNode];});
}
// Need to wait here until createTreeFromNode is finished.
solveButton.enabled=YES;
if (numSolutions == 0) {
solveButton.title = #"Not Solvable";
} else {
solveButton.title = #"Solve Puzzle";
}
}
Needs to run in background so UI can be updated:
-(void)createTreeFromNode:(TreeNode *)node
{
// Tried using GCD
dispatch_queue_t main_queue = dispatch_get_main_queue();
...Create Tree Node and find Children Code...
if (!solutionFound){
// Solution not found yet so check other children by recursion.
[self createTreeFromNode:newChild];
} else {
// Solution found.
numSolutions ++;
if (maxMoves < newChild.numberOfMoves) {
maxMoves = newChild.numberOfMoves;
}
if (minMoves < 1 || minMoves > newChild.numberOfMoves) {
solutionNode = newChild;
minMoves = newChild.numberOfMoves;
// Update UI on main Thread
dispatch_async(main_queue, ^{
minMovesLabel.stringValue = [NSString stringWithFormat:#"%d",minMoves];
numSolutionsLabel.stringValue = [NSString stringWithFormat:#"%d",numSolutions];
maxMovesLabel.stringValue = [NSString stringWithFormat:#"%d",maxMoves];
});
}
GCD and performSelectorInBackground samples below. But first, let's look at your code.
You cannot wait where you want to in the code above.
Here's the code you had. Where you say wait in the comment is incorrect. See where I added NO.
- (void) solvePuzzle:(id)sender{
solveButton.enabled = NO;
solveButton.title = #"Working . . . .";
// I've tried using this as a Background thread, but I can't get the code to waitTilDone before continuing and changing the button state.
[self performSelectorInBackground:#selector(createTreeFromNode:) withObject:rootNode];
// NO - do not wait or enable here.
// Need to wait here until createTreeFromNode is finished.
solveButton.enabled=YES;
}
A UI message loop is running on the main thread which keeps the UI running. solvePuzzle is getting called on the main thread so you can't wait - it will block the UI. It also can't set the button back to enabled - the work hasn't been done yet.
It is the worker function's job on the background thread to do the work and then when it's done to then update the UI. But you cannot update the UI from a background thread. If you're not using blocks and using performSelectInBackground, then when you're done, call performSelectorOnMainThread which calls a selector to update your UI.
performSelectorInBackground Sample:
In this snippet, I have a button which invokes the long running work, a status label, and I added a slider to show I can move the slider while the bg work is done.
// on click of button
- (IBAction)doWork:(id)sender
{
[[self feedbackLabel] setText:#"Working ..."];
[[self doWorkButton] setEnabled:NO];
[self performSelectorInBackground:#selector(performLongRunningWork:) withObject:nil];
}
- (void)performLongRunningWork:(id)obj
{
// simulate 5 seconds of work
// I added a slider to the form - I can slide it back and forth during the 5 sec.
sleep(5);
[self performSelectorOnMainThread:#selector(workDone:) withObject:nil waitUntilDone:YES];
}
- (void)workDone:(id)obj
{
[[self feedbackLabel] setText:#"Done ..."];
[[self doWorkButton] setEnabled:YES];
}
GCD Sample:
// on click of button
- (IBAction)doWork:(id)sender
{
[[self feedbackLabel] setText:#"Working ..."];
[[self doWorkButton] setEnabled:NO];
// async queue for bg work
// main queue for updating ui on main thread
dispatch_queue_t queue = dispatch_queue_create("com.sample", 0);
dispatch_queue_t main = dispatch_get_main_queue();
// do the long running work in bg async queue
// within that, call to update UI on main thread.
dispatch_async(queue,
^{
[self performLongRunningWork];
dispatch_async(main, ^{ [self workDone]; });
});
}
- (void)performLongRunningWork
{
// simulate 5 seconds of work
// I added a slider to the form - I can slide it back and forth during the 5 sec.
sleep(5);
}
- (void)workDone
{
[[self feedbackLabel] setText:#"Done ..."];
[[self doWorkButton] setEnabled:YES];
}
dispatch_queue_t backgroundQueue;
backgroundQueue = dispatch_queue_create("com.images.bgqueue", NULL);
- (void)process {
dispatch_async(backgroundQueue, ^(void){
//background task
[self processHtml];
dispatch_async(main, ^{
// UI updates in main queue
[self workDone];
});
});
});
}
By and large, any work to be submitted to a background queue needs to follow this pattern of code:
dispatch_queue_t queue = dispatch_queue_create("com.myappname", 0);
__weak MyClass *weakSelf = self; //must be weak to avoid retain cycle
//Assign async work
dispatch_async(queue,
^{
[weakSelf doWork];
dispatch_async(dispatch_get_main_queue(),
^{
[weakSelf workDone];
});
});
queue = nil; //Using ARC, we nil out. Block always retains the queue.
Never Forget:
1 - queue variable above is a reference counted object, because it is a private queue, not a global one. So it is retained by the block which is executing inside that queue. Until this task is complete, it is not released.
2 - Every queue got its own stack which will be allocated / deallocated as part of recursive operation. You only need to worry about class member variables which are reference counted (strong, retain etc.) which are accessed as part of doWork above.
3 - While accessing those reference counted vars inside background queue operation, you need to make them thread-safe, depending on use cases in your app. Examples include writes to objects such as strings, arrays etc. Those writes should be encapsulated inside #synchronized keyword to ensure thread-safe access.
#synchronized ensures no another thread can get access to the resource it protects, during the time the block it encapsulates gets executed.
#synchronized(myMutableArray)
{
//operation
}
In the above code block, no alterations are allowed to myMutableArray inside the #synchronized block by any other thread.

Using an application-lifetime-thread other than the main thread

I've a multi-threading application in which each thread has to do some job, but at a certain point some code needs to be executed serially (like writing into sqlite3 database), so I'm calling that code to be performed on main thread using:
[self performSelectorOnMainThread:#selector(serialJob:) withObject:object waitUntilDone:YES];
and every thing went just fine except that when that code needs some time the user interaction with the application gets disabled until that code has been finished, so is there any way to make another ONE thread that can be run on background and can be called whenever I need it just like the main one so I can replace the previous call with:
[self performSelector:#selector(serialJob:) onThread:REQUIRED_THREAD withObject:object waitUntilDone:YES];
this thread should be some class's static data member to be accessed from all over the code.
any help would be very appreciated, and many thanks in advance...
This is quite easy to do, just spawn your thread and let it run it's runloop using [[NSRunLoop currentRunLoop] run]. That's all that is required to be able to use performSelector:onThread: with a custom thread.
If you are on iOS 4 or newer you should consider using Grand Central Dispatch queues instead of threads though. The GCD APIs are much easier to use and can utilize the system resources much better.
Like Sven mentioned, look into Grand Central Dispatch.
You can create a queue like this:
dispatch_queue_t myQueue = dispatch_queue_create("com.yourcompany.myDataQueue", NULL);
Now you can call blocks on that queue:
dispatch_async(myQueue, ^{
// Your code to write to DB.
});
When you're done, don't forget to release the queue:
dispatch_release(myQueue);
Due to the my question that I need the current thread to be blocked until the database job has been finished, I've tried these two solutions and they worked perfectly. You can either use critical sections or NSOperationQueue and I prefer the first one, here is the code for both of them:
define some class "DatabaseController" and add this code to its implementation:
static NSString * DatabaseLock = nil;
+ (void)initialize {
[super initialize];
DatabaseLock = [[NSString alloc] initWithString:#"Database-Lock"];
}
+ (NSString *)databaseLock {
return DatabaseLock;
}
- (void)writeToDatabase1 {
#synchronized ([DatabaseController databaseLock]) {
// Code that writes to an sqlite3 database goes here...
}
}
- (void)writeToDatabase2 {
#synchronized ([DatabaseController databaseLock]) {
// Code that writes to an sqlite3 database goes here...
}
}
OR to use the NSOperationQueue you can use:
static NSOperationQueue * DatabaseQueue = nil;
+ (void)initialize {
[super initialize];
DatabaseQueue = [[NSOperationQueue alloc] init];
[DatabaseQueue setMaxConcurrentOperationCount:1];
}
+ (NSOperationQueue *)databaseQueue {
return DatabaseQueue;
}
- (void)writeToDatabase {
NSInvocationOperation * operation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(FUNCTION_THAT_WRITES_TO_DATABASE) object:nil];
[operation setQueuePriority:NSOperationQueuePriorityHigh];
[[DatabaseController databaseQueue] addOperations:[NSArray arrayWithObject:operation] waitUntilFinished:YES];
[operation release];
}
these two solutions block the current thread until the writing to database is finished which you may consider in most of the cases.

Use an NSRecursive Lock to wait for an operation to finish

Would it be save to use an NSRecursiveLock to purposefully wait for an operation to complete on a background thread? Here is an example:
I have a class where I want to have a loadParts function that can be asynchronous or synchronous. The asynchronous function will possibly be called early so that the parts can be loaded before the data is actually needed. The synchronous one should check if the data has been loaded, or is being loaded currently. If it has been loaded it can just return the data; if it is currently loaded, then it should wait for it to be loaded and then return; and if it isn't even being loaded, then it should just load it synchronously. This is the code I am trying to use:
// Private function to be run either on main thread or
// background thread
-(void)_loadParts
{
[_loadingPartsLock lock];
_loadingParts = YES;
// Do long loading operation
_loadingParts = NO;
_partsLoaded = YES;
[_loadingPartsLock unlock];
}
// Asynchronous loading of parts
-(void)preloadParts
{
if( _loadingParts || _partsLoaded )
return;
[self performSelectorInBackground:#selector(_loadParts) withObject:nil];
}
// Synchronous loading of parts
-(void)loadParts
{
if( _loadingParts )
{
[_loadingPartsLock lock];
[_loadingPartsLock unlock];
}
if( !_partsLoaded )
{
[self _loadParts];
}
}
Is this safe / an efficient way to do this? I already see some possible problems with it. Is it thread safe to set and test the value of a BOOL without a lock? I am also locking twice in the synchronous function if it is called while the background thread is still loading.
Is there a more common and better way to achieve this functionality?
Thanks!
A far, far, better solution is to use a dispatch_queue or NSOperationQueue (configured for serial operation).
Enqueue your loading operations and then enqueue whatever is supposed to happen when it is done. If the "done" operation is "tell the main thread to update", that's fine -- perform a method on your main thread that is effectively an event that triggers the update in response to the now loaded data.
This avoids the issues and overhead associated with locking entirely while also solving the "is done" notification issue without requiring some kind of polling mechanism.
Inspired by bbum's answer I found a solution that uses NSOperationQueue but not quite in the way he described. In my preloadParts function I create and store a load operation that is an instance of NSInvocationOperation that runs my background thread function. I then add it to the NSOperationQueue.
If at any point, the data is requested by another class. I first check if the data is loaded (the variable is set). If not, I check if the operation is in the queue. If it is, then I call [_loadOperation waitUntilFinished]. Otherwise, I add it to the operation queue with the argument to waitUntilFinished. Here is the code I came up with:
-(void)preloadCategories
{
if( [[_operationQueue operations] containsObject:_loadOperation] )
return;
[_operationQueue addOperation:_loadOperation];
}
-(CCPart*)getCategoryForName:(NSString*)name
{
if( nil == _parts )
{
[self loadCategories];
}
return [_parts objectForKey:name];
}
-(void)loadCategories
{
if( nil != _parts )
return;
if( [[_operationQueue operations] containsObject:_loadOperation] )
{
[_loadOperation waitUntilFinished];
}
else
{
[_operationQueue addOperations:[NSArray arrayWithObject:_loadOperation]
waitUntilFinished:YES];
}
}
-(void)_loadCategories
{
// Function that actually does the loading and sets _parts to be an array of the data
_parts = [NSArray array];
}
In the initialization function I set the _operationQueue and _loadOperation as follows:
_operationQueue = [[NSOperationQueue alloc] init];
_loadOperation = [[NSInvocationOperation alloc] initWithTarget:self
selector:#selector(_loadCategories)
object:nil];