Preserve Core Data Between Development Distributions - ios

I have a development distribution of an app out on a couple of devices.
Turns out my export functionality causes a memory leak - meaning I can't get that screen to open without reinstalling the distribution of the app.
Is that data totally lost? I'd really like to be able to save it.
Some ideas:
Write a second helper app that could grab the data
Write some sort of shell script that could retrieve the data plugged into a comptuer
Plug in the devices to a computer... do something in Xcode... no lost data?
Is there any hope?
UPDATE
There was hope!
First - Your data is accessible via Organizer in XCode.
Second - New versions in iTunes do not overwrite core data. BUT you're going to want to make sure the version # increases as iTunes was somewhat finicky about sending over the new version. Your testers might be tempted to delete the app - replacing it in iTunes and re-syncing is all they need to do.

If you update the app without deleting it first, the data is not removed by the OS. So the new version of your app has the opportunity to read the old data.

Related

How to get default project with NSPersistentCloudKitContainer up and running?

I followed the same steps as in "Using Core Data With CloudKit":
New project
Enable Core Data + Cloud Kit
Add iCloud/CloudKit entitlement + Background mode/remote notifications entitlement.
In the iPhone Xr simulator I signed into an iCloud account I created (and then verified on icloud.com!) and ran the app, creating multiple entries.
I then signed into the same iCloud account in the iPhone Xs simulator. I ran the app but no entries were merged. Creating entries in this simulator also does not merge back over to the Xr simulator.
What am I missing?
To see the changes with Simulators you have to quit the app, and reload it (or build & run).
Simulators have never been able to receive Remote Notifications to trigger an iCloud sync so you need to manually force a sync, but I've found that syncing cannot be triggered manually from the menu in my Xcode 11 beta (gives an error).
There is a good post by Andrew Bancroft about some other things such as setting the automaticallyMergesChangesFromParent property to true, but this doesn't make a difference when using Simulators (EDIT: It does, but I didn't realise as I was just building & running each time).
Andrew's Post: https://www.andrewcbancroft.com/blog/ios-development/data-persistence/getting-started-with-nspersistentcloudkitcontainer/#where-s-my-data
I'm in the same boat as I can't afford to install any beta software (except Xcode) so I'm going to have to stick with the simulators. But my experience of converting an existing App to CloudKit has been very, very positive. I just had to do three things to my existing project:
Add Background Notification & CloudKit capabilities
Make sure all Core Data attributes & relationships are optional (or have a default value if nil)
Rename NSPersistentContainer to NSPersistentCloudKitContainer
...and that's it! Mind blown.
All my nested many-to-many relationships appear to work perfectly.
I still need to work out how to sync images currently stored as JPGs in the users Documents directory but I suspect they'll need to be stored in Core Data as BLOBs to enable conversion to CKAssets in the background.
Apple now have example code called CoreDataCloudKitDemo.
This includes all the basic stuff and also has additional code which processes the changes when they arrive from the other device.
You need to have the lines
description.cloudKitContainerOptions =
NSPersistentCloudKitContainerOptions(
containerIdentifier: "iCloud.com.developerid.databasename")
to get your local database going to iCloud and creating the schema.
You need to use the Cloudkit Dashboard on the web to see the schema etc.

How does Xcode know which app to replace when updating

I have been working on an app in Xcode (not submitted to the App Store or anything like that) that has a lot of very important data whose loss is insurmountable. The app has recently started crashing on startup; therefore, I have tried to update the code to Swift2 so that it works.
After having Xcode automatically update this app to the new version of Swift, I have been having a major issue: When I re-download the app using a cable plugged into the iMac and the iDevice, the new version of the app does not replace the old one––it adds another app to the device. Why would this be happening, and, more importantly, is there any way to fix that?
The point of this is to retrieve the data which was saved in UserDefaults to the previous version of the app. Hence, I'll do pretty much anything to get that data back.
It is absolutely imperative that I retrieve the data stored in UserDefaults; the data is not stored anywhere else.
You are correct that the key is the bundle ID. We have a main bundle ID for production and a second target with a different ID for testing. Pretty convenient to have different versions of the app on the same device.
The second thing you can check is that the version number in the new project is greater than the version on the original project.
To see what apps and versions are installed on your phone, go to Devices (Shift-Command-2). Select your phone from the list on the left and the manually installed apps will be listed near the bottom. Sometimes this gets covered by the Console messages so you might need to scroll down.
Here's what the Device Manager looks like--I deleted my console logs...
Here is the Installed Apps view. It is behind the console logs so you need to scroll down in the top area...

SharedCoreData using OSX app and iOS App

I am using the source code from https://github.com/jab5990/TestCDiCloud.git. Apparently this source code is the sample code from the WWDC 2012 Session #227 called Using iCloud with Core Data. The original source code does not seem to be available on Apple's website any longer.
I am new to Core Data and I struggle quite a bit with these concepts. The situation is that the data does not get refreshed while both apps are running:
I add data to my mac app (2 first rows)
I start the iPhone 7 app in the simulator (after signing in to iCloud)
The entries from the mac show up
I add more data to the mac app
The data does not show up after several minutes
So on in DetailViewController.m:204 on the iPhone App the Notification NSPersistentStoreDidImportUbiquitousContentChangesNotification is registered, which should mean that changes from the Mac app should be incorporated.
How do I ensure that the data stays in sync.
In the simulator sometimes you need to use the Debug -> Trigger iCloud Sync menu to trigger the sync. It is not automatic like on iOS devices.
If you keep having issues then try these sample apps which include code for handling iCloud account switches, moving from local to iCloud, making backups, storing and fetching backup files in iCloud, etc...
http://ossh.com.au/design-and-technology/software-development/sample-library-style-ios-core-data-app-with-icloud-integration/
BTW that wwdc2012 session is old so I would look at the more recent wwdc2013 session 207 video for things that have changed in iOS7, OSX 10.9
iCloud can take quite some time to transfer files, and then the Core Data framework has to get around to actually importing the files. So several minutes or even longer is not unheard of for a delay.
You can use Xcode to trigger a sync with the Debug menu. That may help. Otherwise, you probably just have to wait, or perhaps quit and relaunch the app.
Welcome to the wonderful world of iCloud debugging.

IPhone Core Data Backup Restore Testing Questions

I'm in the learning stages of IOS development and have a few questions based on some behavior I recognized on my initial testing.
My questions for now will be related to a local ITunes backup.
For one thing, does an app that is not "certified" (an app under development and testing) supposed to get backed up on ITunes? On ICloud? And what about it's core data? I ask this because I watched as it backed up other apps, but not my test app in the progress bar.
Bottom line is, I want to test how a user of my app's [core] data will or will not be restored under 2 situations as follows.
The user drops his phone in a lake and needs to do a COMPLETE RESTORE on a new device
The user deletes my app (after having backed up), then later wants to reinstall the app.
Through a few different iterations, I can not get my app's data back after an app removal and reinstall.
I would like to test this under both local and ICloud backup. From what I can understand, you are not given the option to see what files/apps are backed up and available to restore. Furthermore you are not able to restore individual apps/data? Or am I missing something?
I have not done anything special in terms of "designing for ICloud backup/restore or syncing". I want all data to be available ONLY locally as it is and is currently working great.
I guess my biggest question for the moment is "Are development apps treated like certified apps in the backup and restore processes?"
There is a lot of information out there but it is all rather convoluted. Plus it appears an ICloud backup/restore and an Itunes backup/restore are 2 different animals? Thanks for any guidance.
BTW, I can see the app in the Backup Options, and Backup? is set to yes, however after I backup and look on ITunes, I see all the other apps except my test app.

How to simulate iOS version upgrade?

We need to test our app in the context of an iOS upgrade (e.g., 5.1 -> 6.0). Unfortunately, Apple doesn't allow downgrading devices. We thought of doing it in the simulator, but different versions of the simulator are different environments in themselves. I think we can copy the bundle from one simulator to the other, but that won't migrate the keychain (will it?).
Thanks!
To test a transition from one state (before) to another (after), you need a way to put the app in the before state.
Your app surely won't be running while the OS is being updated, so you really only need to worry about the app starting up and discovering that the OS has been updated. There are a couple options:
Copy all your app's data files from a device running the "old" iOS version (5.1 according to your question) to a device running the new (6.0) version. The organizer in Xcode will let you easily copy your app's "container" from a device to your Mac or vice versa.
Make your app write it's data in the "old" format. It's not uncommon for an app to have methods for reading and writing data in different formats depending on the environment, so it's often easier to get your app to write data out in the old format than to actually copy from an old device.
Whichever path you choose, think about any other places (like user defaults) where you might made OS version-dependent changes and set those back to values that correspond to the previous OS. This applies especially to keychain items, which aren't stored in your app's sandbox.
Unit testing frameworks (like Apple's XCTest framework) generally have a setup mechanism that you could use to reset your app to the before state, including copying files, adding and removing keychain items, setting defaults items, etc. You can then add unit tests that run whatever code might be involved in an update and test the results. With a set of easily repeatable tests you'll be able to debug any problems more easily.
However you approach it, the goal is to put the app in the same state that it would be in if it were running for the first time after an OS update occurred. You don't have to worry about simulating the actual OS update, you only need to trick the app into thinking that the update has just happened.
For now, you can still install iOS 8.2. When a new version is released, Apple leaves both versions open for installation for a short time. While that "signing window" is open you can upgrade a device, test, and then restore it from an image of the older version. So you could do some intensive testing while the window is open, but obviously that's not a long-term solution (it typically lasts only a few days).
If you have the budget for it, you could install 8.2 on a device, put a big sticker on it saying "do not upgrade", and keep it on 8.2 for as long as it's relevant. Install your app on that device and take a backup (with backup encryption enabled so that keychain entries will be included), then restore that backup to another device that's on 8.3 - this is basically the same procedure you'll go through when doing an upgrade/restore through iTunes so it should be pretty close. It won't be exactly the same as an OTA update on-device of course, but for that, see option 1 above (and see it soon).

Resources