Created
April 13, 2016 11:27
-
-
Save koke/c118d6cb71cb60614db1c7aa90805a91 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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