When (not) to abuse NSUserDefaults

后端 未结 5 1747
予麋鹿
予麋鹿 2020-12-09 15:48

I wonder what the guidelines are for:
1 - how often I can read from NSUserDefaults
2 - how much data I can reasonably store in NSUserDefaults

Obviously, ther

相关标签:
5条回答
  • 2020-12-09 16:33

    I wonder what the guidelines are for: 1 - how often I can read from NSUserDefaults

    quite regularly. expect the defaults' overhead to be similar to a thread-safe NSDictionary

    2 - how much data I can reasonably store in NSUserDefaults

    physically, more than you'll need it to. the logical maximum is how fast you need it to be, and how much space it takes on disk. also remember that this representation is read written to/from disk at startup/shut down and various other times.

    If my game has an option for the computer to be one of the players, I will use NSUserDefaults to save that boolean value. That much is clear. But is it also reasonable to access NSUserDefaults during my game every time I want to know whether the computer is a player or should I be using an instance variable for that instead?

    just add a const bool to the opponent object. zero runtime loss, apart from the memory, which will not be significant.

    Assume here I need to check that boolean every second. Is the answer the same is it's 100 ms instead? What about every 10 s?

    again, it's like a thread-safe NSDictionary (hashing). it will be fairly fast, and fast enough for reading at that frequency. whether it's the best design or not depends on the program. if it becomes huge, then yes the performance will suffer.

    If my game has 50 moving objects and I want their positions and speeds to be stored when the user quits the app, is NSUserDefaults a reasonable place to store that data? What about 20 moving objects? What about 200?

    it would be fine, although i would not read/write via user defaults during game-play; just save/load the state as needed.

    i don't recommend saving all this in user defaults. just create a file representation for your game's state and use user defaults for what it's designed for. if it's huge and you write to it often, then the implementation may flush the state to disk regularly, which could take a relatively long time.

    0 讨论(0)
  • 2020-12-09 16:41

    Don't worry about limits. Instead, ask yourself this simple question:

    Is this a preference?

    If it is a preference, then it should be in user defaults. That's what user defaults is for. If not, then it should be in the Documents directory (or, on the Mac, possibly in Application Support).

    On iOS, you might tell whether it's a preference or not by whether it would be appropriate to (if possible) put it in your settings bundle for display and editing in the Settings application. On Mac OS X, you can usually tell whether it's a preference or not by whether it would be appropriate to put it in the Preferences window.

    Of course, that relies on your judgment. Stanza for Mac, for example, gets it wrong, putting non-preferences in its Preferences window.

    You can also consider the question by its converse:

    Is this user-created data?

    A preference that you will have a default value for is not user-created data; it is user-overridden data. No less bad to lose it, but it informs where you should keep it.

    0 讨论(0)
  • 2020-12-09 16:47

    Hundreds to thousands of items are fine in NSUserDefaults (it's basically just a wrapper around property list serialization). With respect to the overhead for your application, the best thing to do is try it and use a profiler.

    0 讨论(0)
  • 2020-12-09 16:48

    NSUserDefaults is basically a wrapper for loading a NSDictionary from a .plist file from the disk (and also writing it to the disk). You can store as much data in NSUserDefaults, but you have little control over how much memory it uses, and how it reads from the disk.

    I would use different technologies for different information/data.

    • Small bits of data from servers, preferences, user info, et cetera, I would use NSUserDefaults.

    • For login information (access tokens, sensitive data), I would use the keychain. The keychain could also be used for data that should not be deleted when the app is deleted.

    • For large amounts of server data or game data, I would write it to the disk, but keep it in memory.

    In your situation, I would keep it in memory (probably a @property), but I would periodically write it to the disk (perhaps every 1 to 5 times it changes, use an int ivar). Make sure that this disk writing method is in the AppDelegate, so that it won't fail when you close the view controller that is executing it.

    This way, the data is easily accessed, but its also saved to the disk for safe keeping.

    0 讨论(0)
  • 2020-12-09 16:55

    The main performance issue no-one here is mentioning is that the user’s home directory may be on a network volume, and may not be particularly fast. It’s not an ideal situation, but it happens, so if you’re worried about performance that’s what you should be testing against.

    That said, NSUserDefaults uses an in-memory cache, and the cost is only incurred when synchronizing. According to the documentation, synchronization happens “automatically … at periodic intervals”; I believe this only applies if something has changed, though.

    So, for the case of checking whether the computer is a player, using NSUserDefaults once a frame shouldn’t be a problem since it’s cached. For storing game state, it may be a performance problem if you updated it constantly, and as Peter Hosey says it’s a semantic abuse.

    0 讨论(0)
提交回复
热议问题