Option 1:
class ImageDownloadOperation: Operation {
let url: URL
var image: UIImage?
var completion: ((UIImage?) -> Void)?
init(url: URL, completion: ((UIImage?) -> Void)? = nil) {
self.url = url
self.completion = completion
}
override func main() {
guard !isCancelled else { return }
// Download image data
Task {
do {
let imageData = try await URLSession.shared.data(from: url)
if let downloadedImage = UIImage(data: imageData.0) {
// Resize image to reduce memory usage
let scaledImage = resizeImage(downloadedImage, targetSize: CGSize(width: 100, height: 100))
image = scaledImage
}
} catch {
print("Error downloading image: \(error)")
}
}
// Call completion handler on the main thread
DispatchQueue.main.async {
self.completion?(self.image)
}
}
private func resizeImage(_ image: UIImage, targetSize: CGSize) -> UIImage {
let renderer = UIGraphicsImageRenderer(size: targetSize)
return renderer.image { _ in
image.draw(in: CGRect(origin: .zero, size: targetSize))
}
}
}
class ImageTableViewCell: UITableViewCell {
@IBOutlet weak var customImageView: UIImageView!
override func prepareForReuse() {
super.prepareForReuse()
customImageView.image = nil
}
}
class ImageTableViewController: UITableViewController {
let imageUrls = [
URL(string: "https://example.com/image1.jpg")!,
URL(string: "https://example.com/image2.jpg")!,
// Add more image URLs as needed
]
var images = [UIImage?]()
override func viewDidLoad() {
super.viewDidLoad()
downloadImages()
}
func downloadImages() {
Task {
let downloadOperations = imageUrls.map { url in
ImageDownloadOperation(url: url) { image in
self.updateUI(with: image)
}
}
for operation in downloadOperations {
operation.start()
}
}
}
func updateUI(with image: UIImage?) {
DispatchQueue.main.async {
self.images.append(image)
self.tableView.reloadData()
}
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return images.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ImageCell", for: indexPath) as! ImageTableViewCell
if let image = images[indexPath.row] {
cell.customImageView.image = image
} else {
// Placeholder or loading indicator
cell.customImageView.image = UIImage(named: "placeholder")
}
return cell
}
}
OPTION 2:
This we can do using OPERATIONQUEUE.
Here you can PAUSE, RESUME and CANCEL downloading.
import UIKit
class ImageDownloadOperation1: Operation {
let url: URL
var image: UIImage?
private var task: URLSessionDataTask?
private var isExecutingInternal = false
private var isFinishedInternal = false
private var isPausedInternal = false
private var isCancelledInternal = false
init(url: URL) {
self.url = url
super.init()
}
override var isExecuting: Bool {
return isExecutingInternal
}
override var isFinished: Bool {
return isFinishedInternal
}
override var isAsynchronous: Bool {
return true
}
override func start() {
guard !isCancelled else { return }
guard !isPausedInternal else { return }
guard !isExecutingInternal else { return }
isExecutingInternal = true
task = URLSession.shared.dataTask(with: url) { [weak self] (data, response, error) in
defer {
self?.isExecutingInternal = false
self?.isFinishedInternal = true
}
guard let data = data, let image = UIImage(data: data), error == nil else { return }
self?.image = image
}
task?.resume()
}
override func cancel() {
super.cancel()
task?.cancel()
isCancelledInternal = true
}
func pause() {
isPausedInternal = true
task?.suspend()
}
func resume() {
isPausedInternal = false
task?.resume()
}
}
class UsingOperationQueueClass: UIViewController {
// Usage
let operationQueue = OperationQueue()
let imageUrls = [
URL(string: "https://example.com/image1.jpg")!,
URL(string: "https://example.com/image2.jpg")!,
// Add more image URLs as needed
]
var images = [UIImage?]()
override func viewDidLoad() {
super.viewDidLoad()
// Create ImageDownloadOperation instances for each image URL
// Here you can modify the code by adding completion bloack and load image.
// Same like Option 1 code.
let operations = imageUrls.map { ImageDownloadOperation1(url: $0) }
// Add operations to the queue
operationQueue.addOperations(operations, waitUntilFinished: false)
// Pause the 2nd operation
operations[1].pause()
// Resume other operations
operations.filter { $0 !== operations[1] }.forEach { $0.resume() }
// Resume the 2nd operation
operations[1].resume()
}
}