Description
- contentful.swift version number:
4.2.2
- Xcode version number:
10.0 (10A254a)
- Target operating system(s) and version number(s)
- iOS: 12.0
- tvOS:
- watchOS:
- macOS:
- Package manager:
- Carthage
- Cocoapods
Hey,
It seems like there's an issue in how the SDK checks for custom types implementing the EntryDecodable
protocol, when fetching a single entry using the method Client.fetch(_:,id:,then:)
.
It checks whether the type passed is different from both EntryDecodable.self
and Entry.self
:
- For the latter, it's fine, since it's a class that can't be subclassed outside of the repo (though it should also probably be
final
for the same reason explained below) - For the former,
resourceType != EntryDecodable.self
never will befalse
, even if the types implement theEntryDecodable
protocol.
This can be reproduced using the following code:
protocol TestProtocol {
func test() // To add some metadata to the types, just in case
}
extension TestProtocol {
func test() {
}
}
struct Test1: TestProtocol {}
class Test2: TestProtocol {}
final class Test3: TestProtocol {}
enum Test4: TestProtocol {}
var testIndex = 1
func checkProtocol<TestType>(_ type: TestType.Type) {
print("Test\(testIndex) -> \(type != TestProtocol.self)")
testIndex += 1
}
checkProtocol(Test1.self)
checkProtocol(Test2.self)
checkProtocol(Test3.self)
checkProtocol(Test4.self)
Which will output:
Test1 -> true
Test2 -> true
Test3 -> true
Test4 -> true
This all happens here: https://github.com/contentful/contentful.swift/blob/master/Sources/Contentful/Client.swift#L458-L463
(likewise, if a subclass of Entry
is defined in the SDK, for example named MyEntry
, then MyEntry.self != Entry.self
is true)
I couldn't find a way to check if a meta-type inherits from/implements another in Swift so as not to change the code too much, so unfortunately I don't have any "proper" fix (probably something using generics constraint would be best).
Maybe adding a parameter resolveLinks
(defaults to true
) to the method would be enough? I'd expect anyway that most people will be retrieving Entry
or EntryDecodable
subtypes anyway
For now, until this is fixed, I've added a method that always resolved links like:
public func fetchAndResolveLinks<DecodableEntry: EntryDecodable>(
_ resourceType: DecodableEntry.Type,
id: String,
then completion: @escaping ResultsHandler<DecodableEntry>) -> URLSessionDataTask
{
let fetchCompletion: (Contentful.Result<ArrayResponse<DecodableEntry>>) -> Void = { result in
switch result {
case .success(let response) where response.items.first != nil:
completion(Result.success(response.items.first!))
case .error(let error):
completion(Result.error(error))
default:
completion(Result.error(SDKError.noResourceFoundFor(id: id)))
}
}
let query = ResourceQuery.where(sys: .id, .equals(id))
return fetch(url: url(endpoint: DecodableEntry.endpoint, parameters: query.parameters), then: fetchCompletion)
}
(copy/pasting part of the included fetch
method)