Skip to content

Instantly share code, notes, and snippets.

@kbazzani
Last active January 31, 2023 07:08
Show Gist options
  • Save kbazzani/b740b3456329d284906b036d0807d023 to your computer and use it in GitHub Desktop.
Save kbazzani/b740b3456329d284906b036d0807d023 to your computer and use it in GitHub Desktop.
ImageCacheActor with NSCache backing store
/*
This code is based on an WWDC demonstration regarding Actors
I combined it with NSCache
*/
import Foundation
import Dispatch
import SwiftUI
class ImageCacheEntry {
enum State {
case inProgress( Task<(Data,URLResponse),Error> )
case ready( Data )
}
var state:State? = nil
var url:URL? = nil // just for easy debug
init( state:State, url:URL )
{
self.state = state
self.url = url
}
}
actor RemoteImageCache
{
private var cache:NSCache<NSURL,ImageCacheEntry> = NSCache<NSURL,ImageCacheEntry>()
private let delegate:Delegate = Delegate()
init( limit:Int )
{
cache.countLimit = limit
cache.delegate = delegate
}
func image( from url:NSURL ) async throws -> Data?
{
if let cached = self.cache.object( forKey:url )?.state
{
switch cached
{
case .ready( let data ):
return data
case .inProgress( let task):
let (data,_) = try await task.value
return data
}
}
let task = Task
{
DispatchQueue.global(qos:.default).sync {
print("InProgress: \(url)")
}
return try await URLSession.shared.data(from: url as URL)
}
self.cache.setObject( ImageCacheEntry(state: .inProgress( task ), url:url as URL), forKey: url )
do
{
let (data,_) = try await task.value
DispatchQueue.global(qos:.default).sync {
print("Ready: \(url)")
}
self.cache.object(forKey: url)?.state = .ready(data)
return data
}
catch
{
self.cache.removeObject(forKey: url)
throw error
}
}
}
final class Delegate : NSObject, NSCacheDelegate
{
internal func cache( _ acache:NSCache<AnyObject, AnyObject>, willEvictObject object:Any)
{
DispatchQueue.global(qos:.default).sync {
print("Evicted: \((object as! ImageCacheEntry).url)")
}
}
}
//let cache = ObjectCache<NSURL,RemoteFile>( limit:10 )
let cache = RemoteImageCache( limit: 10 )
let urlSession = URLSession.shared
await withTaskGroup(of: (Int).self ) {
group in
for p in 1...30 {
if let url = NSURL(string: "https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/\(p%10).png")
{
group.addTask
{
do
{
DispatchQueue.global(qos:.default).sync {
print("+> Await Image \(p): \(url)")
}
let image = try await cache.image(from: url)
DispatchQueue.global(qos:.default).sync {
print("=> Received Image \(p): \(image) from \(url)")
}
}
catch
{
print("Error: \(error)")
}
return p
}
}
}
for await p in group
{
// print("\(p) complete.")
}
}
/*
Sample Output:
-- Just enough (10) cache entry lmit to store the 10 images.
+> Await Image 1: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
+> Await Image 2: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
+> Await Image 3: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
+> Await Image 5: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
+> Await Image 6: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
+> Await Image 8: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
+> Await Image 4: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png
+> Await Image 9: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
+> Await Image 7: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
+> Await Image 10: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
+> Await Image 12: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
+> Await Image 13: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
+> Await Image 11: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
+> Await Image 15: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
+> Await Image 17: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
+> Await Image 14: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png
+> Await Image 21: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
+> Await Image 16: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
+> Await Image 24: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png
+> Await Image 20: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
+> Await Image 18: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
+> Await Image 19: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
+> Await Image 23: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
+> Await Image 22: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
+> Await Image 25: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
+> Await Image 26: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
+> Await Image 27: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
+> Await Image 28: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
+> Await Image 29: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
+> Await Image 30: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
=> Received Image 22: Optional(870 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
=> Received Image 12: Optional(870 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
=> Received Image 2: Optional(870 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
=> Received Image 28: Optional(946 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
=> Received Image 21: Optional(543 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
=> Received Image 11: Optional(543 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
=> Received Image 18: Optional(946 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
=> Received Image 23: Optional(1531 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
=> Received Image 8: Optional(946 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
=> Received Image 3: Optional(1531 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
=> Received Image 13: Optional(1531 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
=> Received Image 1: Optional(543 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
=> Received Image 14: Optional(583 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png
=> Received Image 24: Optional(583 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png
=> Received Image 4: Optional(583 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png
=> Received Image 26: Optional(1330 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
=> Received Image 16: Optional(1330 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
=> Received Image 6: Optional(1330 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
=> Received Image 30: Optional(340 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
=> Received Image 10: Optional(340 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
=> Received Image 20: Optional(340 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
=> Received Image 27: Optional(575 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
=> Received Image 7: Optional(575 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
=> Received Image 17: Optional(575 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
=> Received Image 25: Optional(832 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
=> Received Image 29: Optional(1170 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
=> Received Image 15: Optional(832 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
=> Received Image 19: Optional(1170 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
=> Received Image 5: Optional(832 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
=> Received Image 9: Optional(1170 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
-- Once more with a limit of (5) for 10 images to show the eviction
+> Await Image 1: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
+> Await Image 2: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
+> Await Image 3: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
+> Await Image 5: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
+> Await Image 6: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
+> Await Image 7: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
+> Await Image 8: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
+> Await Image 10: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
+> Await Image 9: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
+> Await Image 11: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
+> Await Image 13: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
+> Await Image 4: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png
+> Await Image 14: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png
+> Await Image 12: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
+> Await Image 15: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
+> Await Image 16: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
+> Await Image 17: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
+> Await Image 18: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
+> Await Image 19: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
+> Await Image 20: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
+> Await Image 21: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
+> Await Image 22: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
+> Await Image 23: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
+> Await Image 24: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png
+> Await Image 25: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
+> Await Image 26: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
+> Await Image 27: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
+> Await Image 28: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
+> Await Image 29: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
+> Await Image 30: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png)
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png)
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png)
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png)
InProgress: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
Evicted: Optional(https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png)
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png
=> Received Image 4: Optional(583 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
=> Received Image 14: Optional(583 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
=> Received Image 1: Optional(543 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
=> Received Image 21: Optional(543 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
=> Received Image 18: Optional(946 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
=> Received Image 20: Optional(340 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
=> Received Image 8: Optional(946 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
=> Received Image 2: Optional(870 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
=> Received Image 6: Optional(1330 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
=> Received Image 16: Optional(1330 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
=> Received Image 17: Optional(575 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
=> Received Image 12: Optional(870 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
=> Received Image 13: Optional(1531 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
=> Received Image 15: Optional(832 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
=> Received Image 3: Optional(1531 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
=> Received Image 11: Optional(543 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
=> Received Image 9: Optional(1170 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
=> Received Image 10: Optional(340 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
=> Received Image 7: Optional(575 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
=> Received Image 5: Optional(832 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
=> Received Image 22: Optional(870 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/2.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
=> Received Image 23: Optional(1531 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/3.png
=> Received Image 19: Optional(1170 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
=> Received Image 26: Optional(1330 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/6.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
=> Received Image 27: Optional(575 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/7.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
=> Received Image 28: Optional(946 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/8.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
=> Received Image 25: Optional(832 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/5.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png
=> Received Image 30: Optional(340 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/0.png
Ready: https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
=> Received Image 24: Optional(583 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/4.png
=> Received Image 29: Optional(1170 bytes) from https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/9.png
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment