I am using FMDatabase for sqlite based iphone application. The problem is that application is fetching bulk data from a web service and inserting into a local sqlite database which is blocking UI [main thread]. Also we cannot run sqlite related commands in background thread. Can we use NSOperation here ? Any example ??
You should be able to run your SQLite operations in the background, as long as you only run them inside that thread and not from the main or any other.
You could use a NSOperationQueue to handle this, setting the max number of concurrent operations to 1 to make sure only one writes to your SQLite at a time and then calling NSInvocationOperations to save your data.
NSInvocationOperation * invocation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(writeThisToDB) object:thisObject];
[operationQueue addOperation:invocation];
Related
I have an array containing audio file url's. I want to fetch audio files from server using these url's in background mode. I have heard that i can achieve this with NSOperationQueue. My query is
1)How can i achieve this.
2)How can i get call back on single operation completion/failure
3)How can i get call back after completion of the whole process.
I need these call backs to keep track of downlaod process so that i can update my database about the download status of files. So, in case any internet connection loss i can download the remaning files again.
Any idea will be helpful as i am new to NSOperationQueue.
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(download:) object:aAudio];
[queue addOperation:operation];//added code
[operation release];
now do stuff what u want in method download. as per doc set [queue setMaxConcurrentOperationCount:1] for one by one.
Seems like AFNetworking has all that you need (callback blocks for success / failure, puttings requests in NSOperationQueue). In your case probably AFHttpClient and its enqueueHTTPRequestOperation method will do the job.
I am writing location based app, get weather information through API by using NSURLConnection for current/other places .At first time I sent request its working successfully. But next time I want to refer the information for same place it not working while NSURLConnection is not call the any delegate methods.
this is my code:
NSString *strs=[#"http://www.earthtools.org/timezone-1.1/" stringByAppendingString:[NSString stringWithFormat:#"%#/%#",place.latitude,place.longitude]];
NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:strs]];
self.reqTimeZone=[NSURLConnection connectionWithRequest:request delegate:self];
[self.reqTimeZone start];
I assume you mean NSURLConnection (NSConnection doesn't exist). NSURLConnection can only be used once. See Reusing an instance of NSURLConnection.
Another gotcha with NSURLConnection is that it must be ran on a thread with a runloop. The main thread automatically has a run loop, but methods called on GCD and NSOperation threads need to have the runloop created explicitly. In practice you probably don't need to run NSURLConnection on a background thread. The download operation will not block the main thread. If you do decide to run NSURLConnection on a run loop the easiest way to do it is probably to create an NSOperation subclass and create the run loop inside of -main.
I need to show an Activity Indicator to the user during a database operation that takes some seconds.
I have the UIActivityIndicator configured and working, but when I call [myActivity startAnimating]; and the next call is to do the database operations it never shows me the activity.
I think this could be solved by doing an asynchronously access to the database, but I don't know how to do this.
Thank for any related information.
The Main UI is probably freezing when you execute your database query, hence the frozen animation.
How about running the database operation in a background thread:
[myActivity startAnimating];
[self performSelectorInBackground:#selector(someMethod) withObject:nil];
-(void)someMethod {
// do something in the background here.
// long running task
[myActivity performSelectorOnMainThread:#selector(stopAnimating) withObject:nil];
}
One thing to note, if you use Core Data on the background thread to update date you must synchronize them so the changes appear on the main thread (read up on Core Data / Threading for more info)
I have an iPhone app, where I'm displaying a tableview, that's loaded from an RSS feed. When the view is loaded, I call this method to run in a new NSThread:
- (void)start:(NSURL*)url {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSXMLParser *XMLParser = [[[NSXMLParser alloc] initWithContentsOfURL:url] autorelease];
[XMLParser setDelegate:self];
if (items) {
[items release];
}
items = [[NSMutableArray alloc] init];
[self startParsing:XMLParser];
[pool drain];
}
It's working fine, but if the user leaves the view while it's downloading or parsing the xml, I want the thread to stop running, but how would I stop it from running without leaking memory? Also, if it's running the -initWithContentsOfURL: method while I want it to stop, how would I stop that method?
If you anticipate needing to control connections (i.e. stopping a connection if the user cancels or navigates away) you should probably use the asynchronous NSURLConnection API to load your data before parsing the XML. In addition to giving you the ability to close connections as needed, you'll also be able to better respond to network errors.
As NSD pointed out, you should probably implement some sort of cancel method on the class that's driving your XML parsing thread - then just use performSelector:onThread:withObject:waitUntilDone: (or similar) from your main thread when the user cancels the download or navigates away.
These are your thread stopping options
http://developer.apple.com/mac/library/documentation/cocoa/reference/Foundation/Classes/NSThread_Class/Reference/Reference.html#//apple_ref/doc/uid/20000311-DontLinkElementID_12
And from elsewhere in the guide
"If you anticipate the need to terminate a thread in the middle of an operation, you should design your threads from the outset to respond to a cancel or exit message."
Perhaps you should look into the NSOperation and NSOperationQueue classes.
These classes give you a massive amount of control over concurrency and asynchronous execution.
The basic idea is to create a queue, and then subclass NSOperation. Inside your subclasses' main method, do the guts of your work, in this case, you could put your start method inside here.
Then you can control the operation easily, being able to set how many operations can run concurrently, set up any dependencies some operations may have on others. You can also easily cancel operations, which is what you want to do here.
Check out the documentation for NSOperation and NSOperationQueue.
I've been looking for some concrete scenarios for when NSOperation on the iPhone is an ideal tool to use in an application. To my understanding, this is a wrapper around writing your own threaded code. I haven't seen any Apple demo apps using it, and I'm wondering if I'm missing out on a great tool instead of using NSThread.
The ideal solution here would be to describe a use-case scenario for NSOperation and how you would use it to solve your problem(s).
Cocoa Is My Girlfriend has a good tutorial on the use of NSOperation and NSOperationQueue. The tutorial makes use of NSOperation to download several webpages simultaneously in separate threads.
Also, see this article from Mac Research.
The way I use it in my iPhone apps is to basically create an NSOperationQueue member in my application delegate and make it available through a property. Then every time I need to run something in the background, e.g. download some XML I'll just create an NSInvocationOperation and send it to the queque.
NSInvocationOperation *operationToPerform = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(updateXML) object:nil];
[[(MyAppDelegate *)[[UIApplication sharedApplication] delegate] sharedOperationQueue] addOperation:operationToPerform];
[op release];
In a word: NSOperationQueue
NSOperationQueue is thread safe (you can add operations to it from different threads without the need for locks) and enables you to chain NSOp objects together.
My Flickr iPhone app, Reflections, uses NSOperation and NSOperationQueue extensively to manage downloading images and XML.
Caveat: Make sure you read, re-read, and understand what the docs mean when they talk about 'concurrency'.
You should also check out this URL:
http://developer.apple.com/cocoa/managingconcurrency.html
All these above answers are great, but make sure you read the article above and make liberal use of this line in your code:
if ( self.isCancelled ) return;
That line wasn't used in the samples provided by Coca is my Girlfriend, and it wasn't until I got crash logs in from the field that I realized this was an issue/concept.
Here is just a very simple implementation but take time to read the tutorials to fully understand everything:
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:#selector(methodToCall)
object:objectToPassToMethod];
[queue addOperation:operation];
I use it for asynchronous processing. It is the best way to get data from web services or to coordinate actions that take significant time to run. Because they are thread safe, asynchronous (doesn't tie up the main thread) and they support dependencies, they are a really great tool for your toolset.
Dependencies allow you to make several separate operations and make sure the execute and succeed or error out in a certain order. This is really great when you need to synchronize a bunch of data but you need parent objects to sync before syncing child objects.
A sample that you can try using Swift
let operation : NSOperation = NSOperation()
operation.completionBlock = {
println("Completed")
}
let operationQueue = NSOperationQueue.mainQueue()
operationQueue.addOperation(operation)