★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ➤微信公众号:山青咏芝(shanqingyongzhi) ➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/ ) ➤GitHub地址:https://github.com/strengthen/LeetCode ➤原文地址: ➤如果链接不是山青咏芝的博客园地址,则可能是爬取作者的文章。 ➤原文已修改更新!强烈建议点击原文地址阅读!支持作者!支持原创! ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
热烈欢迎,请直接点击!!!
进入博主App Store主页,下载使用各个作品!!!
注:博主将坚持每月上线一个新app!!!
先决条件
XCode 9.2或更高版本
iOS 8或更高版本的目标,macOS 10.9或更高版本,或任何版本的tvOS或watchOS
安装
安装CocoaPods 1.1.0或更高版本。
运行 pod repo update
以使CocoaPods了解最新的Realm版本。
在您的Podfile中,添加 pod 'Realm'
到您的应用目标和 pod 'Realm/Headers'
测试目标。
从命令行运行 pod install
。
使用 .xcworkspace
CocoaPods生成 的 文件来处理您的项目!
如果将Realm与Swift一起使用,请将文件拖到 Swift/RLMSupport.swift
Xcode项目的File Navigator中,选中 Copy items if if needed复选框。
入门
如果您希望纯粹使用来自 Swift的Realm ,请考虑使用 Realm Swift 。 Realm Objective-C和Realm Swift API不可互操作,不支持它们一起使用。
Realm Objective-C使您能够以安全,持久和快速的方式有效地编写应用程序的模型层。 这是它的样子:
// Define your models like regular Objective‑C classes
@interface Dog : RLMObject
@property NSString *name;
@property NSData *picture;
@property NSInteger age;
@end
@implementation Dog
@end
RLM_ARRAY_TYPE(Dog)
@interface Person : RLMObject
@property NSString *name;
@property RLMArray<Dog *><Dog> *dogs;
@end
@implementation Person
@end
// Use them like regular Objective‑C objects
Dog *mydog = [[Dog alloc] init];
mydog.name = @"Rex";
mydog.age = 1;
mydog.picture = nil; // properties are nullable
NSLog(@"Name of dog: %@", mydog.name);
// Query Realm for all dogs less than 2 years old
RLMResults<Dog *> *puppies = [Dog objectsWhere:@"age < 2"];
puppies.count; // => 0 because no dogs have been added to the Realm yet
// Persist your data easily
RLMRealm *realm = [RLMRealm defaultRealm];
[realm transactionWithBlock:^{
[realm addObject:mydog];
}];
// Queries are updated in realtime
puppies.count; // => 1
// Query and update the result in another thread
dispatch_async(dispatch_queue_create("background", 0), ^{
@autoreleasepool {
Dog *theDog = [[Dog objectsWhere:@"age == 1"] firstObject];
RLMRealm *realm = [RLMRealm defaultRealm];
[realm beginWriteTransaction];
theDog.age = 3;
[realm commitWriteTransaction];
}
});
Realm Studio
Realm Studio 是我们的首选开发人员工具,可以轻松管理Realm数据库和Realm平台。 使用 Realm Studio ,您可以打开和编辑本地和同步的域,并管理任何Realm Object Server实例。 它支持Mac,Windows和Linux。
使用菜单项“ 工具”>“生成演示数据库”创建包含示例数据的测试 数据库 。
如果您在查找应用程序的Realm文件时需要帮助,请查看此 StackOverflow答案 以获取详细说明。
例子
您可以在我们的 发布zip 下 找到iOS和OS X的示例应用程序 examples/
,演示如何使用Realm的许多功能,如迁移,如何使用它 UITableViewController
,加密,命令行工具等等。
使用Realm框架
在Objective-C源文件的顶部,用于 #import <Realm/Realm.h>
导入Realm Objective-C并使其可用于您的代码。 在Swift源文件的顶部(如果有的话),使用 import Realm
。 这就是你开始所需要的一切!
使用Swift的Realm Objective-C
Realm Objective-C旨在与混合的Objective-C和Swift项目一起使用。 从Swift开始,您可以在使用Objective-C中的Realm时执行所有操作,例如定义 模型 和使用Realm的Objective-C API。 但是,您应该做的一些事情与纯Objective-C项目略有不同:
RLMSupport.swift
我们建议您编译 Swift / RLMSupport.swift 文件(也可以在我们的 发行版zip中找到 )。 此文件添加了 Sequence
对Realm Objective-C集合类型的一致性,并重新公开了Swift本身无法访问的Objective-C方法,包括可变参数。
Realm Objective-C默认不包含此文件,因为这会强制Realm Objective-C的所有用户包含大量的Swift动态库,无论他们是否在他们的应用程序中使用Swift!
RLMArray属性
在Objective-C中,我们依靠协议一致性使Realm知道在 RLMArray
多对多关系中 包含的对象类型 。 在Swift中,这种语法是不可能的。 因此,您应该 RLMArray
使用以下语法 声明 属性:
class Person: Object {
@objc dynamic var dogs = RLMArray(objectClassName: Dog.className())
}
这相当于Objective-C中的以下内容:
@interface Person : RLMObject
@property RLMArray<Dog *><Dog> *dogs;
@end
tvOS
因为在tvOS上禁止写入“Documents”目录,所以默认的Realm位置设置为 NSCachesDirectory
。 但是,请注意tvOS可以随时清除“Caches”目录中的文件,因此我们建议您依赖Realm作为可重建的缓存,而不是存储重要的用户数据。
如果您想在tvOS应用程序和电视服务扩展(例如Top Shelf扩展)之间共享Realm文件,则必须使用 Library/Caches/
共享容器中的应用程序组目录。
// end declarations
RLMRealmConfiguration *configuration = [RLMRealmConfiguration defaultConfiguration];
configuration.fileURL = [[[NSFileManager defaultManager]
containerURLForSecurityApplicationGroupIdentifier:@"group.io.realm.examples.extension"]
URLByAppendingPathComponent:@"Library/Caches/default.realm"];
您还可以 在应用中 捆绑预构建的Realm文件 。 但是,请务必遵守App Store指南,将您的应用保持在200MB以下。 请浏览我们的 tvOS示例, 了解示例如何使用Realm作为离线缓存或预加载数据的示例tvOS应用程序。
使用Realm与后台应用程序刷新
在iOS 8及更高版本中, NSFileProtection
只要设备被锁定 ,应用程序内的文件 就会 自动加密 。 如果您的应用程序在设备被锁定时尝试执行涉及Realm的任何工作,并且 NSFileProtection
您的Realm文件 的 属性设置为加密它们(默认情况下就是这种情况), open() failed: Operation not permitted
则会引发异常。
为了解决这个问题,有必要确保应用于Realm文件本身及其 辅助文件 的文件保护属性 降级为不太严格 的文件保护属性 ,即使在设备被锁定时也允许文件访问,例如 NSFileProtectionCompleteUntilFirstUserAuthentication
。
如果您选择以这种方式选择退出完整的iOS文件加密,我们建议您使用 Realm自己的内置加密 来确保您的数据仍然得到妥善保护。
由于辅助文件有时可以在操作过程中延迟创建和删除,因此我们建议您将文件保护属性应用于包含这些Realm文件的父文件夹。 这将确保该属性正确应用于所有相关Realm文件,无论其创建时间如何。
RLMRealm *realm = [RLMRealm defaultRealm];
// Get our Realm file's parent directory
NSString *folderPath = realm.configuration.fileURL.URLByDeletingLastPathComponent.path;
// Disable file protection for this directory
[[NSFileManager defaultManager] setAttributes:@{NSFileProtectionKey: NSFileProtectionNone}
ofItemAtPath:folderPath error:nil];
三界
一个 境界是一种境界移动数据库容器的一个实例。
有关Realms的详细讨论,请阅读 The Realm Data Model 。 有关创建和管理领域的信息,请参阅
打开本地领域
要打开Realm,请实例化一个新 RLMRealm
对象:
RLMRealm *realm = [RLMRealm defaultRealm];
[realm transactionWithBlock:^{
[realm addObject:mydog];
}];
这会实例化 默认的Realm 。
配置本地领域
通过创建实例 RLMRealmConfiguration
并设置适当的属性, 在打开Realm之前配置它 。 创建和自定义配置值允许您自定义以及其他方面:
本地Realm文件位置的路径
该 迁移功能 ,如果一个领域的模式和版本之间的更改必须更新
配置 压缩功能 以确保有效利用磁盘空间。
可以在 +[RLMRealm realmWithConfiguration:config error:&err]
每次需要Realm实例时 传递配置 ,也可以将配置设置为默认Realm实例 [RLMRealmConfiguration setDefaultConfiguration:config]
。
例如,假设您有一个应用程序,用户必须登录到您的Web后端,并且您希望支持在帐户之间快速切换。 您可以通过执行以下操作为每个帐户提供自己的Realm文件,该文件将用作默认Realm:
@implementation SomeClass
+ (void)setDefaultRealmForUser:(NSString *)username {
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
// Use the default directory, but replace the filename with the username
config.fileURL = [[[config.fileURL URLByDeletingLastPathComponent]
URLByAppendingPathComponent:username]
URLByAppendingPathExtension:@"realm"];
// Set this as the configuration used for the default Realm
[RLMRealmConfiguration setDefaultConfiguration:config];
}
@end
您可以拥有多个配置对象,因此您可以独立控制每个Realm的版本,架构和位置。
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
// Get the URL to the bundled file
config.fileURL = [[NSBundle mainBundle] URLForResource:@"MyBundledData" withExtension:@"realm"];
// Open the file in read-only mode as application bundles are not writeable
config.readOnly = YES;
// Open the Realm with the configuration
RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:nil];
// Read some data from the bundled Realm
RLMResults<Dog *> *dogs = [Dog objectsInRealm:realm where:@"age > 5"];
存储可写Realm文件的最常见位置是iOS上的“Documents”目录和macOS上的“Application Support”目录。 请尊重 Apple的iOS数据存储指南 ,该 指南 建议如果应用程序可以重新生成的文档应存储在 <Application_Home>/Library/Caches
目录中。 如果使用自定义URL初始化Realm,则必须描述具有写入权限的位置。
默认领域
到目前为止,您可能已经注意到我们 realm
通过调用 初始化了对 变量的访问 [RLMRealm defaultRealm]
。 该方法返回一个 RLMRealm
对象, 该 对象映射到 default.realm
应用程序的Documents文件夹(iOS)或Application Support文件夹(macOS)中指定的文件。
Realm API中的许多方法都有一个接受 RLMRealm
实例 的版本 ,以及一个使用默认Realm的便捷版本。 例如, [RLMObject allObjects]
相当于 [RLMObject allObjectsInRealm:[RLMRealm defaultRealm]]
。
请注意,默认的Realm构造函数和默认的Realm便捷方法不允许错误处理; 你应该只在初始化Realm时使用它们不能失败。 有关 详细信息, 请参阅 错误处理 文档 。
打开同步领域
内存领域
通过设置 inMemoryIdentifier
而不是 fileURL
on RLMRealmConfiguration
,您可以创建一个完全在内存中运行而不会持久保存到磁盘的Realm。 设置 inMemoryIdentifier
将为零 fileURL
(反之亦然)。
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
config.inMemoryIdentifier = @"MyInMemoryRealm";
RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:nil];
内存领域不会跨应用程序启动保存数据,但Realm的所有其他功能将按预期工作,包括查询,关系和线程安全。 如果您需要灵活的数据访问而没有磁盘持久性的开销,这是一个有用的选项。
内存领域在临时目录中创建多个文件,用于协调跨进程通知等事务。 实际上没有数据写入文件,除非由于内存压力操作系统需要交换到磁盘。
注意:当具有特定标识符的所有内存中Realm实例超出范围而没有引用时, 该Realm中的所有数据都将被删除。 我们建议您在应用程序的生命周期内保留对任何内存领域的强引用。 (对于磁盘领域,这不是必需的。)
错误处理
与任何磁盘I / O操作一样, RLMRealm
如果资源受到限制 ,创建 实例有时可能会失败。 实际上,这只能在第一次在给定线程上创建Realm实例时发生。 从同一个线程对Realm的后续访问将重用高速缓存的实例并始终成功。
要在首次访问给定线程上的Realm时处理错误,请提供 NSError
指向该 error
参数 的 指针 :
NSError *error = nil;
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:&error];
if (!realm) {
// handle error
}
辅助领域文件
除标准 .realm
文件外,Realm还为其自己的内部操作生成并维护其他文件和目录。
.realm.lock
- 资源锁的锁文件。
.realm.management
- 进程间锁定文件的目录。
.realm.note
- 用于通知的命名管道。
这些文件对 .realm
数据库文件 没有任何影响 ,如果删除或替换父数据库文件,则不会导致任何错误行为。
当 报告领域的问题 ,请一定要包括这些辅助文件与主一起 .realm
的文件,因为它们包含用于调试的信息。
捆绑一个境界
通常使用初始数据为应用程序设定种子,使其在首次启动时立即可供您的用户使用。 这是如何做到这一点:
首先,填充领域。 您应该使用与最终发货应用相同的数据模型来创建Realm,并使用您希望与应用捆绑在一起的数据填充它。 由于Realm文件是跨平台的,您可以使用macOS应用程序(请参阅我们的 JSONImport示例 )或在模拟器中运行的iOS应用程序。
在您生成此Realm文件的代码中,您应该通过制作文件的压缩副本来完成(请参阅参考资料 -[RLMRealm writeCopyToPath:error:]
)。 这将减少Realm的文件大小,使您的最终应用程序更轻松地为您的用户下载。
将Realm文件的新压缩副本拖到最终应用程序的Xcode Project Navigator中。
转到Xcode中的app target的构建阶段选项卡,并将Realm文件添加到“Copy Bundle Resources”构建阶段。
此时,您的应用可以访问捆绑的Realm文件。 您可以使用找到它的路径 [[NSBundle mainBundle] pathForResource:ofType:]
。
如果捆绑的领域包含您不需要修改固定的数据,你可以直接从束路径设置中打开它 readOnly = true
的上 RLMRealmConfiguration
对象。 否则,如果它是您要修改的初始数据,则可以使用将捆绑的文件复制到应用程序的Documents目录中 [[NSFileManager defaultManager] copyItemAtPath:toPath:error:]
。
您可以参考我们的 迁移示例应用程序 ,以获取有关如何使用捆绑的Realm文件的示例。
类子集
在某些情况下,您可能希望限制哪些类可以存储在特定领域中。 例如,如果您有两个团队在应用程序的不同组件上工作,这两个组件都在内部使用Realm,那么您可能不希望必须协调 它们之间的 迁移 。 你可以通过设置 objectClasses
你 的 属性 来做到这一点 RLMRealmConfiguration
:
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
config.objectClasses = @[MyClass.class, MyOtherClass.class];
RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:nil];
压缩领域
Realm的工作方式是Realm文件的大小始终大于存储在其中的对象的总大小。 请参阅我们关于 线程 的文档, 了解为什么这种架构能够实现Realm的一些出色性能,并发性和安全性优势。
为了避免进行昂贵的系统调用,Realm文件很少在运行时缩小。 相反,它们以特定的大小增量增长,新数据被写入文件内跟踪的未使用空间内。 但是,可能存在Realm文件的重要部分由未使用的空间组成的情况。 为了解决这个问题,您可以 shouldCompactOnLaunch
在Realm的配置对象上 设置 block属性,以确定在第一次打开时是否应该压缩Realm文件。 例如:
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
config.shouldCompactOnLaunch = ^BOOL(NSUInteger totalBytes, NSUInteger usedBytes) {
// totalBytes refers to the size of the file on disk in bytes (data + free space)
// usedBytes refers to the number of bytes used by data in the file
// Compact if the file is over 100MB in size and less than 50% 'used'
NSUInteger oneHundredMB = 100 * 1024 * 1024;
return (totalBytes > oneHundredMB) && ((double)usedBytes / totalBytes) < 0.5;
};
NSError *error = nil;
// Realm is compacted on the first open if the configuration block conditions were met.
RLMRealm *realm = [RLMRealm realmWithConfiguration:config error:&error];
if (error) {
// handle error compacting or opening Realm
}
压缩操作通过读取Realm文件的全部内容,将其重写到不同位置的新文件,然后替换原始文件来工作。 根据文件中的数据量,这可能是一项昂贵的操作。
我们鼓励您尝试使用这些数字来确定在经常执行压缩和让Realm文件变得过大之间取得良好平衡。
最后,如果另一个进程正在访问Realm,即使满足配置块的条件,也会跳过压缩。 这是因为在访问Realm时无法安全地执行压缩。
shouldCompactOnLaunch
同步域不支持 设置 块。 这是因为压缩不会保留事务日志,必须保留事务日志以进行同步。
删除Realm文件
在某些情况下,例如清除缓存或重置整个数据集,从磁盘中完全删除Realm文件可能是合适的。
因为Realm避免将数据复制到内存中,除非绝对需要,所以Realm管理的所有对象都包含对磁盘上文件的引用,并且必须先释放它才能安全删除文件。 这包括从读取(或加入)的所有对象的境界,所有 RLMArray
, RLMResults
以及 RLMThreadSafeReference
目的和 RLMRealm
本身。
实际上,这意味着删除Realm文件应该在应用程序启动之前在打开Realm之前完成,或者在仅在显式 自动释放池中 打开Realm之后完成 ,这样可以确保所有Realm对象都已被释放。
最后,虽然不是绝对必要,但您应该删除 辅助Realm文件 以及主Realm文件以完全清除所有相关文件。
@autoreleasepool {
// all Realm usage here
}
NSFileManager *manager = [NSFileManager defaultManager];
RLMRealmConfiguration *config = [RLMRealmConfiguration defaultConfiguration];
NSArray<NSURL *> *realmFileURLs = @[
config.fileURL,
[config.fileURL URLByAppendingPathExtension:@"lock"],
[config.fileURL URLByAppendingPathExtension:@"note"],
[config.fileURL URLByAppendingPathExtension:@"management"]
];
for (NSURL *URL in realmFileURLs) {
NSError *error = nil;
[manager removeItemAtURL:URL error:&error];
if (error) {
// handle error
}
}
楷模
领域数据模型被定义为具有常规属性的常规Objective-C类。 创建一个,只是子类 RLMObject
或现有的Realm模型类。 领域模型对象的功能大多与其他任何Objective-C对象一样。 您可以在它们上定义自己的方法,使它们符合协议,并像使用任何其他对象一样使用它们。 主要限制是您只能在创建它的线程上使用对象,并且您无法直接为任何持久性属性访问其ivars。
关系和嵌套数据结构通过包含目标类型的属性或 RLMArray
类型的对象列表 来建模 。 RLMArray
实例也可用于建模原始值的集合(例如,字符串或整数数组)。
#import <Realm/Realm.h>
@class Person;
// Dog model
@interface Dog : RLMObject
@property NSString *name;
@property Person *owner;
@end
RLM_ARRAY_TYPE(Dog) // define RLMArray<Dog>
// Person model
@interface Person : RLMObject
@property NSString *name;
@property NSDate *birthdate;
@property RLMArray<Dog *><Dog> *dogs;
@end
RLM_ARRAY_TYPE(Person) // define RLMArray<Person>
// Implementations
@implementation Dog
@end // none needed
@implementation Person
@end // none needed
由于Realm在启动时会解析代码中定义的所有模型,因此它们必须全部有效,即使它们从未使用过。
当使用Swift中的Realm时,该 Swift.reflect(_:)
函数用于确定有关模型的信息,这需要调用 init()
成功。 这意味着所有非可选属性都必须具有默认值。
有关 详细信息, 请参阅我们的 API文档 RLMObject
。
支持的属性类型
境界支持以下属性类型: BOOL
, bool
, int
, NSInteger
, long
, long long
, float
, double
, NSString
, NSDate
, NSData
,和 NSNumber
标记与特定类型 。
CGFloat
不鼓励使用属性,因为类型不是平台无关的。
你可以用 RLMArray<Object *><Object>
和 RLMObject
子类关系,如一对多和一对一的模型。
RLMArray
支持Objective-C泛型。 以下是属性定义的不同组件的含义以及它们有用的原因:
RLMArray
:属性类型。
<Object *>
:通用专业化。 这有助于防止在编译时使用具有错误对象类型的数组。
<Object>
: RLMArray
符合 的协议 。 这使Realm能够知道如何在运行时专门化该模型的模式。
必需的属性
默认情况下, NSString *
, NSData *
,和 NSDate *
属性允许您设置它们 nil
。 如果要要求存在值,请覆盖 子类 +requiredProperties
上 的 方法 RLMObject
。
例如,使用以下模型定义,尝试将人员的名称设置为 nil
将抛出异常,但 nil
允许 将其生日设置 为:
@interface Person : RLMObject
@property NSString *name;
@property NSDate *birthday;
@end
@implementation Person
+ (NSArray *)requiredProperties {
return @[@"name"];
}
@end
使用 NSNumber *
属性 存储可选数字 。 因为境界使用为不同类型的数字不同的存储格式中,属性必须具有标记之一 RLMInt
, RLMFloat
, RLMDouble
,或 RLMBool
。 分配给属性的所有值都将转换为指定的类型。
请注意, NSDecimalNumber
值只能分配给 RLMDouble
Realm属性,并且Realm将存储值的双精度浮点近似值,而不是基础十进制值。
如果我们想存储某人的年龄而不是他们的生日,同时仍允许 nil
他们的年龄未知:
@interface Person : RLMObject
@property NSString *name;
@property NSNumber<RLMInt> *age;
@end
@implementation Person
+ (NSArray *)requiredProperties {
return @[@"name"];
}
@end
RLMObject
子类属性总是可以 nil
,因此不能包含在内 requiredProperties
。 并且 RLMArray
不支持存储 nil
。
主键
覆盖 +primaryKey
以设置模型的主键。 声明主键可以有效地查找和更新对象,并为每个值强制实现唯一性。 将具有主键的对象添加到Realm后,无法更改主键。
@interface Person : RLMObject
@property NSInteger id;
@property NSString *name;
@end
@implementation Person
+ (NSString *)primaryKey {
return @"id";
}
@end
索引属性
要索引属性,请覆盖 +indexedProperties
。 与主键一样,索引使写入速度稍慢,但使查询使用相等性和 IN
运算符更快。 (它还会使您的Realm文件略大,以存储索引。)最好只在优化特定情况下的读取性能时添加索引。
@interface Book : RLMObject
@property float price;
@property NSString *title;
@end
@implementation Book
+ (NSArray *)indexedProperties {
return @[@"title"];
}
@end
Realm支持对字符串,整数,布尔值和 NSDate
属性进行 索引 。
忽略属性
如果您不想将模型中的字段保存到其Realm,请覆盖 +ignoredProperties
。 领域不会干扰这些属性的正常运行; 他们将得到伊娃的支持,你可以自由地覆盖他们的二传手和吸气者。
@interface Person : RLMObject
@property NSInteger tmpID;
@property (readonly) NSString *name; // read-only properties are automatically ignored
@property NSString *firstName;
@property NSString *lastName;
@end
@implementation Person
+ (NSArray *)ignoredProperties {
return @[@"tmpID"];
}
- (NSString *)name {
return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}
@end
请发表评论