How perform Some task In Background in iOS - iphone

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
}

Related

Can I stop or cancel loop function when using [NSThread sleepForTimeInterval:2.0]; in IOS

I have a loop function and in it called [NSThread sleepForTimeInterval:2.0];. it mean after 2s, loop function is called. I want when pass new view, this loop function is stop and when back, it is called again.
I use this code to call loop function:
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
loop = YES;
delete=NO;
temp = [FileCompletedArray mutableCopy];
NSOperationQueue *queue = [NSOperationQueue new];
operations = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(updateArray) object:nil];
[queue addOperation:operations];
[operations release];
}
And loop function:
-(void)updateArray{
while (loop)
{
NSLog(#"start loop");
if(loop){
[NSThread sleepForTimeInterval:2.0];
NSLog(#"start send request");
NSURL *url1 = [NSURL URLWithString:#"http://server.com"];
NSMutableURLRequest *afRequest = [httpClient requestWithMethod:#"POST" path:nil parameters:params1] ;
operation= [[AFHTTPRequestOperation alloc] initWithRequest:afRequest];
NSLog(#" request sent");
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Server response1");
}
failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", error);
}
];
[httpClient enqueueHTTPRequestOperation:operation];
}
else
return;
}
}
And viewdisappear()
-(void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
loop = NO;
delete=NO;
[operations cancel] ;
}
My problem is when pass new view, updateArray still call. It not stop. Do you have suggestion?
You can try it using key value observers. You can implement the changes in following method which will be automatically called as a particular value changes. First you have to set the notification for the ivar that is going to be changed.
[self addObserver:self forKeyPath:#"loop" options:NSKeyValueObservingOptionNew context:nil];
Then you have to implement the changes as per requirement in the following method:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
There are a couple of issues that leap out at me:
If your intent is to actually cancel the sleepForTimeInterval, I don't believe you can do that. There are other mechanisms (such as timers) that are much better suited for that problem.
As an aside, you are issuing an asynchronous request every two seconds. But you have no assurances that your previous request will have completed in that period of time, though. As a result, you can end up with a backlog of multiple network requests that will continue to run after the view is dismissed.
I would have thought that you'd want to initiate the "wait two seconds" inside the completion block of your asynchronous request, to ensure your requests don't get backlogged behind your "every two seconds" logic. Clearly that won't work with your current while loop unless you make the request synchronous, so you might refactor this code, replacing the while loop with something that performs a single request, and in the completion block, waits two seconds before initiating the next request.
You are checking the state of loop, waiting two seconds, and then issuing your request. So if the view disappeared while it was performing the two second sleep, there's nothing here stopping the request from being issued after you finished sleeping.
At the very least, if you're going to use sleepForTimeInterval, you presumably want to check loop state after you finish sleeping. But, to my first point, it's better to use some cancelable mechanism, such as a timer.
If you're saying that your loop never exits, I'd suggest you check to make sure the appearance methods are getting called like you think they should be.
Personally, I'd be inclined to do this with a timer which can easily be canceled/invalidated:
Define my properties:
#property (nonatomic, strong) NSTimer *timer;
#property (nonatomic, getter = isLooping) BOOL looping;
#property (nonatomic, weak) AFHTTPRequestOperation *operation;
Have my appearance methods set the looping variable and start/stop the scheduled requests as appropriate:
- (void)viewDidAppear:(BOOL)animated
{
self.looping = YES;
[self scheduleRequestIfLooping];
}
- (void)viewWillDisappear:(BOOL)animated
{
self.looping = NO;
[self cancelScheduledRequest];
}
The methods that do the starting and stopping of the scheduled requests would use the NSTimer:
- (void)scheduleRequestIfLooping
{
if ([self isLooping]) {
self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(initiateRequest:) userInfo:nil repeats:NO];
}
}
- (void)cancelScheduledRequest
{
[self.timer invalidate];
self.timer = nil;
// you might want to cancel any `AFHTTPRequestOperation`
// currently in progress, too
[self.operation cancel];
}
Note, whether the cancel method should cancel both the timer and any current request in progress (if any) is up to you.
Finally, put the scheduling of the next request inside the completion block of the current request.
- (void)initiateRequest:(NSTimer *)timer
{
// create AFHTTPRequestOperation
AFHTTPRequestOperation operation = ...
// now schedule next request _after_ this one, by initiating that request in the completion block
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Server response1");
[self scheduleRequestIfLooping];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error: %#", error);
// not sure if you want to schedule request if last one failed
}];
self.operation = operation; // save this in the property
}
In the above, I'm using the main thread for the timer. If you really want to do it on a background queue, you can, but (a) it seems unnecessary to me as the network requests already happen on a background thread; and (b) if you do this on a background thread, you might want to make sure you're doing the necessary thread-safe handling of your state variables and the like. It just seemed like an unnecessary complication to me.

How to stop a task initiated using NSOperationQueue?

I have created a process using NSOperationQueue in the below way:
queue = [[NSOperationQueue alloc]init];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:#selector(loadDataWithOperation)object:nil];
[queue addOperation:operation];
[operation release];
In the loadDataWithOperation method I wrote code for printing infinite numbers.
Now I have called cancelAppOperations to stop its execution and also I have tried to set suspended value to YES like this
[queue setSuspended:YES]
even though the process is still running, I am calling the stoping method by using "stop"button. It is calling in the same class.
How can I stop it?
You can send a cancellation message to all operations in the queue before they begin executing, but if your operation is already executing you need to process the cancel message
Here for suspend of queue
[queue setSuspended:YES] is working fine,there I check the condition for stop the For loop i.e
if(![queue isSuspended])
{
NSLog(#"elements are :%d",i);
}
else
{
break;
}
I placed these lines of code in "loadDataWithOperation" method

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.

Help me to understand this code snippet

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?

iphone ios running in separate thread

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