I have a WKWebView app which i will like to clear a specific cache when image is uploaded .
When i upload an image, the name remains same but the old image will be override with new one, like old image is logo.png, new image will be renamed with logo.png also. But because of cache users will still be seeing the old image.
I have below line of code to clear cache once image has been uploaded and it working fine, but my only problem now is that all cached data is being cleared also.
Is there any way i can clear cache for just the image was uploaded, maybe by passing the image name?
Or just clear cache for images?
static func clearCache(){
let cacheURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
let fileManager = FileManager.default
do {
// Get the directory contents urls (including subfolders urls)
let directoryContents = try FileManager.default.contentsOfDirectory( at: cacheURL, includingPropertiesForKeys: nil, options: [])
for file in directoryContents {
print("CACHE = ", file)
do {
try fileManager.removeItem(at: file)
}
catch let error as NSError {
debugPrint("Ooops! Something went wrong: \(error)")
}
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
From the loop i got this
CACHE =
file:///private/var/mobile/Containers/Data/Application/BFEB788B-9EA4-4921-A902-230869CAC814/Library/Caches/com.myapp.ios.sellers/
CACHE =
file:///private/var/mobile/Containers/Data/Application/BFEB788B-9EA4-4921-A902-230869CAC814/Library/Caches/google-sdks-events/
CACHE =
file:///private/var/mobile/Containers/Data/Application/BFEB788B-9EA4-4921-A902-230869CAC814/Library/Caches/com.apple.WebKit.WebContent/
CACHE =
file:///private/var/mobile/Containers/Data/Application/BFEB788B-9EA4-4921-A902-230869CAC814/Library/Caches/WebKit/
It seems like you need to find the file you want to remove when you are in the for loop loop for files. Remove that specific image when the for loop hits. Right now that for loop removes all cache in directoryContents.
Related
hope you are doing good in development. I have a question regarding Zipping currently i am using Zip framework which I am using for zip the all captured image in device but the problem here is I do not want to save the Zip file in document directory instead I wanna save this memory itself. I am struggling since last week please let me know how can we achieve the zipping without saving it in local directory filepath
Also when I captured the image successfully I saved it to local directory using
let documentsDirectory = FileManager.default.urls(for:
.documentDirectory, in: .userDomainMask).first!
let fileName = "image.jpg"
let fileURL = documentsDirectory.appendingPathComponent(fileName)
if let data = UIImageJPEGRepresentation(image, 1.0),
!FileManager.default.fileExists(atPath: fileURL.path) {
do {
// writes the image data to disk
try data.write(to: fileURL)
print("file saved")
} catch {
print("error saving file:", error)
}
}
After when I am trying to send the image before our server I want to make it all one file so I have implemented the Zip (framework)
Here filpathArray meant all captured image in local path
do {
var urls = [URL]()
for i in 0..<(self.filePathArray.count)
{
urls.append(self.filePathArray[i] as! URL)
}
if self.filePathArray.count > 0 {
let zipFiles = try Zip.quickZipFiles(urls, fileName: "AllFiles")
}
}
Here zipping is done successfully but it saved in local path so when using app container I can able to see the images, I do not want to see the images in device like apple sandbox or Xcode container itself
I want to make zipping on the flow like without saving it document directory, Thanks in advance.
This question already has answers here:
Save An Image To Application Documents Folder From UIView On IOS
(6 answers)
Closed 5 years ago.
I want to in my app, be able to allow users to save large images(jpg) as well as data for each image(txt) and load the images/data. I'm having trouble figuring out where to save these images and text files. Userdefault wouldnt work because of the size of the image files and I don't want to save in the documents directory because then the user can access and potentially corrupt the data.
Where is a good place to save large data files for my app so I can load them later?
You can save and retrieve your files in application directory folder. Also you can use iCloud to save your files.
Use below code if you want to save and retrieve files from Directory folder .
Xcode 8.3.2 Swift 3.x. Using NSKeyedArchiver and NSKeyedUnarchiver
Reading file from documents
let documentsDirectoryPathString = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let documentsDirectoryPath = NSURL(string: documentsDirectoryPathString)!
let jsonFilePath = documentsDirectoryPath.appendingPathComponent("Filename.json")
let fileManager = FileManager.default
var isDirectory: ObjCBool = false
if fileManager.fileExists(atPath: (jsonFilePath?.absoluteString)!, isDirectory: &isDirectory) {
let finalDataDict = NSKeyedUnarchiver.unarchiveObject(withFile: (jsonFilePath?.absoluteString)!) as! [String: Any]
}
else{
print("File does not exists")
}
Write file to documents
NSKeyedArchiver.archiveRootObject(finalDataDict, toFile:(jsonFilePath?.absoluteString)!)
If for some reason you don't want to use the documents directory, or you want those data in a separate folder, or you don't want to permanently save them, you can also create your own temporary directory
saving data as file in a new directory (swift 3):
func saveToMyDirectory(data: Data, filename: String) {
var tempDirectoryURL = NSURL.fileURL(withPath: NSTemporaryDirectory(), isDirectory: true)
tempDirectoryURL = tempDirectoryURL.appendingPathComponent(filename)
do {
try data?.write(to: tempDirectoryURL)
} catch {}
}
Alternative approach: use Apple's UIDocumentInteractionController or UIActivityViewController and let the user choose how to save his/her documents:
https://developer.apple.com/documentation/uikit/uidocumentinteractioncontroller
https://developer.apple.com/documentation/uikit/uiactivityviewcontroller
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
I load a webpage to WKWebview using NSURLRequestReturnCacheDataElseLoad cache policy.There is no need for me to clear the cache unless the
server explicitly tells me to do it. But I am facing trouble clearing the cache, once the server tells me to do it.
Most of the answers and articles suggest that removeAllCachedResponses works, though there are several complaints circulating around
about NSURLCache not working properly with NSURLSession or UIWebView.I couldn't get it to work for me either in iOS 8.4 or 9.3 simulators.
So I used the following code to clear all the files in the cache directory Programmatically. The cached files of the website that I use in my WKWebview
reside in Application/Cache/bundleidentifier. Though, I try and delete all the files I can. When I run the code, I get an error trying to delete /Snapshots
.Now this made me wonder what are some other files in the cache directory that I should not tamper with?
I know the SDWebImage cache and few other files reside in this directory. But, I need to clear the SDWebImage cache anyways.
Here is the code I used to clear cache directory :
public func clearCache(){
let cacheURL = NSFileManager.defaultManager().URLsForDirectory(.CachesDirectory, inDomains: .UserDomainMask).first!
let fileManager = NSFileManager.defaultManager()
do {
// Get the directory contents urls (including subfolders urls)
let directoryContents = try NSFileManager.defaultManager().contentsOfDirectoryAtURL( cacheURL, includingPropertiesForKeys: nil, options: [])
for file in directoryContents {
do {
try fileManager.removeItemAtURL(file)
}
catch let error as NSError {
debugPrint("Ooops! Something went wrong: \(error)")
}
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
Now, is this a good practice ? Are there any obvious methods that I am missing to achieve the same?
Your code is great. I tried to use removeDataOfTypes in WKWebsiteDataStore but it didn't work.
This is #Ashildr solution in Swift 3:
func clearCache(){
let cacheURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
let fileManager = FileManager.default
do {
// Get the directory contents urls (including subfolders urls)
let directoryContents = try FileManager.default.contentsOfDirectory( at: cacheURL, includingPropertiesForKeys: nil, options: [])
for file in directoryContents {
do {
try fileManager.removeItem(at: file)
}
catch let error as NSError {
debugPrint("Ooops! Something went wrong: \(error)")
}
}
} catch let error as NSError {
print(error.localizedDescription)
}
}
It's totally fine to clear the caches directory. And yes, iterating through the contents is the way it is done.
Here's what Apple say:
Use this directory to write any app-specific support files that your
app can re-create easily. Your app is generally responsible for
managing the contents of this directory and for adding and deleting
files as needed.
File System Overview
How would one programmatically save an image generated from a playground to the resources folder?
I have generated some photos through filters in my playground that I would like to save somehow. The resources folder seems like a good fit. What if I wanted to save the image to the desktop?
I've seen this done with saving images for apps, but I just want to save it to my desktop (or a specified folder in a specified location.)
Create folder first in 'Documents' with name 'Shared Playground Data' otherwise app will give error.
SWIFT 5:
let image = // your UIImage
let filepath = playgroundSharedDataDirectory.appendingPathComponent("export.jpg")
let imagedata = image.jpegData(compressionQuality: 1.0)
try! imagedata?.write(to: URL.init(fileURLWithPath: filepath.path))
print("write to \(filepath)")
In Xcode 11, the folder is not in ~/Documents anymore for iOS playgrounds but buried deep in ~/Library/Developer/. You have to print the path and create the Shared Playground Data folder manually to save a file from a playground:
import PlaygroundSupport
// ...
let url = playgroundSharedDataDirectory.appendingPathComponent("example.png")
print(url)
try! image.pngData()!.write(to: url)
Here's how to save it to the shared data directory:
Create a path to the image:
let path = XCPlaygroundSharedDataDirectoryURL.appendingPathComponent("export.jpg")!
(you may need to create the directory ~/Documents/Shared Playground Data/)
Then to save your output (in this case a CIImage from a filter)
let temp:CGImage = context.createCGImage(output, from: output.extent)!
let image = UIImage(cgImage: temp)
let data = UIImageJPEGRepresentation(image, 1.0)
try! data?.write(to: path)
While the first answer helped point me in the right direction, the lack of ability to validate the required playgroundSharedDataDirectory path exists, the requirement to create that directory in order for the path to work, as well as force unwrapping (using !) the try can lead to frustration as well as drag out the process.
Here is a safer, more convenient solution that checks the name you provide for extra safety:
func writeImage(_ image: UIImage, name: String) {
if name.isEmpty || name.count < 3 {
print("Name cannot be empty or less than 3 characters.")
return
}
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
print("No documents directory found.")
return
}
let imagePath = documentsDirectory.appendingPathComponent("\(name).png")
let imagedata = image.jpegData(compressionQuality: 1.0)
do {
try imagedata?.write(to: imagePath)
print("Image successfully written to path:\n\n \(documentsDirectory) \n\n")
} catch {
print("Error writing image: \(error)")
}
}
Call using:
writeImage(image, name: "MyNewImage")
A break down of what is happening:
The method writeImage checks to see if the documents directory exists.
If the documents directory does not exist (unlikely), stop process.
If the documents directory exists, carry on and write the image to the path.
I am caching CKRecord on client and fileUrl of CKAsset too. Can fileUrl change from time to time? Asset / data itself is not changing.
The fileURL of an asset will not change, but if this is an asset you downloaded from the server the data is only guaranteed to exist at that location until the completion block of the operation is called. After that point the asset's backing file may be cleaned up at any time to free up disk space.
After downloading an asset from the server you should move or copy the backing file to another location in your application's container if you'd like to keep it.
The archived URL is a full path, but since iOS 8 or so the container URL that your app uses to store its files changes everytime the app starts.
So the archived URL is wrong.
This seems like a bug in the way CKAssets are archived to me, they should be archiving and unarchiving the partial path relative to the app's container. Not the full path.
I guess I'll file a radar.
Edit: here's a solution:
extension CKAsset {
var url: URL? {
let path = fileURL.path
if FileManager.default.fileExists(atPath: path) {
return fileURL
} else if let index = path.range(of: "/Library/Caches/") {
// archived CKAssets store full-path URLs but since iOS 8 or so
// the path of our container (home-dir) changes every time we are
// started. So the full path is useless. Try to mangle it.
let suffix = String(path.suffix(from: index.upperBound))
let adjustedUrl = URL.caches/suffix
if FileManager.default.fileExists(atPath: adjustedUrl.path) {
return adjustedUrl
}
}
return nil
}
}
public extension URL {
static var caches: URL {
return FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first ?? URL(fileURLWithPath: "")
}
}