Skip to content

Commit

Permalink
Prevent calling completion closures multiple times by making private …
Browse files Browse the repository at this point in the history
…Client result handling methods return their results
  • Loading branch information
ejensen committed Dec 3, 2020
1 parent cfc14e3 commit 52170e9
Showing 1 changed file with 21 additions and 31 deletions.
52 changes: 21 additions & 31 deletions Sources/Contentful/Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ open class Client {
let finishDataFetch: (ResultsHandler<Data>) = { result in
switch result {
case .success(let mappableData):
self.handleJSON(data: mappableData, completion: completion)
completion(self.handleJSON(data: mappableData))
case .failure(let error):
completion(.failure(error))
}
Expand Down Expand Up @@ -382,12 +382,7 @@ open class Client {
return nil
}
return fetchCurrentSpaceLocales { result in
switch result {
case .success(let localesResponse):
completion(Result.success(localesResponse.items))
case .failure(let error):
completion(.failure(error))
}
completion(result.map { $0.items })
}
}

Expand Down Expand Up @@ -421,33 +416,32 @@ open class Client {
// At this point, We know for sure that the type returned by the API can be mapped to an `APIError` instance.
// Directly handle JSON and exit.
let statusCode = (response as! HTTPURLResponse).statusCode
self.handleRateLimitJSON(
let result = handleRateLimitJSON(
data: data,
timeUntilLimitReset: timeUntilLimitReset,
statusCode: statusCode,
jsonDecoder: jsonDecoder
) { (_ result: Result<RateLimitError, Error>) in
switch result {
case .success(let rateLimitError):
completion(.failure(rateLimitError))
case .failure(let auxillaryError):
// We should never get here, but we'll bubble up what should be a `SDKError.unparseableJSON` error just in case.
completion(.failure(auxillaryError))
}
)

switch result {
case .success(let rateLimitError):
completion(.failure(rateLimitError))
case .failure(let auxillaryError):
// We should never get here, but we'll bubble up what should be a `SDKError.unparseableJSON` error just in case.
completion(.failure(auxillaryError))
}

return true
}

private func handleRateLimitJSON(
data: Data,
timeUntilLimitReset: Int,
statusCode: Int,
jsonDecoder: JSONDecoder,
completion: ResultsHandler<RateLimitError>
) {
jsonDecoder: JSONDecoder
) -> Result<RateLimitError, Error> {
guard let rateLimitError = try? jsonDecoder.decode(RateLimitError.self, from: data) else {
completion(.failure(SDKError.unparseableJSON(data: data, errorMessage: "SDK unable to parse RateLimitError payload")))
return
return .failure(SDKError.unparseableJSON(data: data, errorMessage: "SDK unable to parse RateLimitError payload"))
}
rateLimitError.statusCode = statusCode
rateLimitError.timeBeforeLimitReset = timeUntilLimitReset
Expand All @@ -458,13 +452,10 @@ open class Client {
"""
ContentfulLogger.log(.error, message: errorMessage)
// In this case, .success means that a RateLimitError was successfully initialized.
completion(Result.success(rateLimitError))
return .success(rateLimitError)
}

private func handleJSON<DecodableType: Decodable>(
data: Data,
completion: @escaping ResultsHandler<DecodableType>
) {
private func handleJSON<DecodableType: Decodable>(data: Data) -> Result<DecodableType, Error> {
let jsonDecoder = jsonDecoderBuilder.build()

var decodedObject: DecodableType?
Expand All @@ -473,7 +464,7 @@ open class Client {
} catch let error {
let sdkError = SDKError.unparseableJSON(data: data, errorMessage: "\(error)")
ContentfulLogger.log(.error, message: sdkError.message)
completion(.failure(sdkError))
return .failure(sdkError)
}

guard let linkResolver = jsonDecoder.userInfo[.linkResolverContextKey] as? LinkResolver else {
Expand All @@ -482,22 +473,21 @@ open class Client {
errorMessage: "Couldn't find link resolver instance."
)
ContentfulLogger.log(.error, message: error.message)
completion(.failure(error))
return
return .failure(error)
}

linkResolver.churnLinks()

// Make sure decoded object is not nil before calling success completion block.
if let decodedObject = decodedObject {
completion(.success(decodedObject))
return .success(decodedObject)
} else {
let error = SDKError.unparseableJSON(
data: data,
errorMessage: "Unknown error occured during decoding."
)
ContentfulLogger.log(.error, message: error.message)
completion(.failure(error))
return .failure(error)
}
}
}

0 comments on commit 52170e9

Please sign in to comment.