使用Realm的RLMArray

时间:2015-07-30 13:04:12

标签: ios objective-c realm

有谁知道如何使用Realm存储字符串数组?我正在尝试将以下响应正确映射到Realm中:

"zoneInfo": {
    "tariffInfoLines": [
        "In this city you pay per minute."
    ]
}

我们有一个包含tariffInfoLines数组的zoneInfo对象。此tariffInfoLines数组包含字符串。在Realm中,有两种不同的变量类型用于存储数据。第一个是RLMObject,它允许你的标准NSString,int,long等。

第二种类型是RLMArray,用于数组(不支持NSArray)。您必须为数组提供一个类型,该类型必须是RLMObject的子类。到目前为止,我们通过使用ABCRealmString对象解决了这个问题,如下所示:

@property RLMArray<ABCRealmString> *tariffInfoLines;

ABCRealmString包含一个NSString属性(它基本上是一个包装器):

@property NSString *value;

然而,这意味着当Realm尝试映射响应以持久化数据时,它正在寻找键“值”(属性的名称)的值。它似乎期望得到类似以下的响应:

"zoneInfo": {
    "tariffInfoLines": [
        {
            "value": "In this city you pay per minute."
        },
    ]
}

在项目中,我们让它适用于以下结构:

"userOptions": [
    {
        "wantsEmailNotifications": true,
        "wantsPushNotifications": false
    },
]

这有一个数组,其中的对象具有Realm可以映射到的清晰键值对。 zoneInfo结构似乎是我们唯一一个包含值集的数组,而不是在对象内部或有任何键。

如果有人能够对此有所了解,可以考虑使用Realm是否可行,或者是否需要更改API以匹配Realm可以映射的结构。

5 个答案:

答案 0 :(得分:34)

来自github issue响应的交叉发布:尽管此示例演示了如何在Realm模型上存储平面字符串数组,但您可以扩展此模式以存储从整数数组到本机Swift枚举的任何内容。基本上任何可以映射到Realm中可表示类型的东西。

class RealmString: Object {
    dynamic var stringValue = ""
}

class Person: Object {
    var nicknames: [String] {
        get {
            return _backingNickNames.map { $0.stringValue }
        }
        set {
            _backingNickNames.removeAll()
            _backingNickNames.appendContentsOf(newValue.map({ RealmString(value: [$0]) }))
        }
    }
    let _backingNickNames = List<RealmString>()

    override static func ignoredProperties() -> [String] {
        return ["nicknames"]
    }
}

// Usage...

let realm = try! Realm()
try! realm.write {
    let person = Person()
    person.nicknames = ["John", "Johnny"]
    realm.add(person)
}

for person in realm.objects(Person) {
    print("Person's nicknames: \(person.nicknames)")
}

// Prints:
// Person's nicknames: ["John", "Johnny"]

答案 1 :(得分:6)

更新(以前的大部分答案都不再正确):

现在,您可以直接在RLMArrays或Lists中存储基本类型或其可空对应项(更具体地说:布尔值,整数和浮点数类型,字符串,日期和数据)。如果要定义此类原始值的列表,则不再需要定义繁琐的单字段包装器对象。相反,您可以自己存储原始值。

原始值列表与包含对象的列表的工作方式大致相同,如下面的示例演示Swift:

class Student : Object {
    @objc dynamic var name: String = ""
    let testScores = List<Int>()
}

// Retrieve a student.
let realm = try! Realm()
let bob = realm.objects(Student.self).filter("name = 'Bob'").first!

// Give him a few test scores, and then print his average score.
try! realm.write {
    bob.testScores.removeAll()
    bob.testScores.append(94)
    bob.testScores.append(89)
    bob.testScores.append(96)
}
print("\(bob.testScores.average()!)")   // 93.0

Realm支持的所有其他语言也支持基元类型列表。

答案 2 :(得分:3)

对于Swift 3.0,这里是更改(在我的情况下,当我切换到swift 3.0时,Xcode 8编译器没有提供自动修复,所以我有一些痛苦要解决它)。

_backingNickNames.append(objectsIn: newValue.map { RealmString(value: [$0]) })

答案 3 :(得分:2)

RealmString方法很好,但每次更新数值时都会得到一个新的RealmString,如果你不清理它们,会留下大量未使用的对象

我建议使用类似的东西:

fileprivate let separator = "\u{FFFF}"

class Person: Object {
    fileprivate dynamic var _nicknames: String?
    var nicknames: [String] {
        get { return _nicknames?.components(separatedBy: separator) ?? [] }
        set { _nicknames = newValue.isEmpty ? nil : newValue.joined(separator: separator) }
    }

    override static func ignoredProperties() -> [String] {
        return ["nicknames"]
    }
}

答案 4 :(得分:-1)

extension String {
    func toStringObject() -> StringObject {
        return StringObject(initValue: self)
    }
}

extension Sequence where Iterator.Element == String {
    func toStringObjects() -> List<StringObject> {
        let list = List<StringObject>()
        for s in self {
            list.append(s.toStringObject())
        }
        return list
    }
}

extension Int {
    func toIntObject() -> IntObject {
        return IntObject(initValue: self)
    }
}

extension Sequence where Iterator.Element == Int {
    func toIntObjects() -> List<IntObject> {
        let list = List<IntObject>()
        for s in self {
            list.append(s.toIntObject())
        }
        return list
    }
}