web-dev-qa-db-ja.com

RealmのRLMArrayを使用して文字列の配列を格納する

Realmを使用して文字列の配列を格納する方法を知っている人はいますか?次の応答をレルムに正しくマッピングしようとしています。

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

TariffInfoLines配列を含むzoneInfoオブジェクトがあります。このtariffInfoLines配列には文字列が含まれています。レルムには、データを格納するための2つの異なる変数タイプがあります。最初は RLMObject で、標準のNSString、int、longなどを許可します。

2番目のタイプは 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を使用してこれが可能かどうか、またはRealmがマップできる構造に一致させるためにAPIの変更が必要かどうかについて、誰かがこれに光を当てることができるかどうか。

13
Jamie

github issue 応答からのクロスポスト:この例では、Realmモデルに文字列のフラット配列を格納する方法を示していますが、このパターンを拡張して、整数の配列からネイティブのSwift enum's。基本的に、レルムで表現可能な型にマップできるすべてのもの。

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"]
34
yoshyosh

更新(以前の回答のほとんどは正しくありません):

RLMArraysまたはLists内に直接、プリミティブ型またはnullが可能な対応物(より具体的には、ブール、整数および浮動小数点型、文字列、日付、およびデータ)を格納できるようになりました。そのようなプリミティブ値のリストを定義したい場合、面倒な単一フィールドラッパーオブジェクトを定義する必要はありません。代わりに、プリミティブ値自体を格納できます。

プリミティブ値のリストは、以下の例が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でサポートされている他のすべての言語も、プリミティブ型のリストをサポートしています。

8
bmunk

Swift 3.0の場合、ここに変更があります(私の場合、Xcode 8コンパイラはSwift 3.0に切り替えたときに自動修正を提供しなかったため、それを解決するための痛み)。

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

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"]
    }
}
2
Rok Gregorič
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
    }
}
0
Ace