境界与Swift:首次加载后不要更新列

时间:2016-04-29 14:14:04

标签: json swift realm

对于我目前的项目,我正在与Realm合作。我对后端进行2次调用,以获取我的JSON数据。第一个调用使用类别Id, Name & a imageUrl填充我的数据库(命名类别)。

class Categories: Object, Mappable {
    dynamic var id:Int = 0
    dynamic var name:String?
    dynamic var imageUrl:String?

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


    override class func primaryKey() -> String {
        return "id"
    }

    func mapping(map: Map) {
        id <- map["id"]
        name <- map["name"]
        imageUrl <- map["imageUrl"]
    }    
}

第二个电话会收到很多不同的信息+每个项目还有一个类别Name & Id可用,我也会写入&#34;类别&#34;对象(注意:没有imageUrl字段,它没有那个JSON)

class Publication: Object, Mappable {
    dynamic var id:Int = 0
    ...
    var categories = List<Categories>()

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

    override static func primaryKey() -> String? {
        return "id"
    }

    func mapping(map: Map) {
        id <- map["id"]
        // map ID and Categories of this item to the Categories db
        categories <- (map["categories"], ListTransform<Categories>())
    }    
}

这是Publication JSON的一部分,它会覆盖我的Category数据库(如您所见,JSON中没有给出imageUrl)

{
    "categories": [
        {
            "id": 39,
            "name": "Etenswaren "
        },
        {
            "id": 91,
            "name": "Dranken"
        }
    ],
}

我现在在我的数据库中遇到的问题是,当我的两个电话完成时,我的Categories对象imageUrl正在被清除(至少是我的类别)在我的Publication课程中找到的内容不再包含网址。)

我希望imageUrl列在填充后不受影响(这样所有网址仍然存在,即使在发布中找到了类别)。我怎么能这样做?

欢迎不同的解决方案。

enter image description here

1 个答案:

答案 0 :(得分:1)

因此,您正在使用ObjectMapper将JSON反序列化为对象模型。对于Publication的属性categories,您依赖于自定义转换ListTransform,我认为它看起来有点像this gist

这个ListTransform将创建一个新的List并随后填充来自给定JSON数组的所有值(如果它是一个数组)。 如果将如此创建的Publication对象添加到Realm,除非明确地将参数update传递为true,否则您的类别将被视为新对象。但是,这将始终将所有对象属性视为新数据,甚至是空字段,这意味着它会使用nil值覆盖数据库中的填充字段。

因此,您可以定义一个自定义TransformType,它可以通过Realm中的主键查找对象。

public class RetrievingListTransform<T:RealmSwift.Object where T:Mappable> : TransformType {
    public typealias Object = List<T>
    public typealias JSON = [AnyObject]

    let mapper = Mapper<T>()

    public let realm: Realm

    /// Provide a function which maps the JSON to a primary key.
    public let primaryKeyTransform: ([String: AnyObject]) -> AnyObject?

    public init(realm: Realm, primaryKeyTransform: ([String: AnyObject]) -> AnyObject?) {
        self.realm = realm
        self.primaryKeyTransform = primaryKeyTransform
    }

    public func transformFromJSON(values: AnyObject?) -> Object? {
        let list = List<T>()
        guard let values = values as? [AnyObject] else {
            return list
        }
        for value in values {
            if let object = transformFromJSONArrayItemToObject(value) {
                list.append(object)
            }
        }
        return list
    }

    func transformFromJSONArrayItemToObject(json: AnyObject) -> T? {
        guard let jsonDict = json as? [String: AnyObject] else {
            return nil
        }
        guard let primaryKey = primaryKeyTransform(jsonDict) else {
            return nil
        }
        if let object = realm.objectForPrimaryKey(T.self, key: primaryKey) {
            return object
        } else {
            return mapper.map(jsonDict)
        }
    }

    public func transformToJSON(list: Object?) -> JSON? {
        guard let list = list else {
            return []
        }
        return list.map { mapper.toJSON($0) }
    }
}

您可以像下面这样使用它:

class Publication: Object, Mappable {
    dynamic var id:Int = 0
    ...
    var categories = List<Categories>()

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

    override static func primaryKey() -> String? {
        return "id"
    }

    func mapping(map: Map) {
        id <- map["id"]
        categories <- (map["categories"], RetrievingListTransform<Categories>(realm: try! Realm()) { (json: [String : AnyObject]) -> AnyObject? in
            return json["id"]
        })
    }    
}

尝试解决此问题时,主要问题是您需要在mapping功能中访问您的领域。但由于签名由ObjectMapper提供,它使用最终的Swift类,因此提供的扩展点很少,因此您无法根据依赖注入最佳实践正确地注入Realm实例。

出于这个原因,我依赖默认的Realm配置。如果你有不同的配置,那么它需要更多的努力,如 通常不建议在全局可访问变量中共享Realm个实例,因为它们不是线程安全的。所以你可以共享你的RealmConfiguration或者需要一个工厂方法,它可以为当前线程返回Realm个实例。