3

Maybe it's the same issue as this one. But few of the solutions that I have tried don't work.

The simulator don't save userdefaults on Xcode Version 9.0 beta 6 (9M214v). I had Xcode 8 as well (together with 9) but removed it.

the code that I'm using:

UserDefaults.standard.setValue("1234567", forKey: "phone")
if let phone = UserDefaults.standard.value(forKey: "phone") as? String{
  //some code here
}

Additionally I have tried:

UserDefaults.standard.set("1234567", forKey: "phone")
if let phone = UserDefaults.standard.object(forKey: "phone") as? String{
  //some code here
} 
ChaosPredictor
  • 3,777
  • 1
  • 36
  • 46
  • 3
    `UserDefaults.standard.synchronize()`? Defaults aren't written to disk until you explicitly make them do it. – Alejandro Iván Oct 02 '17 at 13:30
  • @AlejandroIván [Not necessarily.](https://stackoverflow.com/questions/37485109/is-it-mandatory-to-call-nsuserdefaults-synchronize-method) – Tamás Sengel Oct 02 '17 at 13:35
  • @the4kman well... yeah, you're right. I'm used to synchronize on every write (usually session cookies, user data and pretty much it). In the OP's particular case (reading after writing), I believe this is necessary to ensure data is already saved. Or am I missing something? – Alejandro Iván Oct 02 '17 at 13:39
  • @Alejandro Iván UserDefaults.standard.synchronize() return true after setValue – ChaosPredictor Oct 02 '17 at 13:53
  • There was never a time when it was recommended by Apple to call `synchronize` after every write. Its primary usefulness is prior to program termination or when sharing a user defaults store between multiple applications as a write barrier. NSUserDefaults has automatically handled writing for as long as I can remember. Defaults are absolutely written to disk without your explicitly requesting it (and that is the recommended way to handle it). – Rob Napier Oct 02 '17 at 14:11
  • I still not sure about it, but for me now it's look like a Xcode bug, some kind of stability issue. – ChaosPredictor Oct 03 '17 at 08:51

2 Answers2

5

There are a lot of misunderstandings about what synchronize does and how user defaults are written. Before guessing at how things work, always check the current maintainer's commentary about it. He's pretty clear about things. His analogy to git is also somewhat useful, and see his notes about iOS 8 changes. NSUserDefaults changes way more than you would think it would for such an old piece of tech.

The short and long of it is that calling synchronize is almost never needed in a production app. (In fact, there's recurring discussion about deprecating and removing it.) As the docs note:

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.

And even those cases mostly relate to macOS.

For applications running on iOS 9.3 and later / macOS Sierra and later, -synchronize is not needed (or recommended) even in this situation [synchronizing between processes], since Key-Value Observation of defaults works between processes now, so the reading process can just watch directly for the value to change. As a result of that, applications running on those operating systems should generally never call synchronize.

BUT.....

The usual problem people have with user defaults in the simulator is that they kill the app (hitting stop, restarting the app, crashing) before the write takes place. In production this generally isn't an issue. If you crash right around the time you're writing to user defaults, it's pretty likely you were in a poorly defined state anyway, so whether you wrote garbage, or wrote something good, or didn't write anything is all kind of a toss-up of what you would prefer. But when developing, program termination happens all the time, and often this leads to not writing out the user defaults.

Now one often-seems-to-work solution is to sprinkle synchronize all over the place. But for the most part that just slows your code down. If it works, fine. But in the majority of projects I've worked on, the real solution was just to take a breath before killing the app. It doesn't need a lot of time; just don't kill the app before it has a chance to write the thing you were saving before relaunching to check if it saved.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • thank you, I'm a bit new here (iOS), do you know a good source to learn the right way to work with local storage? – ChaosPredictor Oct 02 '17 at 14:16
  • What do you mean by “local storage?” iOS has several ways to store things locally and it really depends on what you’re storing. BTW since you’re on a beta, there is always a possibility that a particular beta has a bug, though I haven’t heard of any around this. I’d definitely get on the current release and off the beta though. – Rob Napier Oct 02 '17 at 14:23
  • 1
    As a general rule, the definitive docs are on Apple’s site and include the words “programming guide” in their titles (like “File System Programming Guide”). Those are always where you want to start. – Rob Napier Oct 02 '17 at 14:25
  • By "local storage" I mean all the ways to store data in the iPhone, for example if the phone now in airplane mode or doesn't have data connection. – ChaosPredictor Oct 02 '17 at 14:35
  • 1
    Start with the Document-Based App Programming Guide for iOS for the preferred approach for documents. https://developer.apple.com/library/content/documentation/DataManagement/Conceptual/DocumentBasedAppPGiOS/Introduction/Introduction.html#//apple_ref/doc/uid/TP40011149-CH1-SW1 The File System Programming Guide will discuss where to store things on the local file system (documents or otherwise). Core Data PG covers Core Data, if your object graphs are too large for memory. – Rob Napier Oct 02 '17 at 19:24
  • 1
    This is all well and good - unnecessary use of synchronise, and killing the app before the write happens - but the problem I'm having which might be the same as OP, is that the defaults appear to be lost *within the same execution as the one they were written in*. It is losing the defaults before I kill the app. Defaults correctly used on one screen vanish the next time I return to it. Something is really off, and I've spent days trying to work around. If this carries through to production I'm basically going to have to make the decision to cut off support for < iOS 10 as it just doesn't work. – Rob Glassey Oct 07 '17 at 22:36
0

for me I was using a library from git
this library was removing all userDefaults.
As described in this answer

Sultan Ali
  • 2,497
  • 28
  • 25