In my iOS 9+ Swift 2.2 application, I'm downloading multiple images with NSURLSession's dataWithRequest method :
let session: NSURLSession = NSURLSession(configuration: self.configuration)
let request = NSURLRequest(URL: self.url)
let dataTask = session.dataTaskWithRequest(request) { (data, response, error) in
// Handle image
}
dataTask.resume()
session.finishTasksAndInvalidate()
The question is : How can I limit the image cache size? I can see that my application is using more and more disk space on my device. Is there any way to keep the image cache but to limit the size that my application can use? Is there an expiration by default?
NSURLSession uses shared NSURLCache to cache responses. If you want to limit disk/memory usage of a shared cache you should create a new cache and set it as a default one:
let URLCache = NSURLCache(memoryCapacity: 4 * 1024 * 1024, diskCapacity: 20 * 1024 * 1024, diskPath: nil)
NSURLCache.setSharedURLCache(URLCache)
You could find a little more about caching here.
Related
I am on iOS 14.2...
I have a URLSession that i configure that way:
private lazy var backgroundURLSession: URLSession = {
let config = URLSessionConfiguration.background(withIdentifier: "background-download")
config.sessionSendsLaunchEvents = true
config.httpMaximumConnectionsPerHost = 2
config.timeoutIntervalForRequest = 120
return URLSession(configuration: config, delegate: self, delegateQueue: nil)
}()
I give it like 100 URLs to download
let downloadTask = session.downloadTask(with: offlineTile.url)
downloadTask.resume()
and even with httpMaximumConnectionsPerHost = 2 the server gets ALL requests at ONCE... ?!?
What could I be doing wrong
One more note: We have a Varnish Cache in the background... and noticed that the behavior differs, if Varnish is set to pipe (no caching)
In our case it was the load balancer of our server that did not properly to it's https termination, which caused iOS to send all requests at basically once.
I use a URLSession data task to download several JPG images from a backend. As the images are rather large in size (~500 KB) I want to cache the respective responses until they have expired (i.e. they have exceeded their max-age).
This is the code I use for downloading the images:
let request = URLRequest(url: url,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
let task = URLSession.shared.dataTask(with: request) { (data, _, error) in
// Error:
guard let imageData = data, error == nil, let image = UIImage(data: imageData) else {
DispatchQueue.main.async {
completion(nil)
}
return
}
// Success:
DispatchQueue.main.async {
completion(image)
}
}
task.resume()
Curiously, this works great with caching for all images except for one. For some reason, this particular image is always downloaded again – its response is not cached.
The only difference between the responses that I can spot is that the image whose corresponding response is not cached has the biggest file size. While all other images are < 500 kB, this particular image is slightly > 500 kB.
I've played around with the shared cache size and set it to a ridiculously high value, with no effect:
URLCache.shared = URLCache(memoryCapacity: 1000 * 1024 * 1024,
diskCapacity: 1000 * 1024 * 1024,
diskPath: nil)
I've checked that the Cache-Control header field is correctly set in the response:
Cache-Control: public, max-age=86400
and the Age header field is always below max-age, for example:
Age: 3526
What could be the reason for a single response not to be cached?
How can I fix this?
This is not an answer to the question why the shared URLSession does not cache the image and I'm still grateful for any hints or answers to that question.
However, after experimenting some time with my code I figured out that (for whatever reason) the response is always being cached when I use a custom URL session with a default configuration rather than the default shared URL session:
let urlSession = URLSession(configuration: .default)
So if I use:
let task = urlSession.dataTask(with: request) { ... }
instead of
let task = URLSession.shared.dataTask(with: request) { ... }
the caching works as expected – whatever black magic is responsible for that. 🤔
I found a little hint in the docs for URLSession.shared though:
When working with a shared session, you should generally avoid
customizing the cache, ...
In other words, if you’re doing anything with caches, cookies,
authentication, or custom networking protocols, you should probably be
using a default session instead of the shared session.
I am stuck on how to fix something. I currently have an iPhone app that is literally Instagram but just horizontally and paging, where users see friends photos.
Now I have created a function that grabs images from firebase and puts them in an array. Now this works great along with performing a shared URLSession. I noticed my app was running high on memory usage so I added a URLcache, and set the limit on how large it can get, actually is sort of high now that I think about it. But I am still getting high memory (171mb)-, and that's only loading 4 images usage which makes it seem like I am not caching the data right.
I am still learning how to work with URLSessions and also caching so this also might contribute to a problem if I set it up wrong. Online people were saying use SDWebImage, but really, users won't scroll down or be able to scroll down fast because first paging's enabled and also it's horizontal. Here is some of my code, please tell me what you think I should do.
urlcache in
viewDidLoad() { //probably too high..
let memoryCapacity = 500 * 1024 * 1024
let diskCapacity = 500 * 1024 * 1024
let urlCache = URLCache(memoryCapacity: memoryCapacity, diskCapacity: diskCapacity, diskPath: "myDiskPath")
URLCache.shared = urlCache
}
// cellforrow
if posts.count != nil {
let pozt = posts[indexPath.row].pathToImage
let url = URL(string: pozt!)
URLSession.shared.dataTask(with: url!, completionHandler: { (data, response, error) in
if error != nil {
print(error?.localizedDescription as Any)
return
}
DispatchQueue.main.async {
cell.myImage.image = UIImage(data: data!)
self.loader.stopAnimating()
}
}).resume()
}
cell.myImage.image = UIImage(named: imaqes[0])
return cell
}
I think almost all programmers on swift using libraries to cache images.
I use KingFisher instead of SDWebImage. Its lightweight and simple to use.
To install:
Podfile:
pod 'Kingfisher'
In terminal:
pod install
In swift file:
import Kingfisher
In your case use it next way:
// cellforrow
if posts.count != nil {
let pozt = posts[indexPath.row].pathToImage
let url = URL(string: pozt!)
DispatchQueue.main.async {
cell.myImage.kf.setImage(with: url!) //Using kf for caching images
}
}
return cell
Maybe you should use .kf.setImage with comletion handler to remove loader. You should get the idea.
Hope it helps
I am using Alamofire for my uploads. I need to upload multiple images and videos to my server.I need to upload images and videos to in background session even
let bundleIdentifier = Bundle.main.bundleIdentifier
let configuration = URLSessionConfiguration.background(withIdentifier: bundleIdentifier!)
configuration.timeoutIntervalForRequest = 200 // seconds
configuration.timeoutIntervalForResource = 200
self.alamoFireManager = Alamofire.SessionManager(configuration: configuration)
I am using above code setup alamofire for background configuration.
alamoFireManager?.upload(data!, with: (router))
.uploadProgress { progress in // main queue by default
print("Upload Progress: \(progress.fractionCompleted)")
}.validate()
.responseJSON { [weak self] response in
}
but my app is crash when i went to background with SIGABRT
let me know what i am doing wrong,
This is a limitation of Apple's NSUrlSession implementation. Apple doesn't allow usage of NSData for background sessions. But uploading files are allowed. So as a workaround, you can try writing the data to a file and upload that file instead. You can follow the implementation here:
https://stackoverflow.com/a/22107789/1921759
I am using a NSURLSessionDataTask to get JSON data from a device that opens an adhoc-WiFi which is joined by an iPhone. (The connection is running via TCP).
The device is pretty slow - it takes roundabout 5sec to send the particular response.
After firing the request via dataTask.resume() my app is just waiting for the completionHandler to be called.
Unfortunately the request is fired again and again (each after a delay of ~ 1 sec). I guess this is initiated by the dataTask or NSURLSession. I can monitor the repeated requests when debugging the device.
Here's the code I'm using:
let URL = NSURL(string: "<myURL>")!
let configuration = NSURLSessionConfiguration.ephemeralSessionConfiguration()
configuration.HTTPShouldUsePipelining = false
configuration.HTTPMaximumConnectionsPerHost = 1
configuration.allowsCellularAccess = false
configuration.timeoutIntervalForRequest = 30
let session = NSURLSession(configuration: configuration)
let dataTask = session.dataTaskWithURL(URL) {
// the request gets fired repeatedly before this completionHandler is called!
(data, response, error) -> Void in
...
}
dataTask.resume()
Does anyone know how to prevent iOS from re-firing these requests?