import Foundation | |
import RxSwift | |
func requestForImageUrl(url: NSURL) -> NSURLRequest { | |
let request = NSMutableURLRequest(URL: url) | |
request.HTTPShouldHandleCookies = false | |
request.addValue("image/*", forHTTPHeaderField: "Accept") | |
return request | |
} | |
func imageFromResponseData(data: NSData) -> UIImage? { | |
let scale = UIScreen.mainScreen().scale | |
return UIImage(data: data, scale: scale) | |
} | |
func fetchData(request: NSURLRequest, completion: NSData -> Void) -> NSURLSessionTask { | |
let session = NSURLSession.sharedSession() | |
let task = session.dataTaskWithRequest(request) { data, response, error in | |
guard let data = data else { | |
return | |
} | |
completion(data) | |
} | |
task.resume() | |
return task | |
} | |
func rx_fetchData(request: NSURLRequest) -> Observable<NSData> { | |
return Observable.create({ observer in | |
let task = fetchData(request, completion: { data in | |
observer.onNext(data) | |
observer.onCompleted() | |
}) | |
return AnonymousDisposable { | |
task.cancel() | |
} | |
}) | |
} | |
func fetchData(request: NSURLRequest) -> (NSData -> Void) -> NSURLSessionTask { | |
return { completion in | |
fetchData(request, completion: completion) | |
} | |
} | |
func photonize(forSize size: CGSize) -> NSURL -> NSURL { | |
return { url in | |
return photonize(url: url, forSize: size) | |
} | |
} | |
func photonize(url url: NSURL, forSize size: CGSize) -> NSURL { | |
// Naive approach, use PhotonImageURLHelper instead | |
let urlString = (url.host ?? "") + "/" + (url.path ?? "") | |
let photonUrl = String(format: "https://i0.wp.com/%@?w=%i&h=%i", urlString, size.width, size.height) | |
return NSURL(string: photonUrl)! | |
} | |
func applyImage(image: UIImage, to imageView: UIImageView) { | |
imageView.image = image | |
} | |
func applyImage(to imageView: UIImageView) -> UIImage -> Void { | |
return { image in | |
applyImage(image, to: imageView) | |
} | |
} | |
func applyImageInMainQueue(to imageView: UIImageView) -> UIImage -> Void { | |
return { image in | |
dispatch_async(dispatch_get_main_queue(), { | |
applyImage(image, to: imageView) | |
}) | |
} | |
} | |
func unwrapOptional<T, E: ErrorType>(error: E) -> T? -> Observable<T> { | |
return { value in | |
if let value = value { | |
return Observable.just(value) | |
} else { | |
return Observable.error(error) | |
} | |
} | |
} | |
func unwrapOptional<T, U>(value: T?, then f: T -> U) { | |
guard let value = value else { | |
return | |
} | |
f(value) | |
} | |
func unwrapOptional<T, U>(value: T?) -> (T -> U) -> Void { | |
return { f in | |
guard let value = value else { | |
return | |
} | |
f(value) | |
} | |
} | |
func resizeImage(to size: CGSize) -> UIImage -> UIImage { | |
return { image in | |
return image.resizedImage(size, interpolationQuality: .High) | |
} | |
} | |
enum ImageDownloadError: ErrorType { | |
case NilImage | |
} | |
infix operator • { associativity right precedence 140 } | |
func • <T, U, V>(g: U -> V, f: T -> U) -> T -> V { | |
return { t in | |
return g(f(t)) | |
} | |
} | |
extension UIImageView { | |
func old_setResizedImage(withURL url: NSURL) { | |
let photonUrl = photonize(url: url, forSize: frame.size) | |
let request = NSMutableURLRequest(URL: photonUrl) | |
request.HTTPShouldHandleCookies = false | |
request.addValue("image/*", forHTTPHeaderField: "Accept") | |
let session = NSURLSession.sharedSession() | |
let task = session.dataTaskWithRequest(request) { [weak self] data, response, error in | |
let scale = UIScreen.mainScreen().scale | |
guard let data = data, | |
let image = UIImage(data: data, scale: scale) else { | |
return | |
} | |
self?.image = image | |
} | |
task.resume() | |
} | |
func traditional_setResizedImage(withURL url: NSURL) { | |
let resizedURL = photonize(url: url, forSize: frame.size) | |
let request = requestForImageUrl(resizedURL) | |
fetchData(request) { data in | |
guard let image = imageFromResponseData(data) else { | |
return | |
} | |
dispatch_async(dispatch_get_main_queue(), { | |
applyImage(image, to: self) | |
}) | |
} | |
} | |
func functional_setResizedImage(withURL url: NSURL) { | |
fetchData( | |
requestForImageUrl( | |
photonize(url: url, forSize: frame.size) | |
) | |
) { data in | |
unwrapOptional( | |
imageFromResponseData(data), | |
then: applyImageInMainQueue(to: self) | |
) | |
} | |
} | |
func composed_setResizedImage(withURL url: NSURL) { | |
let fetchResizedUrl = fetchData • requestForImageUrl • photonize(forSize: frame.size) | |
fetchResizedUrl(url)({ data in | |
unwrapOptional( | |
imageFromResponseData(data), | |
then: applyImageInMainQueue(to: self) | |
) | |
}) | |
} | |
func concurrent_setResizedImage(withURL url: NSURL) { | |
let backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) | |
let mainQueue = dispatch_get_main_queue() | |
dispatch_async(backgroundQueue) { [frame] in | |
let resizedURL = photonize(url: url, forSize: frame.size) | |
let request = requestForImageUrl(resizedURL) | |
fetchData(request) { data in | |
dispatch_async(backgroundQueue, { | |
guard let image = imageFromResponseData(data) else { | |
return | |
} | |
dispatch_async(mainQueue, { | |
applyImage(image, to: self) | |
}) | |
}) | |
} | |
} | |
} | |
func rx_setResizedImage(withURL url: NSURL) -> Disposable { | |
let backgroundScheduler = ConcurrentDispatchQueueScheduler(globalConcurrentQueueQOS: .Default) | |
let mainScheduler = MainScheduler.instance | |
return Observable | |
.just(url) | |
.observeOn(backgroundScheduler) | |
.map(photonize(forSize: frame.size)) | |
.map(requestForImageUrl) | |
.flatMap(rx_fetchData) | |
.observeOn(backgroundScheduler) | |
.map(imageFromResponseData) | |
.flatMap(unwrapOptional(ImageDownloadError.NilImage)) | |
.observeOn(mainScheduler) | |
.subscribeNext(applyImage(to: self)) | |
} | |
func rx2_setResizedImage(withURL url: NSURL) -> Disposable { | |
let backgroundScheduler = ConcurrentDispatchQueueScheduler(globalConcurrentQueueQOS: .Default) | |
let mainScheduler = MainScheduler.instance | |
let request = Observable | |
.just(url) | |
.observeOn(backgroundScheduler) | |
.map(photonize(forSize: frame.size)) | |
.map(requestForImageUrl) | |
let image = request | |
.flatMap(rx_fetchData) | |
.observeOn(backgroundScheduler) | |
.map(imageFromResponseData) | |
.flatMap(unwrapOptional(ImageDownloadError.NilImage)) | |
return image | |
.observeOn(mainScheduler) | |
.subscribeNext(applyImage(to: self)) | |
} | |
} | |
func identity<T>(value: T) -> T { | |
return value | |
} | |
extension UIImageView { | |
func composable_setResizedImage(processUrl proccessUrl: (NSURL -> NSURL) = identity, processImage: (UIImage -> UIImage) = identity) -> NSURL -> Void { | |
return { url in | |
let processedURL = proccessUrl(url) | |
let request = requestForImageUrl(processedURL) | |
fetchData(request) { data in | |
guard let image = imageFromResponseData(data) else { | |
return | |
} | |
let processedImage = processImage(image) | |
dispatch_async(dispatch_get_main_queue(), { | |
applyImage(processedImage, to: self) | |
}) | |
} | |
} | |
} | |
func downloadAndResizeLocally(url: NSURL) { | |
let download = composable_setResizedImage(processImage: resizeImage(to: frame.size)) | |
download(url) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment