85 lines
2.4 KiB
Swift
85 lines
2.4 KiB
Swift
//
|
|
// ImageService.swift
|
|
// Example
|
|
//
|
|
// Created by Krunoslav Zaher on 3/28/15.
|
|
// Copyright (c) 2015 Krunoslav Zaher. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import RxSwift
|
|
import RxCocoa
|
|
|
|
protocol ImageService {
|
|
func imageFromURL(URL: NSURL) -> Observable<Result<UIImage>>
|
|
}
|
|
|
|
class DefaultImageService: ImageService {
|
|
typealias Dependencies = (
|
|
URLSession: NSURLSession,
|
|
imageDecodeScheduler: ImmediateScheduler,
|
|
callbackScheduler: ImmediateScheduler
|
|
)
|
|
|
|
var $: Dependencies
|
|
|
|
// 1rst level cache
|
|
let imageCache = NSCache()
|
|
|
|
// 2nd level cache
|
|
let imageDataCache = NSCache()
|
|
|
|
init($: Dependencies) {
|
|
self.$ = $
|
|
|
|
// cost is approx memory usage
|
|
self.imageDataCache.totalCostLimit = 10 * MB
|
|
|
|
self.imageCache.countLimit = 20
|
|
}
|
|
|
|
func decodeImage(imageData: Observable<NSData>) -> Observable<UIImage> {
|
|
return imageData >- observeSingleOn($.imageDecodeScheduler) >- mapOrDie { data in
|
|
let maybeImage = UIImage(data: data)
|
|
|
|
if maybeImage == nil {
|
|
// some error
|
|
return .Error(apiError("Decoding image error"))
|
|
}
|
|
|
|
let image = maybeImage!
|
|
|
|
return success(image)
|
|
} >- observeSingleOn($.callbackScheduler)
|
|
}
|
|
|
|
func imageFromURL(URL: NSURL) -> Observable<Result<UIImage>> {
|
|
let maybeImage = self.imageDataCache.objectForKey(URL) as? UIImage
|
|
|
|
let decodedImage: Observable<UIImage>
|
|
|
|
// best case scenario, it's already decoded an in memory
|
|
if let image = maybeImage {
|
|
decodedImage = returnElement(image)
|
|
}
|
|
else {
|
|
let cachedData = self.imageDataCache.objectForKey(URL) as? NSData
|
|
|
|
// does image data cache contain anything
|
|
if let cachedData = cachedData {
|
|
decodedImage = returnElement(cachedData) >- decodeImage
|
|
}
|
|
else {
|
|
// fetch from network
|
|
decodedImage = $.URLSession.rx_observableDataRequest(NSURLRequest(URL: URL)) >- doOnNext { data in
|
|
self.imageDataCache.setObject(data, forKey: URL)
|
|
} >- decodeImage
|
|
}
|
|
}
|
|
|
|
return decodedImage >- doOnNext { image in
|
|
self.imageCache.setObject(image, forKey: URL)
|
|
} >- catchToResult
|
|
}
|
|
}
|