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

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

@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属性将采用该类中声明的默认值,而不是版本使用便捷初始化传递给类的类型值。

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

@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”,那么一切都很好!

我很困惑。 1)为什么添加一个便利初始化有这个效果? 2)为什么将财产设为“公开”可以解决问题?

我创建了一个演示Xcode项目来说明问题,并在任何人需要时可以共享。



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

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

最佳答案

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

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

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中

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加载两个对象并打印它们。

let testResults = realm.objects(TestClass.self)

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


和输出:

some name some string
another name another string


因此,在这种情况下,创建实例时将正确覆盖默认值“ placeholder”。

编辑:

更多信息。

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

10-05 20:22
查看更多