What is the best way to run code on a separate thread? Is it:
[NSThread detachNewThreadSelector: #selector(doStuff) toTarget:self withObject:NULL];
Or:
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:#selector(doStuff:)
object:nil;
[queue addOperation:operation];
[operation release];
[queue release];
I've been doing the second way but the Wesley Cookbook I've been reading uses the first.
In my opinion, the best way is with libdispatch, aka Grand Central Dispatch (GCD). It limits you to iOS 4 and greater, but it's just so simple and easy to use. The code to do some processing on a background thread and then do something with the results in the main run loop is incredibly easy and compact:
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Add code here to do background processing
//
//
dispatch_async( dispatch_get_main_queue(), ^{
// Add code here to update the UI/send notifications based on the
// results of the background processing
});
});
If you haven't done so already, check out the videos from WWDC 2010 on libdispatch/GCD/blocks.
The best way for the multithreading in iOS is using GCD (Grand Central Dispatch).
//creates a queue.
dispatch_queue_t myQueue = dispatch_queue_create("unique_queue_name", NULL);
dispatch_async(myQueue, ^{
//stuffs to do in background thread
dispatch_async(dispatch_get_main_queue(), ^{
//stuffs to do in foreground thread, mostly UI updates
});
});
I would try all the techniques people have posted and see which is the fastest, but I think this is the best way to do it.
[self performSelectorInBackground:#selector(BackgroundMethod) withObject:nil];
I have added a category on NSThread that will let you execute threads in blocks with ease. You can copy the code from here.
https://medium.com/#umairhassanbaig/ios-how-to-perform-a-background-thread-and-main-thread-with-ease-11f5138ba380
Related
I want perform some database related task in background for that I have added code
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0), ^(void) {
[lclDB deleteRecoredwithBlock:^(BOOL success) {
if (success) {
NSLog(#"Deletion Succesful...");
}
}];
});
deleteRecord function internally calls number of methods sequentially to perform delete operation in local database.now I have wait until all delete operation is performed.but I want to do this whole delete operation in background.if any one known please help me to figure out these problem.
Any NSObject can perform action in background using the following :
[myObject performSelectorInBackground:#selector(anAction) withObject:nil];
More information on apple documentation.
Try performSelectorInBackground:withObject: method.
[self performSelectorInBackground:#selector(backgroundMethod) withObject:nil];
You can also use NSInvocationOperation.
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(deleteDataWithOperation) object:nil];
[queue addOperation:operation];
And this is your deleteDataWithOperation method -
-(void)deleteDataWithOperation
{
//Do your work here
}
I'm making the app-book for ipad like app-magazine.
Now I'm using ScrollView and want to load many 1024*768 images(about 100 images), (As you know, If all images are loaded at once, It is impossible.)
so I load just 5 pages(current page & 2 pre pages & 2 next pages) and remove the other pages.
But, I have a question.
I made the method('loadTitlePage') for loading the page and I have to call this method when I want to load all pages.
So, I can't use dispatch_async but dispatch_sync.
Is there any difference between using dispatch_sync and writing code in line(non-block without dispatch_sync)?
It's my code.
[self loadTitlePage:currentPageNo];
dispatch_queue_t dqueue = dispatch_queue_create("scrollLoadTitlePage", NULL);
dispatch_sync(dqueue, ^{
[self loadTitlePage:currentPageNo-2]; });
dispatch_sync(dqueue, ^{
[self loadTitlePage:currentPageNo-1]; });
dispatch_sync(dqueue, ^{
[self loadTitlePage:currentPageNo+1]; });
dispatch_sync(dqueue, ^{
[self loadTitlePage:currentPageNo+2]; });
dispatch_sync(dqueue, ^{
[self removeTitlePage:currentPageNo-3 withNo:currentPageNo+3]; });
You can read here: using dispatch_sync in Grand Central Dispatch
In short.. dispatch_sync is equivalent to a mutex lock.. in your case I don't think there is any difference
Scenario is like this--
In my app there is an Scroll View with many instances of
MyCustomImageDownloaderController(containing imageViews where images are to be assigned after downloading) .
As per our requirement, an image has to be downloaded as we move on to a page.
Scroll View + (MyCustomImageDownloaderController1, MyCustomImageDownloaderController2, MyCustomImageDownloaderController3.... etc)
Let's say i am scrolling on it,
i reached to page 1 --> image for it should start downloading
i reached to page 2 --> image for it should start downloading...so on
and if i am on page 3 and images for previous pages if not been dowloaded, they should stop downloading.
So i tried it with using threads..
on API..
- (void)scrollViewDidEndDecelerating:(UIScrollView *)sender{
Step 1) calculated currentPageNumber
Step 2) started thread for downloading image with url for this currentPage
//startBackGroundThreadForPlaceImage:(NSURL *) url
Step 3)stopped thread for previous page , if that is still running
}
Now My MyCustomImageDownloaderController is as
-(void) startBackGroundThreadForPlaceImage:(NSURL *) url{
if(isImageDownloaded == NO){
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//[self performSelectorInBackground:#selector(loadImageInBackground:) withObject:imageUrl];
myThread = [[NSThread alloc] initWithTarget:self selector:#selector(loadImageInBackground:) object:imageUrl];
//[NSThread detachNewThreadSelector:#selector(loadImageInBackground:) toTarget:self withObject:imageUrl];
[myThread start];
NSLog(#"The current thread is %# ", [[NSThread currentThread] name]);
[pool release];
}
}
NOW Here selector does the work of loading image and assigning to image view
Now Stopping the thread
-(void) stopBackgroundThread{
[myThread cancel];
//[[NSThread currentThread] cancel];
//if([[NSThread currentThread] isCancelled]) {
//[NSThread exit];
//}
[NSThread exit];
}
-(BOOL) isThreadRunning{
return [myThread isExecuting];
}
So i tried a lot of things, but could not Stop the thread in between..
Basically once instantiated thread using any of three methods
1) perform Selector in BackGround
2) NSThread detach new thread
3) NSThread alloc..init with..
In first 2 methods how to get the instance of the newly created thread, so that i could stoop it,
as NSThread currentThread doest not give that
in Method 3,
myThread = [[NSThread alloc] initWithTarget:self selector:#selector(loadImageInBackground:) object:imageUrl];
when i tried
[myThread cancel];
It did not cancel that thread,,
When i tried
[NSThread exit];
it hangs on current screen,,,,i guess it has stopped the main thread
Please help me
Thanks in Advance*strong text*
It's generally better to ask the thread to stop, rather than forcing it, which should be considered a last resort. You should, therefore, frequently check a 'stop flag' and when this gets set, terminate the current thread (by simply exiting the method, in this case). You just need to provide a property on the class the thread is operating on so callers can ask the thread to stop.
It's no different in C++ or Java.
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.
I would like to know and understand this code snippet
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(navigatePage)
object:nil];
[queue addOperation:operation];
[operation release];
[queue release];
-(void)navigatePage
//==================
{
[self performSelectorOnMainThread:#selector(loadPageDetails) withObject:nil waitUntilDone:NO];
[myTableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:NO];
}
Thanks for your time.
In a nutshell, the code looks to be designed to do some processing in a background thread -- it is probably fetching some data over the network (loadPageDetails), and then it is updating the UI with the results (reloadData). However, loadPageDetails is being called on the main thread, which I don't understand -- surely that should be done a background thread, if it is time consuming?
Can you give a fuller context for your code? I don't really see the point of using NSInvocationOperation in the above example, because all the operation does is shove more bits of work back on the main thread.
The usual reason for using background processing would be to not block the main thread when doing something that takes time to complete -- I assume the bit of code that sets up the operation queue is called on the main thread?