RealmSwift ObjectMapper управление строковым массивом (тегами)

#swift #realm #objectmapper

#swift #область #objectmapper

Вопрос:

Что мне нужно представить в RealmSwift, так это следующую схему JSON:

 { 
    "id": 1234,
    "title": "some value",
    "tags": [ "red", "blue", "green" ]
}
 

Это базовый строковый массив, на который я натыкаюсь. Я предполагаю, что в Realm мне нужно представить «теги» как

 dynamic id: Int = 0
dynamic title: String = ""
let tags = List<MyTagObject>()
 

создание собственной таблицы тегов в Realm, но как сопоставить ее с ObjectMapper? Вот как далеко я продвинулся…

 func mapping(map: Map) {
    id <- map["id"]
    title <- map["title"]
    tags <- map["tags"]
}
 

… но строка тегов, конечно, не компилируется из-за списка, а Realm не может использовать тип [String] .

Это похоже на довольно распространенную проблему, и я надеюсь, что кто-то, кто столкнулся с этим, может прокомментировать или указать на сообщение с предложением.

ОБНОВЛЕНИЕ 1 MyTagObject выглядит следующим образом:

 class MyTagObject: Object {
    dynamic var name: String = ""
}
 

ОБНОВЛЕНИЕ 2
Я нашел этот пост, в котором рассматривается объект realm, но предполагается, что массив имеет именованные элементы, а не простую строку.
https://gist.github.com/Jerrot/fe233a94c5427a4ec29b

Комментарии:

1. как выглядит MyTagObject класс?

2. Я обновил вопрос с помощью класса ozgur

3. Я не знаю, в чем проблема. тег — это список ‘MyTagbject’, так что это должно работать нормально…

Ответ №1:

Мое решение состоит в том, чтобы использовать ObjectMapper TransformType в качестве пользовательского метода для сопоставления JSON с List<String> типом Realm. Нет необходимости в моделях 2 Realm.

Переходим к вашему примеру JSON:

 { 
    "id": 1234,
    "title": "some value",
    "tags": [ "red", "blue", "green" ]
}
 
  1. Сначала создайте TransformType объект ObjectMapper:
 import Foundation
import ObjectMapper
import RealmSwift

public struct StringArrayTransform: TransformType {

    public init() { }

    public typealias Object = List<String>
    public typealias JSON = [String]

    public func transformFromJSON(_ value: Any?) -> List<String>? {
        guard let value = value else {
            return nil
        }
        let objects = value as! [String] 
        let list = List<String>()
        list.append(objectsIn: objects)
        return list
    }

    public func transformToJSON(_ value: Object?) -> JSON? {
        return value?.toArray()
    }

}

 
  1. Создайте свою модель 1 Realm, используемую для хранения данных JSON:
 import Foundation
import RealmSwift
import ObjectMapper

class MyObjectModel: Object, Mappable {

    @objc dynamic id: Int = 0
    @objc dynamic title: String = ""
    let tags = List<MyTagObject>()

    required convenience init?(map: Map) {
        self.init()
    }    

    func mapping(map: Map) {
        id <- map["id"]
        title <- map["title"]
        tags <- (map["tags"], StringArrayTransform())
    }

}
 

Готово!

Эта строка — волшебство: tags <- (map["tags"], StringArrayTransform()) . Это говорит ObjectMapper использовать наш пользовательский StringArrayTransform интерфейс, который я показал выше, который принимает массив строк JSON и преобразует его в область List<String> .

Ответ №2:

Прежде всего, мы должны предположить, что наша модель расширяет оба Object и Mappable .

Давайте создадим модель-оболочку для хранения типа primitive ( String ):

 class StringObject: Object {
    dynamic var value = ""
}
 

Затем мы описываем соответствующие свойства и правила сопоставления для корневой модели (не для модели-оболочки):

 var tags = List<StringObject>()

var parsedTags: [String] {
    var result = [String]()
    for tag in tags {
        result.append(tag.value)
    }
    return result
}

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

func mapping(map: Map) {
    if let unwrappedTags = map.JSON["tags"] as? [String] {
        for tag in unwrappedTags {
            let tagObject = StringObject()
            tagObject.value = tag
            tags.append(tagObject)
        }
    }
}
 

Нам нужно tags свойство для хранения и получения данных о тегах из Realm.
Тогда parsedTags свойство упрощает извлечение тегов в обычном формате массива.
ignoredProperties Определение позволяет избежать некоторых сбоев с Realm при сохранении данных (потому что, конечно, мы не можем хранить типы данных, отличные от Realm, в Realm).
И, наконец, мы вручную разбираем наши теги в mapping функции, чтобы сохранить их в области.

Ответ №3:

Это будет работать, если ваш массив тегов будет содержать объекты словаря с ключом: «name»

 { 
    "id": 1234,
    "title": "some value",
    "tags": [ ["name" : "red"], ... ]
}
 

Если вы не можете изменить объект JSON, я рекомендую вам программно сопоставить json с realm.

 for tagName in tags {
    let tagObject = MyTagObject()
    tagObject.name = tagName
    myObject.tags.append(tagObject)
}
 

Комментарии:

1. Точно!! Формат не может быть изменен, так как мне это закодировать? Есть ли там пример?

2. for tagName in tags { let tagObject = MyTagObject() tagObject.name = tagName myObject.tags.append(tagObject) }

3. Я предполагаю, что это внутри функции сопоставления, но как мне получить «теги» в вашем примере for-цикла?

4. используйте библиотеку синтаксического анализа. Как SwiftyJSON

5. о, вы имеете в виду, что я вообще не использую ObjectMapper … пишу свой собственный синтаксический анализ.

Ответ №4:

Следуйте этому коду

 import ObjectMapper
import RealmSwift

//Create a Model Class
class RSRestaurants:Object, Mappable {

    @objc dynamic var status: String?
    var data = List<RSData>()
    
    required convenience init?(map: Map) {
        self.init()
    }
    
    func mapping(map: Map) {
        status <- map["status"]
        data <- (map["data"], ListTransform<RSData>())
    }
}

//Use this for creating Array
class ListTransform<T:RealmSwift.Object> : TransformType where T:Mappable {
    typealias Object = List<T>
    typealias JSON = [AnyObject]
    
    let mapper = Mapper<T>()
    
    func transformFromJSON(_ value: Any?) -> Object? {
        let results = List<T>()
        if let objects = mapper.mapArray(JSONObject: value) {
            for object in objects {
                results.append(object)
            }
        }
        return results
    }
    
    func transformToJSON(_ value: Object?) -> JSON? {
        var results = [AnyObject]()
        if let value = value {
            for obj in value {
                let json = mapper.toJSON(obj)
                results.append(json as AnyObject)
            }
        }
        return results
    }
}