Realm Swift崩溃求助:访问无效对象RLMException异常排查
问题分析与解决方案
崩溃原因
你遇到的RLMException: Attempting to access an invalid object异常,结合触发场景(仅Firebase查询失败时崩溃),核心原因有两点:
- Realm模型字段可选性不匹配:如果
WhatsNewQuiz的quizOwnerImageUrl被定义为非可选String类型,Firebase查询失败时该字段未赋值(保持nil),尝试写入Realm会导致对象被标记为无效,触发异常。 - 循环内频繁单条写入+多Realm实例操作:循环中每次处理一个item就执行一次Realm写入,且
getThumbnailPhotoUrl内部重新创建Realm实例,列表滚动时(UI实时访问Realm对象),频繁的事务操作加跨实例潜在冲突,会加剧对象失效概率。
修复方案
1. 修正模型字段的可选性(必做)
打开WhatsNewQuiz模型,将quizOwnerImageUrl改为可选类型,允许为空:
class WhatsNewQuiz: Object { // 其他字段... @Persisted var quizOwnerImageUrl: String? // 改为可选类型 }
如果业务不允许字段为空,可在Firebase查询失败时设置默认值(比如默认图片URL):
catch { print("Error fetching thumbnail url: \(error)") item.quizOwnerImageUrl = "https://your-default-image-url.com" // 设置默认值 }
2. 批量写入Realm,减少事务次数
将循环内的单条写入改为批量写入,降低UI滚动时的Realm更新频率:
@MainActor func downloadWhatsNewItemsAndInsertOrUpdateAtLocalDb(item: WhatsNewQuiz? = nil) { Task { do { let whatsNewQuizItems = try await getMyWhatsNewQuizDocs(lastAddedAt: item?.launchedAt) if !whatsNewQuizItems.isEmpty { let realm = try await Realm() // 先统一处理所有item的图片URL for item in whatsNewQuizItems { do { // 注意:正式环境要传变量item.quizOwnerUid,而非字符串字面量 let quizOwnerImageUrl = try await getThumbnailPhotoUrl(item.quizOwnerUid, realm: realm) item.quizOwnerImageUrl = quizOwnerImageUrl } catch { print("Error fetching thumbnail url: \(error)") item.quizOwnerImageUrl = "https://your-default-image-url.com" // 可选:设置默认值 } } // 批量写入所有item try realm.write { for item in whatsNewQuizItems { realm.add(item, update: .modified) } } } } catch { print("Error fetching new quiz items: \(error)") } } }
3. 共享Realm实例,避免跨实例操作
修改getThumbnailPhotoUrl函数,接收外部传入的Realm实例,不再内部创建,保证整个流程使用同一个Realm实例:
@MainActor func getThumbnailPhotoUrl(_ personUid: String, realm: Realm) async throws -> String { if let imageUrlHolder = realm.object(ofType: ImageUrlHolder.self, forPrimaryKey: thumbnailContentId(personUid)) { return imageUrlHolder.downloadUrl } else { let storageRef = getPersonThumbnailProfilePhotoStorageRef(personUid: personUid) let downloadUrl = try await storageRef.downloadURL() let newImageUrlHolder = ImageUrlHolder(contentId: thumbnailContentId(personUid), downloadUrl: downloadUrl.absoluteString) try realm.write { realm.add(newImageUrlHolder, update: .modified) } return downloadUrl.absoluteString } }
4. 额外注意:修正参数错误
你当前代码中故意传入错误UID的地方写的是getThumbnailPhotoUrl("item.quizOwnerUid"),这是字符串字面量而非变量引用,正式环境中需改为getThumbnailPhotoUrl(item.quizOwnerUid),否则会持续触发Firebase错误。
内容的提问来源于stack exchange,提问作者Anudeep Ananth
相关产品推荐
相关产品推荐

