• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

RealmObjective-C

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公众号:山青咏芝(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

安装

  1. 安装CocoaPods 1.1.0或更高版本。
  2. 运行pod repo update以使CocoaPods了解最新的Realm版本。
  3. 在您的Podfile中,添加pod 'Realm'到您的应用目标和pod 'Realm/Headers'测试目标。
  4. 从命令行运行pod install
  5. 使用.xcworkspaceCocoaPods生成文件来处理您的项目!
  6. 如果将Realm与Swift一起使用,请将文件拖到Swift/RLMSupport.swiftXcode项目的File Navigator中,选中Copy items if if needed复选框。

入门

如果您希望纯粹使用来自Swift的Realm,请考虑使用Realm SwiftRealm 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

如果你想从Swift纯粹使用Realm ,你应该考虑使用Realm Swift

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时使用它们不能失败。有关详细信息,请参阅错误处理文档

打开同步领域

您是否希望使用Realm Mobile Platform同步所有Realm数据库?所有与同步相关的文档已移至我们的平台文档中

内存领域

通过设置inMemoryIdentifier而不是fileURLon 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的文件,因为它们包含用于调试的信息。

捆绑一个境界

通常使用初始数据为应用程序设定种子,使其在首次启动时立即可供您的用户使用。这是如何做到这一点:

  1. 首先,填充领域。您应该使用与最终发货应用相同的数据模型来创建Realm,并使用您希望与应用捆绑在一起的数据填充它。由于Realm文件是跨平台的,您可以使用macOS应用程序(请参阅我们的JSONImport示例)或在模拟器中运行的iOS应用程序。
  2. 在您生成此Realm文件的代码中,您应该通过制作文件的压缩副本来完成(请参阅参考资料-[RLMRealm writeCopyToPath:error:])。这将减少Realm的文件大小,使您的最终应用程序更轻松地为您的用户下载。
  3. 将Realm文件的新压缩副本拖到最终应用程序的Xcode Project Navigator中。
  4. 转到Xcode中的app target的构建阶段选项卡,并将Realm文件添加到“Copy Bundle Resources”构建阶段。
  5. 此时,您的应用可以访问捆绑的Realm文件。您可以使用找到它的路径[[NSBundle mainBundle] pathForResource:ofType:]
  6. 如果捆绑的领域包含您不需要修改固定的数据,你可以直接从束路径设置中打开它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管理的所有对象都包含对磁盘上文件的引用,并且必须先释放它才能安全删除文件。这包括从读取(或加入)的所有对象的境界,所有RLMArrayRLMResults以及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

支持的属性类型

境界支持以下属性类型:BOOLboolintNSIntegerlonglong longfloatdoubleNSStringNSDateNSData,和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 *属性存储可选数字因为境界使用为不同类型的数字不同的存储格式中,属性必须具有标记之一RLMIntRLMFloatRLMDouble,或RLMBool分配给属性的所有值都将转换为指定的类型。

请注意,NSDecimalNumber值只能分配给RLMDoubleRealm属性,并且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
                      

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
一些Objective-C学习资源发布时间:2022-07-12
下一篇:
【Objective-C Runtime动态加载】---动态创建类Class发布时间:2022-07-12
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap