使用Realm的RLMArray存储字符串数组

时间:2022-09-06 13:09:06

Does anyone know how you can use Realm to store an array of strings? I'm trying to map the following response into Realm correctly:

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

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

We have a zoneInfo object that contains a tariffInfoLines array. This tariffInfoLines array contains strings. In Realm there are two different variable types for storing data. The first is RLMObject which allows your standard NSString, int, long etc.

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

The second type is RLMArray, which is used for arrays (as NSArray is not supported). You have to give the array a type, which must be a class that subclasses RLMObject. We have so far got around this by using a ABCRealmString object, as shown below:

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

@property RLMArray<ABCRealmString> *tariffInfoLines;

ABCRealmString contains an NSString property (it is basically a wrapper):

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

@property NSString *value;

However what this means is that when Realm tries to map the response to persist the data, it is looking for a value for the key "value" (the name of the property). It appears that it expects a response similar to the following:

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

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

In the project, we have it working for the following structure:

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

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

This has an array, with objects inside that have clear key value pairs that Realm can map to. The zoneInfo structure appears to be the only place that we have an array with sets of values inside without them being inside an object or having any keys.

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

If anyone could shed some light on this, regarding if this is possible using Realm, or whether an API change is required to match a structure that Realm can map.

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

5 个解决方案

#1


32  

Cross posting from the github issue response: Although this example demonstrates how to store flat arrays of strings on a Realm model, you can extend this pattern to store anything from arrays of integers to native Swift enum's. Basically anything that you can map to a representable type in Realm.

来自github问题响应的交叉发布:尽管此示例演示了如何在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"]

#2


3  

For the Swift 3.0 here is the change (in my case the Xcode 8 compiler didn't offer auto fix when i switched to swift 3.0 so I had some pain to resolve it).

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

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

#3


3  

UPDATE (most of the previous answers are no longer correct):

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

You can now store primitive types or their nullable counterparts (more specifically: booleans, integer and floating-point number types, strings, dates, and data) directly within RLMArrays or Lists. If you want to define a list of such primitive values you no longer need to define cumbersome single-field wrapper objects. Instead, you can just store the primitive values themselves.

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

Lists of primitive values work much the same way as lists containing objects, as the example below demonstrates for Swift:

原始值列表与包含对象的列表的工作方式大致相同,如下面的示例演示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

All other languages supported by Realm also supports lists of primitive types.

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

#4


2  

The RealmString approach is good, but you end up with a new RealmString every time you update the values, leaving a ton of unused objects laying around if you don't clean them up.

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

I would suggest using something like:

我建议使用类似的东西:

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"]
    }
}

#5


-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
    }
}

#1


32  

Cross posting from the github issue response: Although this example demonstrates how to store flat arrays of strings on a Realm model, you can extend this pattern to store anything from arrays of integers to native Swift enum's. Basically anything that you can map to a representable type in Realm.

来自github问题响应的交叉发布:尽管此示例演示了如何在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"]

#2


3  

For the Swift 3.0 here is the change (in my case the Xcode 8 compiler didn't offer auto fix when i switched to swift 3.0 so I had some pain to resolve it).

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

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

#3


3  

UPDATE (most of the previous answers are no longer correct):

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

You can now store primitive types or their nullable counterparts (more specifically: booleans, integer and floating-point number types, strings, dates, and data) directly within RLMArrays or Lists. If you want to define a list of such primitive values you no longer need to define cumbersome single-field wrapper objects. Instead, you can just store the primitive values themselves.

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

Lists of primitive values work much the same way as lists containing objects, as the example below demonstrates for Swift:

原始值列表与包含对象的列表的工作方式大致相同,如下面的示例演示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

All other languages supported by Realm also supports lists of primitive types.

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

#4


2  

The RealmString approach is good, but you end up with a new RealmString every time you update the values, leaving a ton of unused objects laying around if you don't clean them up.

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

I would suggest using something like:

我建议使用类似的东西:

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"]
    }
}

#5


-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
    }
}