So I'm able to delete image cache's, but is there a way to delete files in the storage for the app? For example, if you go to Settings > General > Storage And iCloud Usage > Manage Storage and then find your app. I want to clear this data, because it keeps building up. Any insight on this?
This is what I currently have:
var documents = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
var cache = System.IO.Path.Combine(documents, ".config", ".isolated-storage", "ImageLoaderCache");
foreach (var file in System.IO.Directory.GetFiles(cache))
{
//older than or 3 days, delete
DateTime fileCreationDate = System.IO.File.GetCreationTime(file);
if ((DateTime.Now - fileCreationDate).Days >= 3)
{
System.IO.File.Delete(file);
}
}
Instead of storing cached images in Document (<Application_Home>/Documents) folder, Store it in Cache (<Application_Home>/Library/Caches) folder.
According to iOS data Storer Guidelines If you are storing something in document directory, it means you want to backup it on iCloud.
so when data is store in document directory- its getting uploaded to iCloud. and thats why its displaying in iCloud storage.
Related
3 files are generated when using CoreData
xxx.sqlite
xxx.sqlite-shm
xxx.sqlite-wal
Since our app has a feature, to export the SQLite file, we would like to perform WAL checkpoint on demand, to "merge" WAL & SHM into .sqlite file.
We thought by "closing" the opened database should be able to accomplish such.
We tried
func forceWALCheckpointingForStore() {
do {
let persistentStoreCoordinator = persistentContainer.persistentStoreCoordinator
let stores = persistentStoreCoordinator.persistentStores
for store in stores {
try persistentStoreCoordinator.remove(store)
}
} catch {
error_log(error)
}
}
3 files are still visible instead of 1 .sqlite file
Based on an answer 7 years ago - Force a Core Data Checkpoint? It seems that it is not possible to achieve so via CoreData.
I was wondering, is it possible in to-date? Is it possible to perform CoreData WAL checkpoint to "merge" everything into a single SQLite file?
I'm building an iOS app with data stored in Firestore and associated images stored in Cloud Storage for Firebase. Essentially, my app's starting screen is a scrolling list of cards representing documents from one of my Firestore collections and an associated image (pulled from Cloud Storage, matched using document title).
To generate the starting scrollview data, each time I open my app, I run a call to both Firestore and Cloud Storage to populate my local structs and retrieve the images (around 10 of them, each 600px by 400 px and between 300-500 KB).
I'm currently on the free Spark plan. My quotas are fine for Firestore, but yesterday, I was testing the app in the simulator (maybe ran it ~60 times?) and exceeded the 1 GB bandwidth limit for Cloud Storage calls. I think this is because I'm downloading a lot of images and not storing them locally (because I download them again each time the app is run?).
Here's the code that runs each time the app is opened to get all of the data and associated images:
// StoryRepository.swift
import Foundation
import FirebaseFirestore
import FirebaseStorage
import FirebaseFirestoreSwift
class StoryRepository: ObservableObject { // listen to any updates
let db = Firestore.firestore()
let storage = Storage.storage()
#Published var stories = [Story]() // Story is a local struct with vars for title, previewImage (the associated card image I get from Cloud Storage), and other data in Firestore.
init() {
loadStoryCardData()
}
func loadStoryCardData() {
db.collection("stories").addSnapshotListener{ (querySnapshot, error) in
guard let documents = querySnapshot?.documents else {
print("Error fetching documents: \(error!)")
return
}
// create Cloud Storage reference
let storageRef = self.storage.reference()
// each document represents a story. get the title of that story, and then fetch the image from Cloud Storage that has the same filename as that title.
documents.forEach { document in
guard let title = document["title"] as? String else {
print("Could not read story title.")
return
}
let primaryImageRef = storageRef.child("storyCardPrimaryImages/" + title + ".jpg")
// Download in memory with a maximum allowed size of 1MB (1 * 1024 * 1024 bytes)
primaryImageRef.getData(maxSize: 1 * 1024 * 1024) { data, error in
if let error = error {
print("Error fetching primary image: \(error)")
return
} else {
if let image = UIImage(data: data!) {
self.stories.append(Story(title: title, previewImage: image, data: document.data())!)
}
}
}
}
}
}
}
I'm just wondering how to optimize this, because when I release this app and gain users, I can just imagine where my bandwidth will go. Should I store the local structs and images in the iOS FileManager so I only download them once, when the app first runs? How will I update the local data should anything in either Firestore or Cloud Storage change?
I thought about storing the images in a smaller size, but I really need them to be 600px by 400px in my app. I'd prefer to stay on the free Spark plan if possible. Honestly, I'm just a little taken aback that I've already run into quota limits while testing – when it's just me running the app. Overall, I'm at a bit of a loss – any advice would be really, really appreciated.
Should I store the local structs and images in the iOS FileManager so I only download them once, when the app first runs?
Using a local cache like this is definitely one good way to reduce the total bandwidth use.
How will I update the local data should anything in either Firestore or Cloud Storage change?
That will be for you to engineer. In general, one way to do this would be for your process that updates the objects in storage to also update some metadata about the image, and store that in Firestore. Your app can query Firestore, for changes, then check to see if your locally cached files are up to date before downloading them again.
I thought about storing the images in a smaller size, but I really need them to be 600px by 400px in my app.
You can always increase the amount of JPG compression, which will also reduce the quality of the image. That's a tradeoff you'll have to experiment with to your preference.
I'm writing a program that uploads images to Azure blob storage and stores them in folders. The images are stored in an image array before they're uploaded.
Now I want to be able to retrieve a folder of images and store it back in an image array.
Do I need to create a blobContainer locally with the folder name I'm looking to download and then download it?
Or can I only download the images one by one.
//Creating the Container
let blockBlob = blobContainer.blockBlobReference(fromName: "folderName")
blockBlob.properties.contentType = "image/png"
//Download the container
blockBlob.download(to: imageArray, completionHandler: {(NSError) -> Void in })
Is this the correct idea for how this should be done?
For now, we can't download the whole container/folder using one single API/SDK operation according to Azure Blob REST API.
So your second assumption is right--download your images to local stream/file one by one in a loop.
You can add one more DownloadBlob step in ListBlobs process.
Update
Get your folder aka the directory using method directoryReferenceFromName in container.
Then use listBlobsSegmentedWithContinuationToken to list and download blobs in directory. And the count method is also available.
Is it possible to load data from app's local database in app extension?
I have one requirement to use app's local database in app extension.
Is it possible? if yes then give some sources.
The only way you can share data between the main app and the extension is through userDefaults with suiteName by using app groups , so if you can write all your data from database to defaults then it'll be shared , but the problem is that it's not a recommended way as always defaults holds configuration data , also extension must be launched first so app can read data from it
You have to use Application group identifier, the you can share data with the NSUserDefaults. https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html
You can use the same Application group identifier to acces a shared directory:
NSURL *groupURL = [[NSFileManager defaultManager]
containerURLForSecurityApplicationGroupIdentifier:
#"com.yourapp.domain"];
Extension can use the network to fetch data.
You can share everything between a host app and its app extensions:
Keychain via keychain sharing
UserDefaults via app groups
Files via app groups
Database via SQLite file and app groups
To share a database between host app and extension you simply put the database file into the shared storage of the app group. This way, any change in the database of the host app is instantly available in the database of the extension and vice versa. With the CoreStore framework it is very easy to set up a database in the app group storage:
import CoreStore
let dataStack: DataStack = {
let dataStack = DataStack(xcodeModelName: "App")
let storagePathUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.company.App")!.appendingPathComponent("App.sqlite")
do {
try dataStack.addStorageAndWait(SQLiteStore(fileURL: storagePathUrl, configuration: "Default", localStorageOptions: .
recreateStoreOnModelMismatch))
} catch let error {
print("Cannot set up database storage: \(error)")
}
return dataStack
}()
An example to insert a user object (User must be definded in your App.xcdatamodeld) into the database would then be:
dataStack.perform(asynchronous: { transaction in
let user = transaction.create(Into<User>())
user.email = "user#test.com"
user.name = "test"
}, completion: { _ in })
Please note that you must handle locking by yourself if host app and extension run at the same time and write to the database at the same time.
I want to allow my app to download images from the web to be placed in /images and then displayed in the UI - this is to allow branding specific images to be downloaded for a multitenant app.
The app downloads the image fine and places the image into the /Images folder
However when trying to load the image using UIImage.FromFile it always returns null - even though I know full well the image is there!
I know UIImage.FromBundle caches stuff so I chose to use FromFile but this doesn't seem to work?!
Is there something I need to do to make this work? Or am I pushing my luck a little?
I am using the following to create the file path:
public static UIImage SafeClaim_Logo = UIImage.FromFile(NSBundle.MainBundle.BundlePath +"/Images/Logo.png");
The following is the code I use to download and save the file - the file path from the above is the same below when I inspect it
HttpClient client = new HttpClient ();
var clientResponse = await client.GetByteArrayAsync(url);
using (FileStream fs = new FileStream(NSBundle.MainBundle.BundlePath + path, FileMode.OpenOrCreate))
{
var bytes = clientResponse;
fs.Write(bytes, 0, bytes.Length);
}
The app bundle is read-only so you can't change or add something in there at runtime.
All content created at runtime should be stored in your documents or cache folders.
You can get the documents folder by calling:
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)
One good place to store this kind of files is the Library/ folder. On iOS 7 you can access it using:
var libraryFolderPath = Path.GetFullPath(
Path.Combine(Environment.GetFolderPath(
Environment.SpecialFolder.MyDocuments), "..", "Library"));
On iOS 8:
var url = NSFileManager.DefaultManager.GetUrls (
NSSearchPathDirectory.LibraryDirectory, NSSearchPathDomain.User) [0];
var libraryFolderPath = url.Path;
The reason is explained by Xamarin documentation:
The Library directory is a good place to store files that are not
created directly by the user, such as databases or other
application-generated files. The contents of this directory are never
exposed to the user via iTunes.
You can create your own subdirectories in Library; however, there are
already some system-created directories here that you should be aware
of, including Preferences and Caches.
The contents of this directory (except for the Caches subdirectory)
are backed up by iTunes. Custom directories that you create in Library
will be backed up.
If you need to enable iTunes file sharing and expose the content of the Documents/ folder, your files are not visible to the user.