Skip to content

iOS_advance

guoling edited this page Apr 19, 2024 · 6 revisions

MMKV for iOS/macOS

MMKV is an efficient, small, easy-to-use mobile key-value storage framework used in the WeChat application. It's currently available on both Android, iOS/macOS, Windows and POSIX.

In Advance

There're some settings on MMKV that tune things to suit your need.

Log

  • 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, add some code like these:

    - (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);
    }

    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 disrecommend):
    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];

Recover from data corruption

  • 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 some code like these:

    - (MMKVRecoverStrategic)onMMKVCRCCheckFail:(NSString *)mmapID {
        return MMKVOnErrorRecover;
    }
    
    - (MMKVRecoverStrategic)onMMKVFileLengthError:(NSString *)mmapID {
        return MMKVOnErrorRecover;
    }

Customize location

  • 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" relativePath:path];

Encryption

  • By default MMKV stores all key values in plain text on file, relying on iOS's sandbox to make sure the file is encrypted. Should you worry about information leaking, you can choose to encrypt MMKV.

    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
    [kv reKey:key_1];
    
    NSData *key_2 = [@"Key_seq_2" dataUsingEncoding:NSUTF8StringEncoding];
    // change encryption key
    [kv reKey:key_2];
    
    // change from encrypted to unencrypted
    [kv reKey:nullptr];

Auto Clean Up

  • 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];

Backup & Restore

  • 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 backupOneMMKV:mmapID rootPath:rootPath toDirectory:dstPath];
    // restore all instances
    count = [MMKV restoreAll:nil fromDirectory:dstPath];

Auto Expiration

  • 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 with 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,
    };

What's Next

Clone this wiki locally