为什么在Realm对象声明中添加便捷初始化会导致私有值混乱? [英] Why does adding a convenience init to a Realm object declaration mess with private values?

查看:82
本文介绍了为什么在Realm对象声明中添加便捷初始化会导致私有值混乱?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个Realm对象,该对象需要存储一个枚举值.为此,我使用了中概述的方法问题,其中涉及声明String类型的私有属性,然后声明Enum类型的另一个属性,该类型使用getter和setter设置/读取私有属性.

I have created a Realm object that needs to store an enum value. To do that I use a method outlined in this question which involves declaring a private property of type String, and then declaring another property of type Enum that sets/reads the private property using getters and setters.

为便于参考,下面是该代码:

For ease of reference here is the code for that:

@objcMembers
class PlaylistRealmObject: Object {

    dynamic var id: String = UUID().uuidString
    dynamic var created: Date = Date()
    dynamic var title: String = ""
    private dynamic var revisionTypeRaw: String = RevisionType.noReminder.rawValue
    var revisionType: RevisionType {
        get { return RevisionType(rawValue: revisionTypeRaw)! }
        set { revisionTypeRaw = newValue.rawValue }
    }
    let reminders = List<ReminderRealmObject>()
    let cardsInPlaylist = List<CardRealmObject>()

    override static func primaryKey() -> String? {
        return "id"
    }

}

但是我注意到,如果我在类声明中添加了一个便利的初始化(以便于初始化对象变得更加容易),我最终得到的对象的versionType属性将采用该类中声明的默认值,并且不是使用便捷初始化传递给类的修订类型值.

I have noticed though that if I add a convenience init to the class declaration (to make it a bit easier to initialise the object) the revisionType properties on the objects I end up with adopt the default value declared in the class, and NOT the revision type value passed to the class using the convenience init.

这是带有方便初始化的类声明

Here is the class declaration with a convenience init

@objcMembers
class PlaylistRealmObject: Object {

    dynamic var id: String = UUID().uuidString
    dynamic var created: Date = Date()
    dynamic var title: String = ""
    private dynamic var revisionTypeRaw: String = RevisionType.noReminder.rawValue
    var revisionType: RevisionType {
        get { return RevisionType(rawValue: revisionTypeRaw)! }
        set { revisionTypeRaw = newValue.rawValue }
    }
    let reminders = List<ReminderRealmObject>()
    let cardsInPlaylist = List<CardRealmObject>()

    convenience init(title: String, revisionType: RevisionType) {
        self.init()
        self.title = title
        self.revisionType = revisionType
    }

    override static func primaryKey() -> String? {
        return "id"
    }

}

而且-使事情更加令人困惑-如果我只是从versionTypeRaw属性中删除单词"private",一切都会正常!

And - to make things even more perplexing - if I simply remove the word 'private' from the revisionTypeRaw property, everything works fine!

我很困惑. 1)为什么添加一个便利初始化会产生这种效果? 2)为什么将属性设为公开"可以解决此问题?

I am confused. 1) Why does adding a convenience init have this effect? 2) Why does making the property 'public' resolve the issue?

我已经创建了一个演示Xcode项目来说明该问题,并可以在任何人需要的情况下共享.

I have created a demo Xcode project to illustrate the issue and can share it if anyone needs it.

更新: 我发现了问题.它与init的便利无关.我根据Realm文档在类顶部使用@objcMembers: https ://realm.io/docs/swift/latest/#property-属性

Update: I found the problem. It has nothing to do with the convenience init. I am using @objcMembers at the top of the class as per the Realm docs: https://realm.io/docs/swift/latest/#property-attributes

如果将其删除并将@objc放在private关键字的前面,则一切正常.我想问题是:什么解释了这种行为?

If you remove this and place @objc in front of the private keyword, everything works as would be expected. I guess the question then is: what explains this behaviour?

推荐答案

这是一个很好的问题,但是我认为问题出在代码的其他地方.让我们测试一下.

This is a good question but I think the issue is elsewhere in the code. Let's test it.

我创建了一个TestClass,它具有一个Realm管理的公共可见变量,名称,以及一个非托管的公共变量visibleVar,后者由Realm管理的私有变量privateVar作为后盾.我还为每个问题提供了一个方便的初始化.重要的部分是将privateVar设置为字符串占位符",因此我们需要查看它是否被覆盖.

I created a TestClass that has a Realm managed publicly visible var, name, as well as a non-managed public var visibleVar which is backed by a Realm managed private var, privateVar. I also included a convenience init per the question. The important part is the privateVar is being set to the string "placeholder" so we need to see if that is overwritten.

class TestClass: Object {
    @objc dynamic var name = ""
    @objc private dynamic var privateVar = "placeholder"

    var visibleVar: String {
        get {
            return self.privateVar
        }
        set {
            self.privateVar = newValue
        }
    }

    convenience init(aName: String, aString: String) {
        self.init()
        self.name = aName
        self.visibleVar = aString
    }
}

然后我们创建两个实例并将其保存在Realm中

We then create two instances and save them in Realm

let a = TestClass(aName: "some name", aString: "some string")
let b = TestClass(aName: "another name", aString: "another string")

realm.add(a)
realm.add(b)

然后执行按钮操作,以从Realm加载两个对象并打印它们.

Then a button action to load the two objects from Realm and print them.

let testResults = realm.objects(TestClass.self)

for test in testResults {
    print(test.name, test.visibleVar)
}

和输出:

some name some string
another name another string

因此,在这种情况下,创建实例时正确覆盖了占位符"的默认值.

So in this case, the default value of "placeholder" is being overwritten correctly when the instances are being created.

更多信息.

通过使用@objMembers定义整个类,它会将您的属性公开给Objective-C,但是私有再次将它们隐藏.因此,该属性不会暴露给ObjC.要扭转这种隐藏状态,您必须明确地说出@objc.因此,更好的做法是使用@objc动态定义每行的托管领域属性.

By defining your entire class with @objMembers, it exposes your propertites to Objective-C, but then private hides them again. So that property is not exposed to ObjC. To reverse that hiding, you have to say @objc explicitly. So, better practice is to define the managed Realm properties per line with @objc dynamic.

这篇关于为什么在Realm对象声明中添加便捷初始化会导致私有值混乱?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆