-
-
Notifications
You must be signed in to change notification settings - Fork 2k
iOS_advance
MMKV is an efficient, small, easy-to-use mobile key-value storage framework used in the WeChat application. It's currently available on Android, iOS/macOS, Windows, POSIX and HarmonyOS NEXT.
There are some settings on MMKV that tune things to suit your need.
-
By default, MMKV prints log to console, which is not convenient for diagnosing online issues. You can set up MMKV log redirecting on App startup. Implement protocol
MMKVHandler, and pass the handler on initialization:@interface MyHandler : NSObject <MMKVHandler> @end @implementation MyHandler - (void)mmkvLogWithLevel:(MMKVLogLevel)level file:(const char *)file line:(int)line func:(const char *)funcname message:(NSString *)message { const char *levelDesc = nullptr; switch (level) { case MMKVLogDebug: levelDesc = "D"; break; case MMKVLogInfo: levelDesc = "I"; break; case MMKVLogWarning: levelDesc = "W"; break; case MMKVLogError: levelDesc = "E"; break; default: levelDesc = "N"; break; } // use your own logging tool //NSLog(@"[%s] <%s:%d::%s> %@", levelDesc, file, line, funcname, message); } @end // On App startup MyHandler *handler = [[MyHandler alloc] init]; [MMKV initializeMMKV:nil logLevel:MMKVLogInfo handler:handler];
As for a logging tool, we recommend using xlog, which also comes from the WeChat team.
-
You can turn off MMKV's logging once and for all on MMKV initialization(which we strongly discourage):
You should never turn MMKV's log off unless you have very strong evidence that it makes your App slow.[MMKV initializeMMKV:nil logLevel:MMKVLogNone];
-
By default, MMKV discards all data when there's a CRC check fail, or file length is not correct, which might happen on accidentally shutdown. You can tell MMKV to recover as much data as possible. The repair rate is not promised, though. And you might get unexpected key values from recovery. Implement protocol
MMKVHandler, add the error handling callbacks:- (MMKVRecoverStrategic)onMMKVCRCCheckFail:(NSString *)mmapID { return MMKVOnErrorRecover; } - (MMKVRecoverStrategic)onMMKVFileLengthError:(NSString *)mmapID { return MMKVOnErrorRecover; }
-
You can receive notifications when an MMKV instance's content is changed by another process, or when content is loaded successfully. Implement these optional
MMKVHandlercallbacks:- (void)onMMKVContentChange:(NSString *)mmapID { NSLog(@"content changed by other process: %@", mmapID); } - (void)onMMKVContentLoadSuccessfully:(NSString *)mmapID { NSLog(@"content loaded successfully: %@", mmapID); }
-
By default, MMKV stores file inside
$(Documents)/mmkv/. You can customize MMKV's root directory on MMKV initialization:NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); auto libraryPath = (NSString *) [paths firstObject]; auto rootDir = [libraryPath stringByAppendingPathComponent:@"mmkv_2"]; [MMKV initializeMMKV:rootDir];
-
You can even customize any MMKV instance's location:
auto path = [MMKV mmkvBasePath]; path = [path stringByDeletingLastPathComponent]; path = [path stringByAppendingPathComponent:@"mmkv_3"]; auto mmkv = [MMKV mmkvWithID:@"test/case1" rootPath:path];
-
By default MMKV stores all key values in plain text on file, relying on iOS's sandbox to protect the file from unauthorized access. Should you worry about information leaking, you can choose to encrypt MMKV. MMKV supports both AES CFB-128 and AES CFB-256 encryption. By default AES-128 is used (keys are truncated to 16 bytes). To use AES-256, you must explicitly pass
aes256:YES.NSData *cryptKey = [@"My-Encrypt-Key" dataUsingEncoding:NSUTF8StringEncoding]; auto mmkv = [MMKV mmkvWithID:@"MyID" cryptKey:cryptKey];
-
You can change the encryption key later as you like. You can also change an existing MMKV instance from encrypted to unencrypted, or vice versa.
NSString *mmapID = @"testAES_reKey"; // an unencrypted MMKV instance MMKV *kv = [MMKV mmkvWithID:mmapID cryptKey:nullptr]; NSData *key_1 = [@"Key_seq_1" dataUsingEncoding:NSUTF8StringEncoding]; // change from unencrypted to encrypted with AES-128 key length [kv reKey:key_1]; NSData *key_2 = [@"Key_Seq_Very_Looooooooong" dataUsingEncoding:NSUTF8StringEncoding]; // change encryption key with AES-256 key length [kv reKey:key_2 aes256:YES]; // change from encrypted to unencrypted [kv reKey:nullptr];
-
By default, MMKV caches all MMKV instances in the memory, and cleans them on memory warning. However, MMKV will never destroy them unless specifically call
-[MMKV close]. You can turn on auto clean up by calling+[MMKV enableAutoCleanUp:]after MMKV initialization:// auto clean up instances that not been accessed in 10 minutes [MMKV enableAutoCleanUp:10];
-
You can use MMKV's backup & restore API to backup your data to somewhere else, and restore them later.
auto parentPath = [[MMKV mmkvBasePath] stringByDeletingLastPathComponent]; auto dstPath = [parentPath stringByAppendingPathComponent:@"mmkv_backup"]; auto rootPath = [parentPath stringByAppendingPathComponent:@"mmkv_2"]; // backup one instance (from customize root path) auto ret = [MMKV backupOneMMKV:mmapID rootPath:rootPath toDirectory:dstPath]; // backup all instances auto count = [MMKV backupAll:nil toDirectory:dstPath]; // restore one instance (to customize root path) ret = [MMKV restoreOneMMKV:mmapID rootPath:rootPath fromDirectory:dstPath]; // restore all instances count = [MMKV restoreAll:nil fromDirectory:dstPath];
-
Starting from v1.3.0, you can upgrade MMKV to auto key expiration. Note that this is a breaking change. Once upgraded to auto key expiration, the file is not valid for any older version of MMKV (<= v1.2.16) to operate correctly.
-
Global Expiration. The most simple way to do it is to turn on auto key expiration for all keys in the whole file.
// expire in a day [mmkv enableAutoKeyExpire:MMKVExpireInDay]; // MMKVExpireInDay = 24 * 60 * 60
Or, if you prefer, you can enable auto key expiration without setting a global expiration duration. In this case, each key is not expired by default.
// enable auto key expiration without global duration [mmkv enableAutoKeyExpire:MMKVExpireNever]; // MMKVExpireNever = 0
-
Individual Expiration. You can set a special expiration duration for a key, regardless of whether the file has a global duration or not. Note that you have to enable auto key expiration first.
// enable auto key expiration with an hour duration [mmkv enableAutoKeyExpire:MMKVExpireInHour]; // MMKVExpireInHour = 60 * 60 // set a key with the file's global expiration duration, aka MMKVExpireInHour [mmkv setString:@"some value" forKey:@"key_1"]; // set a special key that expires in two hours [mmkv setString:@"some value" forKey:@"key_2" expireDuration:(2 * 60 * 60)]; // set a special key that never expires [mmkv setString:@"some value" forKey:@"key_3" expireDuration:MMKVExpireNever];
Or, if you prefer, you can enable auto key expiration without setting a global expiration duration. In this case, each key is not expired by default.
// enable auto key expiration without global duration [mmkv enableAutoKeyExpire:MMKVExpireNever]; // MMKVExpireNever = 0 // set a key that never expires [mmkv setString:@"some value" forKey:@"key_1"]; // set a special key that expires in an hour [mmkv setString:@"some value" forKey:@"key_2" expireDuration:MMKVExpireInHour];
-
The expire duration is counted in seconds. MMKV has some pre-defined duration for your convenience. You can use any other duration you prefer. For example, expiration in a week is
7 * 24 * 60 * 60.typedef NS_ENUM(UInt32, MMKVExpireDuration) { MMKVExpireNever = 0, MMKVExpireInMinute = 60, MMKVExpireInHour = 60 * 60, MMKVExpireInDay = 24 * 60 * 60, MMKVExpireInMonth = 30 * 24 * 60 * 60, MMKVExpireInYear = 365 * 30 * 24 * 60 * 60, };
-
You can turn off auto key expiration:
[mmkv disableAutoKeyExpire];Note: Once disabled, the file format stays upgraded. Old MMKV versions (<= v1.2.16) still cannot operate on it.
-
You can query non-expired keys:
size_t nonExpiredCount = [mmkv countNonExpiredKeys]; NSArray *nonExpiredKeys = [mmkv allNonExpiredKeys];
-
MMKV provides several utility methods for inspecting and managing instances:
MMKV *mmkv = [MMKV defaultMMKV]; // size info size_t totalSize = mmkv.totalSize; size_t actualSize = mmkv.actualSize; size_t keyCount = mmkv.count; // import from another instance auto other = [MMKV mmkvWithID:@"other"]; [mmkv importFrom:other]; // manually sync to file [mmkv sync]; [mmkv async]; // reclaim disk space after heavy deletions [mmkv trim]; // clear all with keeping file space (for reuse) [mmkv clearAllWithKeepingSpace];
-
You can check, validate, and remove MMKV storage files:
// check if an MMKV file exists BOOL exists = [MMKV checkExist:@"MyID"]; BOOL existsInPath = [MMKV checkExist:@"MyID" rootPath:customPath]; // validate file integrity BOOL valid = [MMKV isFileValid:@"MyID"]; BOOL validInPath = [MMKV isFileValid:@"MyID" rootPath:customPath]; // remove MMKV storage files [MMKV removeStorage:@"MyID" rootPath:nil];
-
Starting from v2.4.0, you can open an MMKV instance in read-only mode. Any write operation will be silently ignored.
MMKV *mmkv = [MMKV mmkvWithID:@"MyID" mode:MMKVReadOnly]; // or combine with multi-process MMKV *mmkv = [MMKV mmkvWithID:@"MyID" mode:MMKVMultiProcess | MMKVReadOnly];
-
Starting from v2.4.0, you can turn on
enableCompareBeforeSetto reduce unnecessary write operations. When enabled, MMKV will compare the new value with the existing value before writing, and skip the write if they are the same.[mmkv enableCompareBeforeSet];Note:
enableCompareBeforeSetis NOT compatible with encryption or auto key expiration. Do not enable them on the same MMKV instance. -
You can turn it off later:
[mmkv disableCompareBeforeSet];
-
Starting from v2.4.0, MMKV provides an all-in-one config C struct
MMKVConfigfor convenient MMKV instance creation. UseMMKVConfigDefault()to create one with sensible defaults, then customize the fields you need.MMKVConfig config = MMKVConfigDefault(); config.cryptKey = [@"My-Encrypt-Key" dataUsingEncoding:NSUTF8StringEncoding]; config.mode = MMKVMultiProcess; auto mmkv = [MMKV mmkvWithID:@"MyID" config:config]; // or use the default MMKV with config MMKVConfig defaultConfig = MMKVConfigDefault(); auto defaultKV = [MMKV defaultMMKVWithConfig:defaultConfig];
Available fields (all have sensible defaults):
Field Type Default Description modeMMKVModeMMKVSingleProcessSingle or multi-process mode cryptKeyNSData *nilEncryption key aes256BOOLNOUse AES-256 key length rootPathNSString *nilCustom root directory expectedCapacitysize_t0Initial file size hint enableKeyExpireNSNumber *nil@YES/@NOto enable/disable auto key expirationexpiredInSecondsuint32_t0Default expiration duration in seconds enableCompareBeforeSetBOOLNOCompare value before writing recoverMMKVRecoverStrategicMMKVOnErrorNotSetPer-instance recovery strategy itemSizeLimituint32_t0Max size per key-value pair (0 = unlimited)
Starting from v2.1.0, MMKV supports the NameSpace feature. It’s primarily designed to solve these problems:
-
Using in other modules/3rd lib/SDK without initialization
Traditionally, MMKV requires initialization before use, and it will cause problems in multiple libs because one can’t be sure if MMKV has been initialized, nor can be sure of the root directory of MMKV. With NameSpace, a lib can use MMKV without initialization, and of course without configuring global root directory. -
Make customizing root directory easy
Using NameSpace you can customize the root directory of a group of MMKV instances easily.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
auto libraryPath = (NSString *) [paths firstObject];
auto rootDir = [libraryPath stringByAppendingPathComponent:@"mmkv_namespace"];
MMKVNameSpace *ns = [MMKV nameSpace:rootDir];
MMKV *kv = [ns mmkvWithID:@"test_namespace"];
// get the default namespace (the global root directory)
MMKVNameSpace *defaultNS = [MMKV defaultNameSpace];-
Backup & Restore within a NameSpace:
// backup/restore within a namespace [ns backupOneMMKV:@"test_namespace" toDirectory:dstPath]; [ns restoreOneMMKV:@"test_namespace" fromDirectory:dstPath]; [ns backupAllToDirectory:dstPath]; [ns restoreAllFromDirectory:dstPath];
-
Utility methods on NameSpace:
BOOL valid = [ns isFileValid:@"test_namespace"]; BOOL exists = [ns checkExist:@"test_namespace"]; [ns removeStorage:@"test_namespace"];
Starting from v2.1.0, MMKV’s C++ interface can be accessed in your C++ code.
Steps to adapt:
-
Include MMKV header
#include <MMKVCore/MMKV.h> auto ns = MMKV::nameSpace(nameSpaceDir); auto kv = ns.mmkvWithID("test_NAPI");
Note
Unlike other platforms, in iOS/macOS the core lib is named as MMKVCore instead of MMKV to avoid conflict of the ObjC wrapper framework of MMKV.
MMKV is published under the BSD 3-Clause license. For details check out the LICENSE.TXT.
Check out the CHANGELOG.md for details of change history.
If you are interested in contributing, check out the CONTRIBUTING.md, also join our Tencent OpenSource Plan.
To give clarity of what is expected of our members, MMKV has adopted the code of conduct defined by the Contributor Covenant, which is widely used. And we think it articulates our values well. For more, check out the Code of Conduct.
Check out the FAQ first. Should there be any questions, don't hesitate to create issues.
User privacy is taken very seriously: MMKV does not obtain, collect or upload any personal information. Please refer to the MMKV SDK Personal Information Protection Rules for details.
- In English
- 中文
- In English
- 中文
- In English
- 中文
-
In English
-
中文
-
Golang
- In English
- 中文