Realm和WCDB数据库的Objective-C基本使用

Realm是开源的,完全免费的,支持多种语言,跨移动端,底层并不是基于SQLite,而是完全重新写的对象数据库(Object Database),比SQLite和CoreData要高效的非常多。
在这里插入图片描述

查看如何加密数据库文件
https://academy.realm.io/posts/tim-oliver-realm-cocoa-tutorial-on-encryption-with-realm/

查看官方编写的加密代码
https://github.com/realm/realm-cocoa/blob/master/examples/ios/objc/Encryption/LabelViewController.m

#import <Realm/Realm.h>

// 创建Dog类
@interface Dog : RLMObject
    @property NSString *name;
    @property NSData *picture;
    @property NSInteger age;
@end
@implementation Dog
@end

@interface ViewController ()
@end

@implementation ViewController
    
- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 创建或读取Realm数据库
    NSError *error = nil;
    // 创建基本配置
    RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
    // 设置加密秘钥
    config.encryptionKey = [self getKey];
    NSLog(@"%@", config.encryptionKey); // 就是秘钥
    // 创建Realm实例
    RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:&error];
    if (error) {
        NSLog(@"%@", error);
    }
    
    // 增加数据
    [realm transactionWithBlock:^{
        for (int i = 0; i < 64; i++) {
            // 我就直接创建64个Dog实例,然后插入到数据库
            // 数据表是根据雷鸣创建的
            Dog *dog = [[Dog alloc] init];
            dog.name = [NSString stringWithFormat:@"Rex%d", i];
            dog.age = i;
            uint8_t buffer[i];
            int status = SecRandomCopyBytes(kSecRandomDefault, i, buffer);
            dog.picture = [[NSData alloc] initWithBytes:buffer length:sizeof(buffer)];
            // 调用插入函数
            [realm addObject:dog];
        }
    }];
    
    // 修改
    [realm beginWriteTransaction];
    Dog *query_dog = [[Dog objectsInRealm:realm where:@"age = 2"] firstObject];
    query_dog.name = @"修改后的值";
    [realm commitWriteTransaction];
    
    // 查询
    RLMResults *puppies = [Dog objectsInRealm:realm where:@"age > 0"];
    for (Dog *d in puppies) {
        NSLog(@"name=%@,age=%ld,picture=%@", d.name, (long)d.age, d.picture);
    }
}
    
- (NSData *)getKey {
    // Identifier for our keychain entry - should be unique for your application
    static const uint8_t kKeychainIdentifier[] = "io.Realm.EncryptionExampleKey";
    NSData *tag = [[NSData alloc] initWithBytesNoCopy:(void *)kKeychainIdentifier
                                               length:sizeof(kKeychainIdentifier)
                                         freeWhenDone:NO];
    
    // First check in the keychain for an existing key
    NSDictionary *query = @{(__bridge id)kSecClass: (__bridge id)kSecClassKey,
                            (__bridge id)kSecAttrApplicationTag: tag,
                            (__bridge id)kSecAttrKeySizeInBits: @512,
                            (__bridge id)kSecReturnData: @YES};
    
    CFTypeRef dataRef = NULL;
    OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &dataRef);
    if (status == errSecSuccess) {
        return (__bridge NSData *)dataRef;
    }
    
    // No pre-existing key from this application, so generate a new one
    static const uint8_t kDBPasswordKey[] = "zhangqiang.realm.key";
    NSData *keyData = [[NSData alloc] initWithBytesNoCopy:(void *)kDBPasswordKey
                                                   length:sizeof(kDBPasswordKey)
                                             freeWhenDone:NO];
//    NSData *keyData = [[NSString stringWithUTF8String:kDBPasswordKey] dataUsingEncoding:NSUTF8StringEncoding];

    // Store the key in the keychain
    query = @{(__bridge id)kSecClass: (__bridge id)kSecClassKey,
              (__bridge id)kSecAttrApplicationTag: tag,
              (__bridge id)kSecAttrKeySizeInBits: @512,
              (__bridge id)kSecValueData: keyData};
    
    status = SecItemAdd((__bridge CFDictionaryRef)query, NULL);
    NSAssert(status == errSecSuccess, @"Failed to insert new key in the keychain");
    
    return keyData;
}




WCDB 来自微信的基于SQLCipher的数据库

Object Relational Mapping(ORM) 对象关系映射

完全开源,性能杠杠的!
https://github.com/Tencent/wcdb

  • 映射Objc的类名为表明和索引
  • 映射该类的属性为数据表的字段名

先构建一个Message类,请注意,凡是导入了WCDB头文件类的文件名必须要改成.mm,因为WCDB使用C++封装的,也就是说,mm是可以兼容C++和Objective-C的

#import <WCDB/WCDB.h>

@interface Message : NSObject<WCTTableCoding>
@property int localID;
@property (retain) NSString *content;
@property (retain) NSDate *createTime;
@property (retain) NSDate *modifiedTime;
@property (assign) int unused;

WCDB_PROPERTY(localID)
WCDB_PROPERTY(content)
WCDB_PROPERTY(createTime)
WCDB_PROPERTY(modifiedTime)
@end

@implementation Message
WCDB_IMPLEMENTATION(Message)
WCDB_SYNTHESIZE(Message, localID)
WCDB_SYNTHESIZE(Message, content)
WCDB_SYNTHESIZE(Message, createTime)
WCDB_SYNTHESIZE(Message, modifiedTime)

WCDB_PRIMARY(Message, localID)
WCDB_INDEX(Message, "_index", createTime)
@end
  • WCDB_PROPERTY 表示声明的属性绑定到数据表的列名
  • WCDB_IMPLEMENTATION 表示类名绑定到数据表名
  • WCDB_SYNTHESIZEWCDB_PROPERTY 是一对,一样的使用
  • WCDB_PRIMARY 表示声明的指定属性为主键
  • WCDB_INDEX 表示定义索引
创建数据表
// 指定数据库地址和名称
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"/wcdb.sqlite"];

// 构建数据库实例对象
WCTDatabase *database = [[WCTDatabase alloc] initWithPath:path];
// 设置数据库加密
[database setCipherKey:[@"123456" dataUsingEncoding:NSASCIIStringEncoding]];
//[database setCipherKey:[NSData dataWithBytes:"123456" length:6]];
// 创建数据表格message
BOOL result = [database createTableAndIndexesOfName:@"message" withClass:Message.class];
if (result) {

}
插入数据
// 构建数据模型
Message *message = [[Message alloc] init];
message.localID = 6;
message.content = @"Hello, WCDB 6!";
message.createTime = [NSDate date];
message.modifiedTime = [NSDate date];

// 插入数据
result = [database insertObject:message into:@"message"];
if (result) {
    
}
更新数据
Message *update_message = [[Message alloc] init];
update_message.content = @"Hello, WCDB 5!";
result = [database updateRowsInTable:@"message" onProperties:Message.content withObject:update_message where:Message.localID == 5];
if (result) {
   
}
删除数据
result = [database deleteObjectsFromTable:@"message" where:Message.localID==0];
查询数据
NSArray<Message *> *messages = [database getObjectsOfClass:Message.class fromTable:@"message" orderBy:Message.localID.order()];
if (messages && messages.count > 0) {
    for (int i = 0; i < messages.count; i++) {
        Message *m = messages[i];
        NSLog(@"localID=%d, content=%@, createTime=%@, modifiedTime=%@", m.localID, m.content, m.createTime, m.modifiedTime);
    }
}
执行事务
WCTTransaction *transaction = [database getTransaction];
BOOL transStatus = [transaction begin];// 开始事务
// 执行全部的sql语句,假设这里执行for循环64条语句
for (int i = 10; i < 74; i++) {
    Message *msg = [[Message alloc] init];
    msg.localID = i;
    msg.content = [NSString stringWithFormat:@"Hello, WCDB %d!", i];
    msg.createTime = [NSDate date];
    msg.modifiedTime = [NSDate date];
    [transaction insertObject:msg into:@"message"];
}
transStatus = [transaction commit]; // 提交事务
if (!transStatus) {
    [transaction rollback]; // 有任何语句报错,就回滚
    NSLog(@"%@", [transaction error]);
}
使用WINQ查询
NSArray<Message *> *messages = [database getObjectsOnResults:{Message.localID, Message.content, Message.createTime, Message.modifiedTime} fromTable:@"message" where:Message.localID > 0 && Message.content.isNotNull()];
if (messages && messages.count > 0) {
    for (int i = 0; i < messages.count; i++) {
        Message *m = messages[i];
        NSLog(@"localID=%d, content=%@, createTime=%@, modifiedTime=%@", m.localID, m.content, m.createTime, m.modifiedTime);
    }
}

这行查询代码就像这句SQL

 SELECT localID,content,createTime,modifiedTime
 FROM message
 WHERE localID>0 AND content IS NOT NULL
发布了336 篇原创文章 · 获赞 124 · 访问量 65万+

猜你喜欢

转载自blog.csdn.net/u013538542/article/details/100799441