So this question has been asked a bunch of times, but all the answers are to us ASIHTTP library which is no longer supported.
So I was hoping someone could steer me in the right direction.
I download files (images / videos) in my app using NSData and was wondering how to go about displaying a progress bar/indicator that actually tracks the progress of the download (i.e. 20%, 30% etc etc)
Are there any built-in classes that allow file downloads to be tracked with progress updates?
If you have an NSURLConnection delegate then:
the NSURLResponse you receive to connection:didReceiveResponse: will be of type NSHTTPURLResponse. If you access [[response allHeaderFields] valueForKey:#"Content-Length"] you'll get a string with the length of the data you're expecting to receive;
subsequently through the accumulation of data via connection:didReceiveData: you'll know how much data has been returned.
Since you know how many bytes you've received and how many you're expecting you'll be able to work out the percentage pretty easily.
There are several replacement options for ASIHTTP. The leading one is AFNetworking. It includes support for a progress bar for downloads.
Check out ASIHTTPRequest . It is awesome an will do this any many more wonderous things.
http://allseeing-i.com/ASIHTTPRequest/
Related
I have an iOS app written in Swift 3. in one of the modules i need to upload several files into a Web Server concurrently (files are chosen by the user from camera or gallery). i also have to display progress indicator for each file that indicates when upload is in progress and when upload is completed. the files are about 3-4MB each and the number of files is unknown (depends on the user) .
My Question:
should i use the low level GCD api or the higher NSOperation/NSOperationQueue abstraction ?
I have searched a lot but some got mixed answers (some say GCD and other say NSOperationQueue).i'v been struggling with this question a lot and i don't want to start coding only to find out in the end that i picked the wrong approach. (multi-threaded code is challenging anyhow)
Thank you very much!
I think you should go for NSOperationQueue because it will give you more control over your task. NSOperationQueue will provide objects upon which you can also add dependencies if required.
https://developer.apple.com/documentation/foundation/nsoperation?language=objc
I am working on a shopping app where I use web services to fetch data i.e. product list etc. But it takes too much time to load and thus makes my app really slow.
Is there any solution to this problem?
below is the code I've tried to get Product List.
NSURL * Url=[NSURL URLWithString:#"URL/api/product"];
NSData * Data=[NSData dataWithContentsOfURL:Url];
NSString *str=[[NSString alloc]initWithData:Data encoding:NSUTF8StringEncoding];
NSDictionary *jsonDict = [NSJSONSerialization JSONObjectWithData:[strinng dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:nil];
cannot put JSON response because it's too much.
There is no RIGHT or WRONG way way for this. But there are some points which we can consider for fast data loading. I can mention these points and there can be many other points as well:
Use AFNetworking (for objective c) or Alamofire (for swift), for calling web services and getting response.
Don't do too much things in viewDidLoad. Try to do as less as operations.
You can call web service in viewDidLoad or in viewWillAppear(it will get called every time you visit screen)
After getting response update UI on main thread. Refer this post.
If you want to show images from URL's, load it asynchronously. You can use third party library like SDWebImage Or else use extensions provided in AFNetworking and Alamofire
If you want to show list of products in list, use Load More functionality. for this purpose your API's should be smart enough which are implemented using pagination.
Use UITableView or UICollectionView for showing reusable components.
Till now I can highlight these points. If I found anything else, I will update my answer.
It will be better if you show what you did for that, but according to your requirement i will suggest you,
Use AFNetworking to communicate with server, it is little bit faster.
if you send request to server in new ViewController, make sure you are going to send request in viewWillAppear.
Try to avoid get too much data at the same time.
Try to use Asynchronous request means that it will not wait. You use Asynchronous means that it will not wait. means the thread that initiated that operation will wait for the task to finish before continuing.
Just use NSURLSession. It is good API from Apple. Just remember to use dispatch grand central get mainQueue in the completion block to update any UI.
Start loading the data from API when the App Launches (AppDelegate)and store the response data in a model. This way the time lag would be reduced. Also you can try saving the response into CoreData and when the view is loaded you can refresh the data.
Hope this helps.
Nothing can be done on your side to speed up the process when the data you receive is in abundant.
You should split your APIs, probably, one API will give you the list
of products.
Make an API in way to send only request number of products and the
number of products should be based on your phone screen resolution
and number of products that can be shown there. For example, it
could be 4 on iPhone 4 whereas 6 on iPhone 6. On scrolling call that API again to receive another 4 or 6 products.
On clicking a particular product, use another API to get its
contents.
I have a problem regarding the best approach to make an App that has to download and show pdf's, It is fed by a JSON that has links to 147 pdf files, sized between 1 and 2 MB.
Questions:
What is the best approach to download all the files to an iPad?
Shall I use AFNetworking 2.0?
Is NSFileManager the way to save all the files?
Problems I may encounter:
With an asynchronous download, if lost connection or no more space on the iPad, what are the counter mesures?
Are there tutorials or examples that deal with this situation?
Sorry for all the questions but I'm new to this.
Best Regards.
What is the best approach to download all the files to an iPad?
This is really broad as #rmaddy suggested. Specific questions are more easily answered. There are lots of ways you could download a file via an HTTP request to your device each with pros/cons depending on your situation.
Shall I use AFNetworking 2.0?
Sure. You'll get no argument from me. This is a widely used and solid API to interface with HTTP-based resources.
Is NSFileManager the way to save all the files?
Yes. NSFileManager is the class you use to read/write files from/to your app's sandbox.
With an asynchronous download, if lost connection or no more space on the iPad, what are the counter measures?
I'm not 100% certain so I can't speak to exactly what happens in this case. AFNetworking may provide some help by writing to a temporary file during a download, etc....
Are there tutorials or examples that deal with this situation?
I have a sample project on Github that shows a table of files that you can download. You can watch the progress of your downloads, pause each request, resume and cancel as well. When you're done you can view the file you downloaded. It uses AFNetworking and might be useful to you:
https://github.com/chefnobody/StreamingDownloadTest
When downloading large files, the main counsel would be to avoid trying to load these into memory as you download them. Instead, make sure you stream them directly to persistent storage. In terms of handling space-specific errors, just make sure you check NSError objects that are returned to you in completion handlers or the appropriate delegate methods.
If using AFNetworking, you can specify the outputStream of the AFURLConnectionOperation to reference a NSOutputStream that you create, referencing some path in your persistent storage.
See Memory pressure issue while downloading multiple files using AFNetworking for example.
Alternatively, you can use NSURLSession (whether via AFNetworking or you do it yourself) and instantiate a NSURLSessionDownloadTask, which does the same sort of thing.
Google "NSURLSessionDownloadTask example" and you'll find tons of references. The block-based rendition of downloadTaskWithURL is incredibly simple. To do background downloads is a little more complicated and requires delegate-based implementation (see Downloading Files and Handling iOS Background Activity sections of URL Loading System Programming Guide: Using NSURLSession or watch the WWDC 2013 video, What’s New in Foundation Networking.)
Either way, you avoid some of the memory consumption challenges associated with downloading large files.
I have created a simple testing app to learn how to use NSURLSession. This App has to download images from a webservice and present them into a UITableView.
I've already written the first part of the App that reads a list of images urls from the web service, now, I want to display this list.
My doubt is:
given that the list of images could be a really long list, is it ok to create a NSURLSessionDownloadTask for each image?
I thought to create the session in the cellForRowAtIndexPath function and store the NSURLSessions in a NSDictionary using as key the IndexPath of the cell (and probably relying on NSURLCache to avoid to download the same images more than once).
Other solutions:
I can see three more solutions:
Using GCD with dispatch_async
Subclassing NSOperation and essentially store an NSOperation for any image I need to download.
Using a third party library like AFNetwork... but since it is a learning purpose app I prefer to go completely with my code
.
If the multiple NSURLSession isn't a good solution, I'd choose one of those options.
What do you think about this approach?
NSURLSessionTask is fine for a large number of downloads. One advantage of it over some of the other methods you mentioned is that downloads can be cancelled or paused. It also correctly implements concurrency for network operations, which is more difficult than many cats on the internet will lead you to believe (if you don't believe me, view the eskimo's 2010 WWDC session and sample code. NSOperation for network connections is not trivial).
NSURLSessionTask and friends are designed for exactly the kinds of problems you are trying to solve, and it's very well tested.
For a tableview, start the task in tableView:willDisplayCell:forRowAtIndexPath: and cancel (or pause) a task in tableView:didEndDisplayingCell:forRowAtIndexPath:. That will limit the active downloads to the currently visible cells.
Suggestion:
I also came across a similar situation were I need to download about 2000 Image files and 100 Video files. For that purpose I implemented a custom download manager using NSOperationQueue and blocks.
I have added this library to GitHub, please feel free to check the implementation.
IMO whilst it is ok to create an NSURLSessionTask for each image a standard first in first out implementation will cause problems when scrolling through your cells. The reason for this is that downloads will be queued on your NSURLSession and tasks will be executed in the order they've been added to the queue, in other words in a FIFO manner. Imagine a scenario where you've scrolled through a vast number of cells and you have to wait for all downloads to complete in order. You would not only have to wait a long time, you would be making unnecessary network requests for image assets that may no longer be relevant to your user.
Nick Lockwood created a great NSOperationQueue subclass called NSOperationStack that reverses the order of operations so that the the last operation is executed first (LIFO). IMO for a large number of downloads a LIFO implementation is a must.
NSOsperationStack is available here
If you combine this with an implementation that uses cellForRowAtIndexPath to initiate and NSURLCache to store downloads, you should end up with a very streamlined and efficient solution.
I would use (or at least take a look at) SDWebImage's SDWebImageManager.
Besides downloading you can set priority and continue in the background options which I think you'll want to have.
I am currently developing a application which has to be able to show offline videos which need to be downloaded first.
The problem was that these videos can be bigger that the memory that I can allocate to my application. So parts that are downloaded have to be saved immediately instead of saved in a NSData object. I'm hearing conflicting stories on whether or not RESTKit should work, and ASIHTTPRequest seems to be deprecated.
I will follow the suggestion from this thread as it seems to be the best option.
NSURLConnection download large file (>40MB)
Consider using NSURLConnection to download the video file and write the data directly to a file (NSFileHandle).
One advantage of using this method is that the NSURLConnection didReceiveData delegate method is continuously called as data is received, so you can update a progress bar.
Check out AFNetworking for network managing. I am not sure if they have video downloading, but the framework works great for images and other types of downloads that I have down before.
Without explaining all the hasle with dealing with HTTP responses by chunks and streams I would recommend using AFDownloadRequestOperation. It supports resuming downloads and has callbacks for showing download progress. I love it and use it in most of my projects.
P.S. It uses AFNetworking, which is a great framework for making all kinds of HTTP requests.