如何从 Swift 中的 Contentful 访问图像?
How to access image from Contentful in Swift?
这是我获取条目的方式:
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
类型时出现问题。虽然当我打印我的条目时,我看到 "thumb" 键,变量的类型是 Contentful.Link.asset(Contentful.Asset)
。因此我无法将其转换为资产类型。
我想要实现的是存储图像 Url 以便稍后与 Kingfisher 或类似库一起使用它来加载图像。
存储图像以访问其 url 的正确方法是什么?
编辑:
我尝试了下面介绍的解决方案,但现在出现以下运行时错误:
错误是:
Fatal error: Unexpectedly found nil while unwrapping an Optional value
看来您使用的是旧版本的 SDK。 contentful.swift SDK 现在在 version 1.0.1,强烈建议升级到最新版本,它带来了 API 稳定性,以及使用 [=12 将数据映射到您自己的类型的不同接口=] 协议。它利用 Swift 4 的 Decodable
协议,因此您可以使用标准库 + SDK 提供的一些辅助扩展方法来控制 JSON 映射到您的类型的方式!
使用 contentful.swift 1.0.1,EntryDecodable
协议将正确地 link 您所有的类型和资产,而不会创建重复项。你的 class 看起来像下面这样(请注意,如果你有 Contentful 中不需要的属性(因此可以在响应中省略)你应该使用 decodeIfPresent
其中 returns 是可选的.
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)
}
}
这是我获取条目的方式:
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
类型时出现问题。虽然当我打印我的条目时,我看到 "thumb" 键,变量的类型是 Contentful.Link.asset(Contentful.Asset)
。因此我无法将其转换为资产类型。
我想要实现的是存储图像 Url 以便稍后与 Kingfisher 或类似库一起使用它来加载图像。
存储图像以访问其 url 的正确方法是什么?
编辑:
我尝试了下面介绍的解决方案,但现在出现以下运行时错误:
错误是:
Fatal error: Unexpectedly found nil while unwrapping an Optional value
看来您使用的是旧版本的 SDK。 contentful.swift SDK 现在在 version 1.0.1,强烈建议升级到最新版本,它带来了 API 稳定性,以及使用 [=12 将数据映射到您自己的类型的不同接口=] 协议。它利用 Swift 4 的 Decodable
协议,因此您可以使用标准库 + SDK 提供的一些辅助扩展方法来控制 JSON 映射到您的类型的方式!
使用 contentful.swift 1.0.1,EntryDecodable
协议将正确地 link 您所有的类型和资产,而不会创建重复项。你的 class 看起来像下面这样(请注意,如果你有 Contentful 中不需要的属性(因此可以在响应中省略)你应该使用 decodeIfPresent
其中 returns 是可选的.
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)
}
}