NSObject转RLMObject存入Realm遇错,求增删及UI模型保留方案
看起来你踩了Realm最常见的坑之一——把普通NSObject和RLMObject混着用导致的方法找不到崩溃,我来帮你一步步解决这两个问题:
首先先解决你当前的崩溃问题:你调用addToDatabaseStory时传的是Story(NSObject子类),但Realm的方法只接受RLMObject子类实例(也就是你的StoryStorage),所以Realm内部尝试调用isInvalidated这个RLMObject专属方法时,普通的Story对象根本没有这个方法,直接崩溃了。
1. 正确的新增操作
核心是把UI层的Story转换成Realm层的StoryStorage,再存入Realm。你可以给StoryStorage加一个初始化方法,或者给Story加一个转成StoryStorage的方法:
// StoryStorage.h #import <Realm/Realm.h> @interface StoryStorage : RLMObject @property NSString *storyId; // 建议加主键,方便后续查询删除 @property NSString *title; @property NSString *content; // 其他属性... - (instancetype)initWithStory:(Story *)story; @end // StoryStorage.m @implementation StoryStorage + (NSString *)primaryKey { return @"storyId"; // 设置主键,确保唯一性 } - (instancetype)initWithStory:(Story *)story { self = [super init]; if (self) { self.storyId = story.storyId; self.title = story.title; self.content = story.content; // 复制其他属性 } return self; } @end
然后新增到Realm的代码要放在事务里:
- (void)addToDatabaseStory:(Story *)story { RLMRealm *realm = [RLMRealm defaultRealm]; [realm beginWriteTransaction]; StoryStorage *storage = [[StoryStorage alloc] initWithStory:story]; [realm addOrUpdateObject:storage]; // 用addOrUpdateObject避免重复添加 [realm commitWriteTransaction]; }
2. 正确的删除操作
删除的前提是你操作的是Realm中存在的StoryStorage实例,不能是已经被删除的对象,也不能是普通的Story对象。常见的两种删除方式:
- 通过主键查询删除:
- (void)deleteStoryFromDatabaseWithId:(NSString *)storyId { RLMRealm *realm = [RLMRealm defaultRealm]; [realm beginWriteTransaction]; StoryStorage *storage = [StoryStorage objectForPrimaryKey:storyId]; if (storage) { // 确保对象存在,避免野指针 [realm deleteObject:storage]; } [realm commitWriteTransaction]; }
- 如果已经持有
StoryStorage实例(注意:这个实例必须是当前Realm线程的有效实例,跨线程的话要重新查询):
- (void)deleteStoryStorage:(StoryStorage *)storage { RLMRealm *realm = [RLMRealm defaultRealm]; if (!storage.isInvalidated) { // 先判断对象是否已被删除 [realm beginWriteTransaction]; [realm deleteObject:storage]; [realm commitWriteTransaction]; } }
你的思路其实是对的:UI层用独立的NSObject子类Story,Realm层用StoryStorage,两者完全解耦,这样删除Realm里的StoryStorage根本不会影响UI的Story。具体可以这么做:
数据流向分离:
- 从服务器拉取数据后,先解析成UI用的
Story数组,用于展示; - 同时把
Story转换成StoryStorage存入Realm做缓存; - 如果需要从Realm加载缓存数据,先查询
StoryStorage,再转换成Story给UI展示。
- 从服务器拉取数据后,先解析成UI用的
删除时只操作Realm层:
当你需要删除Realm中的数据时,只针对StoryStorage做删除操作,UI层的Story实例因为是独立的NSObject,完全不受Realm的影响,依然可以正常在UI上展示。
举个例子,假设你在DetailController里要删除Realm数据,但还要保留当前展示的Story:
// DetailController.m - (IBAction)deleteFromCacheButtonTapped:(id)sender { // 只删除Realm里的对应StoryStorage [self deleteStoryFromDatabaseWithId:self.currentStory.storyId]; // self.currentStory是UI用的Story实例,依然可以正常显示,不受影响 }
另外要注意:如果你的UI是绑定到Realm对象的(比如之前直接用RLMObject当模型),那删除后Realm对象会失效,导致UI报错。但现在你用独立的NSObject模型,就完全没有这个问题了。
最后提醒一下:Realm对象是线程受限的,不要在非创建线程操作Realm对象,跨线程的话一定要重新查询。
内容的提问来源于stack exchange,提问作者Pavel Bogart

