【问题标题】:About transaction in Realm database关于 Realm 数据库中的事务
【发布时间】:2017-06-05 05:19:43
【问题描述】:

这是我的Realm 对象:

class AchievementDate : Object {

    dynamic var date: Date = Date()
    dynamic var apple: Int = Int(0)

    func save() {
        do {
            let realm = try Realm()
            try realm.write {
                realm.add(self)
            }
        } catch let error as NSError {
            fatalError(error.localizedDescription)
        }
    }
}

我在 View 控制器的 viewDidLoad() 方法中更改了苹果的值,如您所见:

override func viewDidLoad() {      
    super.viewDidLoad()
    achievementDate.apple = 2
    achievementDate.save()    
}

然后当用户单击屏幕上的暂停按钮时,我会更新苹果的值,如下所示:

@IBAction func pausedButtonTapped(_ sender: UIButton) {
    achievementDate.apple += 1
    achievementDate.save()
}

Xcode 运行成功,但是当我单击暂停按钮时,应用程序崩溃了。在控制台中它说:

*** 由于未捕获的异常“RLMException”而终止应用程序,原因:“尝试在写入事务之外修改对象 - 调用 首先在 RLMRealm 实例上开始写事务。'

我对此很困惑,顺便说一句,交易一般是什么意思?非常感谢。

【问题讨论】:

    标签: ios swift swift3 realm


    【解决方案1】:

    写入事务用于将领域内对象的修改分组到单个工作单元中。 Managed Realm 对象只能在写入事务中进行修改。写入事务的范围是您传递给Realm.write(_:) 的调用的块。对write 的调用开始一个写事务,在事务处于活动状态时执行主体,当块返回时,写事务被提交,并且更改被持久化到 Realm 文件中。

    您尚未分享 achievementDate 是如何初始化的,但根据您看到的异常假设它是一个托管对象的 AchievementDate 实例似乎是安全的(也就是说,它要么被创建然后添加到领域,或者从领域加载)。作为例外说明,您只能在写入事务中修改托管对象。您可以扩展写入事务的范围以包含对托管对象的修改,或者您可以完全避免修改托管对象(通过向模型类添加主键,并使用 Realm.create(_:value:update:)Realm.add(_:update:)update: true 使用给定的主键值更新现有对象)。

    【讨论】:

    • 我通过声明一个变量来初始化对象: var achievementDate = AchievementDate() 然后将它传递给视图控制器。
    • 顺便说一句,如何扩大写入事务的范围以包含修改,如何解决这个问题?提前致谢。
    • 这意味着它以非托管对象的形式开始,但在您第一次调用realm.add(self, update: true)(在viewDidLoad() 内)时成为托管对象。要扩大写入事务的范围,您需要将调用 Realm.write(_:) 移出您的 save() 函数。
    • 有什么方法可以作为托管对象开始生活吗?建议?谢谢。
    • 如果我将它从我的 save() 函数中移出,是否意味着我应该在需要时只在视图控制器中调用它。
    【解决方案2】:

    如果要更新模型,首先需要定义一个主键

    class AchievementDate: Object {
        dynamic var id = 0
        dynamic var date:Date = Date()
        dynamic var apple:Int = Int(0)
    
        override static func primaryKey() -> String? {
            return "id"
        }
    }
    

    然后像这样更新模型:

    static func save(achievementDate:AchievementDate) {
        let realm = try! Realm()
        try! realm.write {
            realm.add(achievementDate, update: true)
        }
    }
    

    或者,如果您不需要主键,并且模型已经从 Realm 检索到,您可以像这样更新模型:

    let realm = try! Realm()
    try! realm.write {
        achievementDate.apple = 2
    }
    

    【讨论】:

    • 不需要定义主键来更新对象。您可以通过任何支持的查询检索对对象的引用,然后在写入事务中简单地修改其属性。
    • @bdash 如果我定义一个主键来更新对象,我可以理解主键实际上是这个对象在内存中的引用吗?然后检索它并更新它
    • 主键(如果已声明)是对象上唯一标识给定对象的属性。 Realm 提供了一些方便的函数,可用于声明主键的类(Realm.object(ofType:forPrimaryKey:)Realm.create(_:value:update:) / Realm.add(_:update:)update: true)。
    • @Nan,有了主键,就可以非常准确的区分对象了。
    • 我按照你的第一种方法,我对对象进行了修改并更新了 save() 函数,Xcode 仍然抱怨这个问题?很困惑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-16
    • 2010-10-16
    相关资源
    最近更新 更多