Add Async image loading

This commit is contained in:
Ivan Vorobei
2019-06-06 22:24:34 +03:00
parent dbabd124fb
commit bcedea412a
914 changed files with 164 additions and 1 deletions

View File

@@ -0,0 +1,27 @@
//
// File 2.swift
//
//
// Created by Callum Trounce on 05/06/2019.
//
import Foundation
import SwiftUI
@available(iOS 13.0, *)
class ImageCache {
private let cache = NSCache<NSURL, CGImage>()
private let queue = DispatchQueue.init(label: "cacheQueue", qos: .userInteractive)
func store(image: CGImage, for url: URL) {
queue.async { [unowned cache] in
cache.setObject(image, forKey: url as NSURL)
}
}
func image(for url: URL) -> CGImage? {
return cache.object(forKey: url as NSURL)
}
}

View File

@@ -0,0 +1,59 @@
//
// File 2.swift
//
//
// Created by Callum Trounce on 05/06/2019.
//
import Foundation
import SwiftUI
import Combine
@available(iOS 13.0, *)
class ImageLoader {
static let shared = ImageLoader()
private let fileManager = FileManager()
private let cache = ImageCache()
private lazy var session = URLSession.init(configuration: .default)
public func load(url: URL, result: @escaping ((CGImage) -> Void)) {
if let cachedImage = cache.image(for: url) {
result(cachedImage)
return
}
let request = session.downloadTask(with: url, completionHandler: { [weak self] (downloadLocation, response, error) in
self?.handleDownload(response: response!, location: downloadLocation!, result: result)
})
request.resume()
}
func handleDownload(response: URLResponse, location: URL, result: @escaping ((CGImage) -> Void)) {
guard let url = response.url else { return }
do {
let directory = try fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent(location.lastPathComponent)
try fileManager.copyItem(at: location, to: directory)
guard
let imageSource = CGImageSourceCreateWithURL(directory as NSURL, nil) else {
fatalError("couldn't create image source")
}
guard let image = CGImageSourceCreateImageAtIndex(imageSource, 0, nil)
else {
fatalError("Couldn't load image \(directory)")
}
cache.store(image: image, for: url)
result(image)
} catch {
fatalError(error.localizedDescription)
}
}
}

View File

@@ -0,0 +1,37 @@
//
// RemoteImage.swift
// Landmarks
//
// Created by Callum Trounce on 06/06/2019.
// Copyright © 2019 Apple. All rights reserved.
//
import Foundation
import SwiftUI
import Combine
@available(iOS 13.0, *)
class RemoteImage: BindableObject {
var didChange = PassthroughSubject<Image?, Never>()
typealias PublisherType = PassthroughSubject<Image?, Never>
var image: Image? = nil {
didSet {
guard oldValue != image else { return }
DispatchQueue.main.async {
self.didChange.send(self.image!)
}
}
}
func load(url: URL) -> Self {
guard image == nil else { return self }
ImageLoader.shared.load(url: url) { [unowned self] (image) in
let final = Image.init(image, scale: 1, label: Text(url.lastPathComponent))
self.image = final
}
return self
}
}

View File

@@ -0,0 +1,30 @@
//
// RemoteImageView.swift
// Landmarks
//
// Created by Callum Trounce on 06/06/2019.
// Copyright © 2019 Apple. All rights reserved.
//
import Foundation
import SwiftUI
@available(iOS 13.0, *)
public struct RemoteImageView: View {
var url: URL
var placeholderImage: Image?
@State
var remoteImage: RemoteImage = RemoteImage()
public var body: some View {
return (remoteImage.load(url: url).image ?? placeholderImage)?.resizable()
}
public init(url: URL, placeholderImage: Image? = nil) {
self.placeholderImage = placeholderImage
self.url = url
}
}

View File

@@ -0,0 +1,5 @@
struct SwURL {
}