Last active
January 31, 2023 07:08
-
-
Save kbazzani/b740b3456329d284906b036d0807d023 to your computer and use it in GitHub Desktop.
ImageCacheActor with NSCache backing store
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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