Подтвердить что ты не робот

Хранение массива строк с использованием Realm RLMArray

Кто-нибудь знает, как вы можете использовать Realm для хранения массива строк? Я пытаюсь правильно отобразить следующий ответ в Realm:

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

У нас есть объект zoneInfo, который содержит массив pricesInfoLines. Этот массив parameterInfoLines содержит строки. В 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.

4b9b3361

Ответ 1

Перекрестная публикация из github issue response: Хотя этот пример демонстрирует, как хранить плоские массивы строк в модели 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 nicknames: \(person.nicknames)")
}

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

Ответ 2

Для Swift 3.0 здесь есть изменение (в моем случае компилятор Xcode 8 не предлагал автоматическое исправление, когда я переключился на swift 3.0, поэтому мне пришлось немного поправить его).

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

Ответ 3

Подход 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

UPDATE (большинство предыдущих ответов больше не верны):

Теперь вы можете хранить примитивные типы или их обнуляемые копии (более конкретно: логические, целые и числовые числа с плавающей запятой, строки, даты и данные) непосредственно в 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, также поддерживают списки примитивных типов.

Ответ 5

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