Skip to content

Instantly share code, notes, and snippets.

@koke
Created April 13, 2016 11:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save koke/c118d6cb71cb60614db1c7aa90805a91 to your computer and use it in GitHub Desktop.
Save koke/c118d6cb71cb60614db1c7aa90805a91 to your computer and use it in GitHub Desktop.
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