【问题标题】:Swift 3: Property observer for singletonSwift 3:单例的属性观察器
【发布时间】:2017-01-27 10:16:07
【问题描述】:

我想知道是否有任何方法可以观察单例类的任何属性的变化

在我的情况下,使用 Realm 我有类似的东西

class User: Object {
   dynamic var name:String = ""
   dynamic var email:String = ""
   dynamic var id:String = ""
   dynamic var picURL:String = ""
   dynamic var pic:Data = Data()

    static let currentUser = User()
    {
        didSet
        {
            try! realm.write {
                realm.add(currentUser, update: true)
            }
    }
  }
}

我想要实现的是我希望在我的应用程序中只有一个用户对象,并且只要它的任何属性被修改,我都想将它保存到 Realm。

但是,上面的示例显示错误

'let' 声明不能观察属性

你会如何处理它?你认为我的想法是让 Realm 对象单例并在任何属性更改时更新它是一个好主意吗?

我想知道拥有一个由 Realm 持久化的类的单例对象是否真的有意义。

【问题讨论】:

  • 不清楚你想要实现什么:要么可以修改currentUser,那么这应该是var,而不是let,或者不能修改currentUser(到目前为止,因为它是一个let 常量),但在这种情况下,设置它时不需要监听器。
  • @AndreasOetjen 你能具体说明我的解释中哪一部分不清楚吗?
  • @AndreasOetjen 请注意,如果我将其修改为 var,它将不再是单例
  • 如果你想要一个单例,你应该为currentUser实现一个getter,并创建一个私有初始化器private。

标签: ios swift swift3 realm


【解决方案1】:

目前不可能有一个单一领域的全面观察者Object,但是有an issue tracking it in the Realm GitHub,我相信目前正在优先考虑它。

Alcivanio 是正确的,因为您需要手动触发更新事件以确保将更改保留到 Realm。话虽如此,因为 Realm 控制持久对象中的访问器,所以不能保证在将对象保存到 Realm 后调用 didSet。为简单起见,我建议使用闭包来更新用户对象。

更新答案:如果你的单例是一个领域Object,你不能在写事务之外修改它的属性。就像我在下面写的那样,最简单的做法是拥有一个管理 Realm 写入事务的 update 闭包,然后您只需在其中更新 Singleton 对象的属性。

正如您还看到的,您不能将didSet 与let 定义的属性一起使用,因此最好退回到Objective-C 约定并使用内部实例变量。

一切就绪,也许可以考虑这样做:

fileprivate var _current: User? = nil

class User: Object {
    dynamic var name:String = ""
    dynamic var email:String = ""
    dynamic var id:String = ""
    dynamic var picURL:String = ""
    dynamic var pic:Data = Data()

    static var current: User
    {
        if _current == nil {
            let realm = try! Realm()

            // Query for an existing user
            _current = realm.objects(User.self).first

            // Create a new user if it didn't exist in Realm
            if _current == nil {
                 _current = User()
                 try! realm.write { realm.add(_current) }
            }
        }
        return _current
    }

    public func update(_ block: (() -> Void)) {
        let realm = try! Realm()
        try! realm.write(block)
    }
}

let user = User.current
user.update {
    user.name = "DCDC"
}

【讨论】:

  • 谢谢!不幸的是,我收到了instance member '_current' be used on type 'User'
  • @DCDC 这很奇怪。好的。我更新了答案。我对 Swift 单例进行了一些研究,并确认此方法有效(将 _current 置于课程范围之外)。
  • 我可能应该指出这个版本将创建一个新的User 并在每次运行应用程序时将其保存到 Realm。如果您只想要一个代表该用户的 User 对象,那么运行查询并仅在 Realm 文件还没有 User 对象的情况下创建一个新的 User 对象可能更合适。
  • 我在使用这种方法时遇到了一些其他问题——当我注销时,我从领域中删除了用户,所以现在当我尝试登录时,用户不再存在。当更新方法以下列方式工作时最好 - 如果没有用户,创建一个,或者更新已经存在的一个
  • 嗯,好吧。如果在 Realm 中删除对象,_current 不会自动变为nil。您需要确保在注销时,_current 也设置为 nil。
【解决方案2】:

好吧,如果你只有一个用户,你应该把这个观察者放在每个变量中,而不是放在 let user 中。在那里你可以调用用户更新的方法。

dynamic var name: String {
    didSet{
        User.updateOnRealm()//create this method
    }
}

要编写更新方法,您必须编写类似这样的内容

class func updateOnRealm() {
    //update code here
}

【讨论】:

  • 好的,这是唯一的方法,我无法观察 currentUser 对象的所有变化?
  • 你想观察currentUser是否被修改,或者User的任何属性是否被修改?
  • @DCDC 好像不行,你不能观察 let 用户。您将无法更改用户,但可以更改其变量。所以,对我来说观察使用 didSet 的用户是没有意义的。也许还有另一种方法可以做到这一点。如果您发现了,请与我们分享:)
【解决方案3】:

根据你写的:

我想要实现的是我希望在我的应用程序中只有一个用户对象,并且只要它的任何属性被修改,我都想将它保存到 Realm。

我会建议这个解决方案:

  1. 创建一个不使用单例模式的class User。

  2. 创建一个符合单例模式的class UserManager

  3. 为A 用户创建自定义设置方法。然后,在这些设置器中,您可以更改用户属性,无论是否写入数据库。您还可以检查使用 INPUT(将名称设置为小写等)。

使用这种方法,您可以轻松地测试您的 User 类、扩展它、子类化和重用。

如果您需要下面的代码 sn-ps 注释 =)。

【讨论】:

    猜你喜欢
    • 2017-06-06
    • 1970-01-01
    • 2016-04-22
    • 2015-02-02
    • 1970-01-01
    • 2019-07-31
    • 1970-01-01
    • 2020-08-15
    • 1970-01-01
    相关资源
    最近更新 更多