如何从Swift中的Contentful访问图像?

时间:2018-03-05 13:58:34

标签: ios swift contentful

这是我获取参赛作品的方式:

func fetchAllEntriesByLocation(latitude:Double, longitude: Double, completion: @escaping (([Item]) ->Void)) {
    var items:[Item] = []

    let query = Query(where: "content_type", .equals("item")).where("fields.location", .isNear(Location(latitude: latitude, longitude: longitude)))
    client.fetchEntries(with: query) { [weak self] result in
        guard let strongSelf = self else { return }
        DispatchQueue.main.async {
            strongSelf.delegate?.finishedTask()
        }
        switch result {
        case .success(let entries):
            entries.items.forEach { entry in
                items.append(Item(entry: entry))
            }
            DispatchQueue.main.async {
                completion(items)
            }
        case .error(let error):
            print(error)
        }
    }

}

以及我如何映射它们

final class Item: EntryModellable {

static let contentTypeId: String = "item"

let name: String
let location: Location
let address: String
let open: String
let desc: String
let phone: String
let url: String
let thumbUrl: Asset


init(entry: Entry) {
    self.name = entry.fields["name"] as? String ?? ""
    self.location = entry.fields["location"] as? Location ?? Location(latitude: 52.23, longitude: 20.9)
    self.open = entry.fields["open"] as? String ?? ""
    self.address = entry.fields["address"] as? String ?? ""
    self.desc = entry.fields["opis"] as? String ?? ""
    self.phone = entry.fields["phone"] as? String ?? ""
    self.url = entry.fields["www"] as? String ?? ""
    self.thumbUrl = entry.fields["thumb"] as? Asset
}

}

当我尝试映射到Asset类型时,会出现问题。虽然当我打印我的作品时,我会看到"拇指" key,变量的类型是Contentful.Link.asset(Contentful.Asset)。因此我无法将其转换为资产类型。

我想要实现的只是存储图像Url以便稍后使用Kingfisher或类似的库来加载图像。

存储图像以访问其网址的正确方法是什么?

编辑:

我尝试了下面介绍的解决方案,现在我收到以下运行时错误: enter image description here

错误是:

  

致命错误:在解包可选值时意外发现nil

1 个答案:

答案 0 :(得分:3)

看起来您使用的是旧版SDK。 contentful.swift SDK现在位于version 1.0.1,强烈建议升级到带来API稳定性的最新版本,以及使用EntryDecodable协议将数据映射到您自己的类型的不同界面。它利用Swift 4的Decodable协议,因此您可以使用标准的lib + SDK提供的一些帮助扩展方法来控制JSON如何映射到您的类型!

使用contentful.swift 1.0.1,EntryDecodable协议将正确链接所有类型和资产,而不会创建重复项。您的类看起来如下所示(请注意,如果您拥有Contentful中不需要的属性(因此可以在响应中省略),则应使用decodeIfPresent返回可选项。

final class Item: EntryDecodable, ResourceQueryable {

    static let contentTypeId: String = "item"

    let sys: Sys
    let name: String
    let location: Location
    let address: String
    let open: String
    let desc: String
    let phone: String
    let url: String

    // Links must be optional variables as they are resolved after the initializer exits        
    var thumbUrl: Asset? 

    public required init(from decoder: Decoder) throws {
        sys             = try decoder.sys()
        let fields      = try decoder.contentfulFieldsContainer(keyedBy: Item.Fields.self)
        name            = try fields.decode(String.self, forKey: .name)
        desc            = try fields.decode(String.self, forKey: .desc)
        location = try? fields.decodeIfPresent(Location.self, forKey: .location) ?? Location(latitude: 52.23, longitude: 20.9)
        address = try fields.decode(String.self, forKey: .address)
        open = try fields.decode(String.self, forKey: .open)
        phone  try fields.decode(String.self, forKey: .phone)
        url = try fields.decode(String.self, forKey: .url) 


        // Here is how you resolve your Asset.
        try fields.resolveLink(forKey: .thumbUrl, decoder: decoder) { [weak self] linkedAsset in
            self?.thumbUrl = linkedAsset as? Asset
        }
    }

    // If your Contentful field names differ from your property names, define the mapping here.
    enum Fields: String, CodingKey {
        case name, location, open, address, phone
        case url      = "www"
        case desc     = "opis"
        case thumbUrl = "thumb"
    }
}

现在,您需要更新查询:

let query = QueryOn<Item>.where(field: .location, .isNear(Location(latitude: latitude, longitude: longitude)))
client.fetchMappedEntries(matching: query) { [weak self] (result: Result<MappedArrayResponse<Item>>) in
    // Handle your data here, the thumbUrl field will contain a resolved asset for your entries (if that relationship exists in Contentful)
    switch result {
        case .success(let arrayResponse):
            if let firstItem = arrayResponse.items.first {
                print(firstItem.thumburl?.urlString) 
            }
        case .error(let error):
            print(error)        
    }
}