mirror of
https://github.com/ivanvorobei/SwiftUI.git
synced 2026-01-15 21:53:29 +01:00
Add Async image loading
This commit is contained in:
27
Examples/Async image loading/RemoteImage/ImageCache.swift
Executable file
27
Examples/Async image loading/RemoteImage/ImageCache.swift
Executable 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)
|
||||
}
|
||||
}
|
||||
59
Examples/Async image loading/RemoteImage/ImageLoader.swift
Executable file
59
Examples/Async image loading/RemoteImage/ImageLoader.swift
Executable 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Examples/Async image loading/RemoteImage/RemoteImage.swift
Executable file
37
Examples/Async image loading/RemoteImage/RemoteImage.swift
Executable 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
|
||||
}
|
||||
}
|
||||
30
Examples/Async image loading/RemoteImage/RemoteImageView.swift
Executable file
30
Examples/Async image loading/RemoteImage/RemoteImageView.swift
Executable 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
|
||||
}
|
||||
}
|
||||
5
Examples/Async image loading/SwURL.swift
Executable file
5
Examples/Async image loading/SwURL.swift
Executable file
@@ -0,0 +1,5 @@
|
||||
struct SwURL {
|
||||
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user