#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" ]
}
- Сначала создайте
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 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
}
}