Skip to content

Commit

Permalink
Add low data mode support
Browse files Browse the repository at this point in the history
  • Loading branch information
onevcat committed Jan 1, 2021
1 parent b05183a commit 21d2c77
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 21 deletions.
5 changes: 5 additions & 0 deletions Sources/General/KFOptionsSetter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,11 @@ extension KFOptionSetter {
options.retryStrategy = strategy
return self
}

public func lowDataModeSource(_ source: Source?) -> Self {
options.lowDataModeSource = source
return self
}
}

// MARK: - Request Modifier
Expand Down
12 changes: 12 additions & 0 deletions Sources/General/KingfisherError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,18 @@ public enum KingfisherError: Error {
}
return false
}

var isLowDataModeConstrained: Bool {
if #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *),
case .responseError(reason: .URLSessionError(let sessionError)) = self,
let urlError = sessionError as? URLError,
urlError.networkUnavailableReason == .constrained
{
return true
}
return false
}

}

// MARK: - LocalizedError Conforming
Expand Down
34 changes: 13 additions & 21 deletions Sources/General/KingfisherManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,19 @@ public class KingfisherManager {
completionHandler?(.failure(error))
return
}
// When low data mode constrained error, retry with the low data mode source instead of use alternative on fly.
guard !error.isLowDataModeConstrained else {
if let source = retrievingContext.options.lowDataModeSource {
retrievingContext.options.lowDataModeSource = nil
startNewRetrieveTask(with: source, downloadTaskUpdated: downloadTaskUpdated)
} else {
// This should not happen.
completionHandler?(.failure(error))
}
return
}
if let nextSource = retrievingContext.popAlternativeSource() {
retrievingContext.appendError(error, to: source)
startNewRetrieveTask(with: nextSource, downloadTaskUpdated: downloadTaskUpdated)
} else {
// No other alternative source. Finish with error.
Expand Down Expand Up @@ -276,27 +288,7 @@ public class KingfisherManager {
}
}
} else {

// Skip alternative sources if the user cancelled it.
guard !error.isTaskCancelled else {
completionHandler?(.failure(error))
return
}
if let nextSource = retrievingContext.popAlternativeSource() {
retrievingContext.appendError(error, to: currentSource)
startNewRetrieveTask(with: nextSource, downloadTaskUpdated: downloadTaskUpdated)
} else {
// No other alternative source. Finish with error.
if retrievingContext.propagationErrors.isEmpty {
completionHandler?(.failure(error))
} else {
retrievingContext.appendError(error, to: currentSource)
let finalError = KingfisherError.imageSettingError(
reason: .alternativeSourcesExhausted(retrievingContext.propagationErrors)
)
completionHandler?(.failure(finalError))
}
}
failCurrentSource(currentSource, with: error)
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions Sources/General/KingfisherOptionsInfo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,9 @@ public enum KingfisherOptionsInfoItem {
/// when pass to an `ImageDownloader` or `ImageCache`.
///
case retryStrategy(RetryStrategy)


case lowDataSource(Source)
}

// Improve performance by parsing the input `KingfisherOptionsInfo` (self) first.
Expand Down Expand Up @@ -291,6 +294,7 @@ public struct KingfisherParsedOptionsInfo {
public var progressiveJPEG: ImageProgressive? = nil
public var alternativeSources: [Source]? = nil
public var retryStrategy: RetryStrategy? = nil
public var lowDataModeSource: Source? = nil

var onDataReceived: [DataReceivingSideEffect]? = nil

Expand Down Expand Up @@ -332,6 +336,7 @@ public struct KingfisherParsedOptionsInfo {
case .progressiveJPEG(let value): progressiveJPEG = value
case .alternativeSources(let sources): alternativeSources = sources
case .retryStrategy(let strategy): retryStrategy = strategy
case .lowDataSource(let source): lowDataModeSource = source
}
}

Expand Down
3 changes: 3 additions & 0 deletions Sources/Networking/ImageDownloader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,9 @@ open class ImageDownloader {
// Creates default request.
var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: downloadTimeout)
request.httpShouldUsePipelining = requestsUsePipelining
if #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) , options.lowDataModeSource != nil {
request.allowsConstrainedNetworkAccess = false
}

if let requestModifier = options.requestModifier {
// Modifies request before sending.
Expand Down

0 comments on commit 21d2c77

Please sign in to comment.