Executing code after an update - ios

I have a live app that has cached data. When I send out an update on test flight or to the app store I want the app to clear the cached data.
Is there an way to execute a line of code like clearCacheResults() on a update?

You can store the version no in defaults
let version: AnyObject? = NSBundle.mainBundle().infoDictionary!["CFBundleShortVersionString"]
NSUserDefaults.standardUserDefaults().setObject(version, forKey: "appversion")
More info on the bundle keys available here in the doc
First time this will be nil. however on next launch you can retrieve
the previous stored version from defaults
let oldVersion: AnyObject? = NSUserDefaults.standardUserDefaults().objectForKey("appversion")
and compare
if (oldVersion != version) {
// clear cache
}

Related

Does tearing coredata stack will solve model update problem?

suppose latest app release version is version no 20. and there are 10 coredata migrations so far till version no 20.
and for example: a user which is using version 3. directly do auto update to version no 20.
i want to delete coredata stack and rebuild it then.
but does it solve that model update issue ? means version 3 uses v3 data model update (xcdatamodel) and version 20 uses v20 data model update(xcdatamodel).
if i delete and rebuild coredata with below code when user autoupdate app from version 3 to 20.
then will it also point to new xcdatamodel version ?
var allstores : Array = self.storeContainer.persistentStoreCoordinator.persistentStores
for store in allstores{
// remove store file from coordinator
do {
try storeContainer.persistentStoreCoordinator.destroyPersistentStore(at: store.url!, ofType: NSSQLiteStoreType, options: nil)
} catch let error {
print("\(error.localizedDescription)")
}
}
and then rebuild..
self.storeContainer.loadPersistentStores(completionHandler: { (nsPersistentStoreDescription, error) in
guard let error = error else {
return
}
fatalError(error.localizedDescription)
})
Yes. I implemented this strategy once I decided to rebuild the database when it was incompatible with older versions. Side node: now I just rely on CoreData to handle the migration.
To test if it works, create an entity with a non-mandatory field and insert a row for that entity without a value for that field. Now in your new data model, make that exact same field mandatory. Now what you will see is an app crash if you don't destroy the persistent store and rebuild it, as you are showing in your code. However, if you rebuild it, it will work.
Note that the user has lost all of his data, but I presume you already know that. I had some code that queried the database for existing data and it copied the local cache from the server.

Is sharing UserDefaults between iOS and tvOS still possible?

Is sharing UserDefaults between iOS and tvOS still possible?
In my Xcode project I use UserDefaults to share data between my iOS target and my tvOS target. I always receive nil values from my UserDefaults when I try to get data back from my tvOS app.
These are the steps I took to share data:
1: Add App Groups for both targets. Both targets use the same App Group ID:
group.nl.mycompany.myappname.
I use the .nl domain but this should be fine since this also worked for my other projects.
2: Confirm both targets have the same deployment target. I tried using 10.0 and 11.0.
3: Validate the myproject.entitlements that everything is set OK.
4: Validate that on developer.apple.com the App Group is enabled for my bundle identifier.
5: Both targets have the same bundle ID. I also tried using 2 different bundle identifiers.
6: The way I write to UserDefaults from my iOS app:
guard let defaults = UserDefaults(suiteName: "group.nl.mycompany.myappname") else { return }
defaults.set("Apple", forKey: "username")
defaults.synchronize()
I confirm this works in my iOS app by getting the value like so:
guard let defaults = UserDefaults(suiteName: "group.nl.mycompany.myappname") else { return nil }
defaults.synchronize()
let name = defaults.string(forKey: "username")
This indeed returns "Apple".
7: Opening my tvOS app and calling this code returns nil:
guard let defaults = UserDefaults(suiteName: "group.nl.mycompany.myappname") else { return nil }
defaults.synchronize()
let name = defaults.string(forKey: "username")
Is it possible that UserDefaults sharing has been removed? Something similar happened to sharing UserDefaults between your phone and watch link here. I also read that the maximum size of UserDefaults is 500kb for the AppleTV but saving this simple string should be fine.
Apple clearly states in the UserDefaults documentation that
With the exception of managed devices in educational institutions, a
user’s defaults are stored locally on a single device, and persisted
for backup and restore. To synchronize preferences and other data
across a user’s connected devices, use NSUbiquitousKeyValueStore
instead.
As it says, you should use iCloud-based NSUbiquitousKeyValueStore for synchronized data storage.
As for its (NSUbiquitousKeyValueStore) limits, the documentation says
The total amount of space available in your app’s key-value store, for a given user, is 1 MB. There is a per-key value size limit of 1 MB, and a maximum of 1024 keys.

Detect if app starts after backup restore

Is there a way in swift to detect if the app starts after restoring a backup?. Let's say make a backup on a device and restore it into another device.
I tried a solution which seems to work after some testing. I tried several backup restores and it worked fine for me.
The first step would be to save the vendor identifier at the first run of the app:
if UserDefaults.standard.value(forKey: "vendorID") == nil {
if let vendorID = myDevice.identifierForVendor?.description {
UserDefaults.standard.set(vendorID, forKey: "vendorID")
}
}
The second step is to check if the saved vendor id matches the current device's vendor identifier.
Because the vendor id changes after a backup or restoring a backup to a device, I can do other action if the two vendor IDs don't match:
let savedVendorID = UserDefaults.standard.value(forKey: "vendorID") as! String
if savedVendorID == myDevice.identifierForVendor?.description {
//The app can start normally
} else {
//Do action needed after backup restore
}
The vendor id changes under other conditions as well but for my app those changes doesn't matter.

How to remove all UserDefaults data ? - Swift [duplicate]

This question already has answers here:
Delete all keys from a NSUserDefaults dictionary iOS
(18 answers)
Closed 5 years ago.
I have this code to remove all UserDefaults data from the app:
let domain = Bundle.main.bundleIdentifier!
UserDefaults.standard.removePersistentDomain(forName: domain)
print(Array(UserDefaults.standard.dictionaryRepresentation().keys).count)
But I got 10 from the print line. Shouldn't it be 0?
The problem is you are printing the UserDefaults contents, right after clearing them, but you are not manually synchronizing them.
let domain = Bundle.main.bundleIdentifier!
UserDefaults.standard.removePersistentDomain(forName: domain)
UserDefaults.standard.synchronize()
print(Array(UserDefaults.standard.dictionaryRepresentation().keys).count)
This should do the trick.
Now you don't normally need to call synchronize manually, as the system does periodically synch the userDefaults automatically, but if you need to push the changes immediately, then you need to force update via the synchronize call.
The documentation states this
Because this method is automatically invoked at periodic intervals, use this method only if you cannot wait for the automatic synchronization (for example, if your application is about to exit) or if you want to update the user defaults to what is on disk even though you have not made any changes.
This answer found here https://stackoverflow.com/a/6797133/563381 but just incase here it is in Swift.
func resetDefaults() {
let defaults = UserDefaults.standard
let dictionary = defaults.dictionaryRepresentation()
dictionary.keys.forEach { key in
defaults.removeObject(forKey: key)
}
}

Swift 3 Migration Cleared NSUserDefault Data

I'm not sure how to use the new UserDefaults class with the new Swift3 changes.
I had this code prior to the migration to swift3 which successfully retrieved the data stored in the userDefaults:
if NSUserDefaults.standardUserDefaults().objectForKey("profileArray") != nil {
profileArray = NSUserDefaults.standardUserDefaults().objectForKey("profileArray") as! [String]
}
With the migration to swift3 the code is now:
if UserDefaults.standard.object(forKey: "profileArray") != nil {
profileArray = UserDefaults.standard.object(forKey: "profileArray")! as! [NSString]
}
The new syntax makes sense but when I run the project the data that was previously stored in the user default seems to be gone.The userdefault.standard... is now returning empty/nil.
How do I retrieve the data that was stored prior to the swift3 migration?
Appreciate the help with moving to swift3!
I don't know if that solves your problem, but your syntax is not very efficient – you retrieve the object from user defaults unnecessarily twice.
The recommended way is optional binding and the dedicated method to get an array:
if let array = UserDefaults.standard.array(forKey: "profileArray") as? [String] {
profileArray = array
}
Im Swift use always String rather than NSString unless you have no choice.
I have finally figured this out. The userDefaults weren't "cleared". but the userDefaults are specific to a device. so with the migration to xcode8 the iOS simulators were also upgraded....and these are technically new devices where userDefaults had never been captured.
I proved this theory by adding a simulator (you can go back and re-install iOS 9.x simulators) and this worked.
I also tested on a real device using iOS 9.x & the new swift 3 code and the defaults persisted on that device.
So problem solved! :)

Resources