I am parsing n images using NSUrl delegates. But I'm not getting the results in the same order.
How can i make it in the same order of request send?
If you're running these concurrently (i.e. just initiating a whole bunch of NSURLConnection requests), this behavior is not at all surprising because while you may initiate them in a particular order, you have no assurances that they'll necessarily finish in that same order. You could address this by initiating these requests serially (i.e. don't start the next request until the prior one finishes), but I'd discourage you from doing that as you'll pay a significant performance penalty. It is much better to refactor your code to handle the fact that they may complete in a non-sequential fashion, rather than placing an artificial constraint that they must finish in a particular order.
So, it's best to employ a mechanism that supports concurrency, but let's you constrain the degree of concurrency (e.g. namely an operation queue). It's not too hard to wrap your NSURLConnection requests in individual NSOperation subclass objects, but rather than reinventing the wheel, you might want to consider using AFNetworking, which does a lot of this for you.
Related
For my ios app I am using the main queue and root queue. I have several objects and I want their mehtods to run in the root queue.
So far, what I have been doing is add a dispatch_async for each time I call one of those methods which will ultimately become very troublesome when I will use more queues and want to go back to main queue.
What I am looking for is way to assign objects to the root queue so that their methods are executed in the roof queue. What I mean is I am looking for sth. like this: [[TestClass alloc] initInQueue:testQueue];
It is possible to create this in a manner similar to KVO. You could swizzle all your methods to wrap them into dispatch_* calls, but I would strongly discourage it. The level of magic is too high, and you will almost certainly tie yourself up in knots. Moreover, you can't wrap an arbitrary method in dispatch_async since you can't have a return result from that. But you also can't wrap arbitrary methods in dispatch_sync because you would likely deadlock. The problems of solving the general case will quickly spiral out of control in my opinion.
What you should be asking instead is whether your queue architecture is correct. Do you really need to keep calling so many small methods on other queues? In many cases it is better to encapsulate full work units (i.e. a coherent sequence of operations that take an input and generate a final result) rather than individual method calls. (Once you think in work units, NSOperation suddenly gets a lot more useful.) While it is occasionally useful to wrap an accessor into a queue for thread-safety, this is not a general solution to concurrency.
While there are advantages to getting off of the main queue, this advice shouldn't be over-applied. You can do reasonable amounts of work on the main queue without any problems. We built single-threaded Cocoa apps on computers less powerful than iPhones long before GCD. (The iPhone is probably more powerful than my old PowerBooks and might be more powerful than my original MacBook.) I'm not discouraging queues here, just make sure you're doing it for the right reasons and don't overcomplicate things.
But if you really need to move the work, then I would recommend just being explicit with dispatch_ calls in the method itself. It's a little more typing, but it's much clearer and less error-prone.
I have an app that is downloading several photos off of Flickr. Right now, all the photos are downloaded with a custom NSOperation class run on an NSOperationQueue.However, I have heard about NSUrlConnection async being more efficient, and was wondering which is better of this situation? Or, is there a third option that's even better than these two?
The custom NSOperation simply calls [NSData dataWithContentsOfURL:] many times on different photos.
Using an approach which utilizes a subclass of NSOperation and which encapsulates NSURLConnection which is used in asynchronous mode (implementing the delegate protocols) is likely the most efficient, iff you additionally consider these aspects:
Ensure that the NSOperation subclass handles the delegate methods quickly, and that the underlaying thread (or the queue) will NOT be used to process the response data. Ideally, the delegate methods pass over the partial response data to another queue or thread where they are processed (note: image data may be preloaded on a background thread or a queue!).
The reason for this is that, the sooner the network operation finishes, the more requests can be performed per time. The network NSOperation shall be put into a NSOperationQueue whose max concurrent operations is set to 1, or 2. Rarely to 4 or higher. This setting depends on whether the server supports pipelining, and on the speed of the connection. Name that queue "Network bound queue".
The "data process" (preload image data) task is ideally a subclass of NSOperation, too. Likewise, the "data process" operations should be queued in a CPU bound NSOperationQueue. Per default the max concurrent operations of a NSOperationQueue is already suitable for CPU bound operations.
If you want to save the data to disk, again, ideally you create a NSOperation and queue those disk operations in a "disk bound queue". On devices, this seems not necessary, but if you have still such oldish "disks" - than it makes sense to set the number of max concurrent operations to the number of independent heads of the disk. ;)
Well, this all may make only a difference, when the connection is really fast and if you are able to process that much data in the same time. We are talking about 5 Mbyte per second on a device, and probably 25 Mbyte per second on a lab top.
Try these tutorials may help you:
http://maniacdev.com/2010/03/easier-threading-with-nsoperation-for-better-performance
http://www.raywenderlich.com/19788/how-to-use-nsoperations-and-nsoperationqueues
http://www.icodeblog.com/2012/10/19/tutorial-asynchronous-http-client-using-nsoperationqueue/
OR
If you are downloading photos and showing them in table cell, then you can use Lazy loading images.
I would recommend using AFNetworking (AFNetworking on Github)
which has built-in functionality for queuing operations.
If you only use it to load images that need to be displayed in a table view cell, you could use the AFNetworking category on UIImageView to load these images asynchronously.
I have an NSArray of links. I want to parse through them with an online article extractor API (Clear Read), and with the result given back for each article (some HTML) I throw it into an NSString.
My problem arises from the fact that, say my array has 100 URLs in it, I loop through the array shooting each item into the API and getting back some results in JSON. This is firing like 100 NSURLConnection calls at once asynchronously.
I wasn't sure if that'd be a problem, but when I give it 100 URLs (real strings, none are nil) the data that comes back often has either empty values for the JSON keys (when they shouldn't), or the data coming back is nil. There's also a bunch of duplicates.
Should I be handling multiple asynchronous connections better than I am now? If so, how?
A couple of thoughts:
If you're doing concurrent asynchronous requests and are using asynchronous NSURLConnection, then you'll want to define your own class for this download operation to make sure that every connection keeps track of its own properties. That way, everything can be encapsulated within this class where the resulting download objects can keep track of what's downloaded, what's been parsed, etc. If you're not using asynchronous NSURLConnection (e.g. you're just using dataWithContentsOfURL), it's even easier, though you lose some of the progress updates that NSURLConnection provides and/or streaming opportunities.
For best performance, you should do concurrent requests. Having said that, you should not have more than four or five concurrent requests going to any particular server. This is an iOS imposed constraint, and especially if you have a slow network connection, you risk having connections timeout otherwise.
If you're doing preliminary testing on the simulator, you may want to make sure you try out the "network link conditioner". It's part of the "Hardware IO Tools for Xcode", available at the Downloads for Apple Developers. There are issues (such as the aforementioned timeout problems if you have too many concurrent requests going to a particular server) that only manifest themselves in slow connections.
Having said that, you also want to make sure to test your solution on a device with real world network speeds. It's easy to successfully run massively parallel tasks successfully on the simulator that are too greedy for the device. Limiting the number of concurrent sessions to five will diminish this resource problem, but it should be part of your testing strategy.
I agree with JRG-Developer, that you should look into established frameworks, such as AFNetworking. Make sure to set the maxConcurrentOperationCount for the queue of the AFHTTPClient, though, if queueing 100 plus operations.
I don't know how much data your 100 requests entail, but be forewarned that the app approval process has been known to reject apps that make extraordinary networks requests on cellular networks. What constitutes excessive cellular network activity is not explicitly stated in the app review guidelines, though Avoiding iPhone App Rejection From Apple has claimed that you should ensure that you don't exceed more than 4.5mb in 5 minutes. You can use Reachability to determine what type of network you are on and perhaps warn the user if they're on cellular (if the amount of data approaches this threshold).
Have you considered using a third party framework - such as AFNetworking - and limiting the number of asynchronous calls happening at once? Perhaps this might help / solve your problem.
In particular, you might consider creating a networking manager class that creates and manages AFHTTPClient(s), which in turn manages AFHTTPRequestOperations, for each endpoint (base URL) you hit.
I am doing a UITableview to download data
the name webservice is very fast, so I use it to populate the table initially, then I start an operation queue for the image.
Then a seperate queue for the rest of data because it loads very slow but that effects the image load time, How can I do the 2 concurrently.
Can you figure out whats slowing the performance there and help me fix it?
As I assume you know, you can specify how many concurrent requests by setting maxConcurrentOperationCount when you create your queue. Four is a typical value.
self.imageDownloadingQueue.maxConcurrentOperationCount = 4;
The thing is, you can't go much larger than that (due to both iOS restrictions and some server restrictions). Perhaps 5, but no larger than that.
Personally, I wouldn't use up the limited number of max concurrent operations returning the text values. I'd retrieve all of those up front. You do lazy loading of images because they're so large, but text entries are so small that the overhead of doing separate network requests starts to impose its own performance penalties. If you are going to do lazy loading of the descriptions, I'd download them in batches of 50 or 100 or so.
Looking at your source code, at a very minimum, you're making twice as many JSON requests as you should (you're retrieving the same JSON in getAnimalRank and getAnimalType). But you really should just alter that initial JSON request to return everything you need, the name, the rank, the type, the URL (but not the image itself). Then in a single call, you get everything you need (except the images, which we'll retrieve asynchronously, and which your server is delivery plenty fast for the UX). And if you decide to keep the individual requests for the rank/type/url, you need to take a look at your server code, because there's no legitimate reason that shouldn't come back instantaneously, and it's currently really slow. But, as I said, you really should just return all of that in the initial JSON request, and your user interface will be remarkably faster.
One final point: You're using separate queues for details and image downloads. The entire purpose in using NSOperationQueue and setting maxConcurrentOperationCount is that iOS can only execute 5 concurrent requests with a given server. By putting these in two separate queues, you're losing the benefit of maxConcurrentOperationCount. As it turns out it takes a minute for requests to time out, so you're probably not going to experience a problem, but still, it reflects a basic misunderstanding of the purpose of the queues.
Bottom line, you should have only one network queue (because the system limitation is how many network concurrent connections between your device and any given server, not how many image downloads and, separately, how many description downloads).
Have you thought about just doing this asyncronously? I wrote a class to do something very similar to what you describe using blocks. You can do this two ways:
Just load async whenever cellForRowAtIndexPath fires. This works for lots of situations, but can lead to the wrong image showing for a second until the right one is done loading.
Call the process to load the images when the dragging has stopped. This is generally the way I do things so that the correct image always shows where it should. You can use a placeholder image until the image is loaded from the web.
Look at this SO question for details:
Loading an image into UIImage asynchronously
I'd like to understand what the difference is between using –initWithRequest:delegate: with delegate methods and +sendAsynchronousRequest:queue:completionHandler:.
Are there some performance differences based on the number of requests, or any other criteria?
sendAsynchronousRequest:queue:completionHandler is an easier call to make. initWithRequest:delegate gives you more control over things like caching, redirects, downloading large or incremental amounts of data, canceling requests, etc, etc.