在 NSUserDefault 中存储值是否有任何限制?

我是 iPhone 开发和 objective C的新手。 我已经使用 NSUserDefaults在我的应用程序中存储了一些值。 但是我不知道在 NSUserDefaults中存储值是否有任何限制。 谁能告诉我。

先谢谢你。

39973 次浏览

As long as there's enough space on the iPhone/iPad, you can store NSUserDefault values. All those values is stored into a .plist file, and this file is very small, most of the time under 1 kb (unless you store a lot of data).

There is No Limit for storing values in NSUserDefaults..

As far as my knowledge there is no limit for storing in NSUserdefaults.

There are limits on what types you may store: they must all be Property List objects, namely NSString, NSNumber, NSData, NSArray, and NSDictionary. Furthermore, you may only store NSArray and NSDictionary if the values are also property list objects; also, all the keys of the NSDictionary must be strings.

Note that an object like UIColor is not on the above list. So if you want to store a color in the defaults database, you'll need to convert it into a string or data object first, then convert it back when you read the defaults.

As far as size limits, there are none that are documented, but note that all data will be stored as a property list file. The entire file is read in and written out as a whole, so if you use NSUserDefaults to store a large amount of data that only changes in parts, you will be wasting a lot of time doing unnecessary I/O.

It whatever the maximum allowed file size is on the drive. You can use this piece of code to check it out!

NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *myKey = @"key";
int sizeOfFile = 1024; // Fill in proper file size here
NSData myObject;
NSString *someFilePath = @"PathToYourFileHere";


for(int i = 1; i < 9999999999999999; i++)
{
myObject = [NSData dataWithContentsOfFile:someFilePath];
[defaults setObject:myObject forKey:[NSString stringWithFormat:@"%@%i", myKey, i]];
NSLog(@"Iteration: %i, TotalWritten: %i", i, i * sizeOfFile);
}

The only Storage Limitation in NSUserDefaults is the Device Storage Capacity.

As much as there are available Storage Space in an iOS Device, you can practically store data in NSUserDefaults. The key-value pair is stored on a xml structured file (.plist) which is stored in an App Bundle.

The user defaults system and key-value store are both designed for storing simple data types—strings, numbers, dates, Boolean values, URLs, data objects, and so forth—in a property list. The use of a property list also means you can organize your preference data using array and dictionary types. It is also possible to store other objects in a property list by encoding them into an NSData object first.

Everyone has answered the direct question of "is there a limit?" However, I found this thread really looking to understand "how much is too much to store in UserDefaults?"

If you're looking for that answer, here's a useful thread. The responses I found helpful were to go to your project file and look at the plist file size:

5 objects is almost nothing. You'll be fine!


On my machine, I have about 28 megs of data in my user defaults. That's not causing any problems at all.


From general programming experience with arrays I would guess performance starts to rapidly decay when you get into 1000’s, depending on element size. Therefore in a program I wouldn’t have an issue storing a couple of hundred elements. This said I would probably start using a sqlite3 database or coredata, sooner rather than later if I were you.

Important to remember:

The above alleviated my concerns that my growing number of defaults (about 20-25 now) would cause problems. I use CoreData already, so I was considering which to use since my number of allowed user preferences/customizations is growing long. So, I'm going to stay with user defaults.

However, as other answers have pointed out, the file will be read and written as a whole. So reading 20 key/string dictionaries and 5 key/boolean dictionaries just to retrieve one string... not exactly ideal. Nonetheless, if it doesn't hurt performance and it saves you a ton of code, why not?

As many already mentioned: I'm not aware of any SIZE limitation (except physical memory) to store data in a .plist (e.g. UserDefaults). So it's not a question of HOW MUCH.

The real question should be HOW OFTEN you write new / changed values... And this is related to the battery drain this writes will cause.

IOS has no chance to avoid a physical write to "disk" if a single value changed, just to keep data integrity. Regarding UserDefaults this cause the whole file rewritten to disk.

This powers up the "disk" and keep it powered up for a longer time and prevent IOS to go to low power state.

From "Energy Efficiency Guide for iOS Apps":

Minimize data writes. Write to files only when their content has changed, and aggregate changes into a single write whenever possible. Avoid writing out an entire file if only a few bytes have changed. If you frequently change small portions of large files, consider using a database to store the data instead.

READS are no problem, as all values are cached in memory.

EDIT: (July 2019): I just found this very good blog post by Jeffry Fulton.

https://jeffreyfulton.ca/blog/2018/02/userdefaults-limitations-and-alternatives

He describes in detail the different aspects of the user defaults and also writes about some performance tests.

Happy Coding!!!

From iOS SDK codes, and related Apple official document..

extension UserDefaults {




/*!
NSUserDefaultsSizeLimitExceededNotification is posted on the main queue when more data is stored in user defaults than is allowed. Currently there is no limit for local user defaults except on tvOS, where a warning notification will be posted at 512kB, and the process terminated at 1MB. For ubiquitous defaults, the limit depends on the logged in iCloud user.
*/
@available(iOS 9.3, *)
public class let sizeLimitExceededNotification: NSNotification.Name




// ....
}


Summary

  1. Currently there is no limit for local user defaults
  2. On tvOS, where a warning notification will be posted at 512kB, and the process terminated at 1MB.
  3. For ubiquitous defaults, the limit depends on the logged in iCloud user.

As of iPadOS 13.1 beta 3, I'm now seeing the following message when trying to store a larger object (an image).

2019-09-14 11:01:29.634368+0100 MyApp[1686:147223] [User Defaults] CFPrefsPlistSource<0x283c7d980> (Domain: com.example.MyApp, User: kCFPreferencesCurrentUser, ByHost: No, Container: (null), Contents Need Refresh: No): Attempting to store >= 4194304 bytes of data in CFPreferences/NSUserDefaults on this platform is invalid. This is a bug in MyApp or a library it uses

However retrieving the key appears to still work.