@@ -23,7 +23,7 @@ class CachedAssetSchemeHandler: NSObject, WKURLSchemeHandler {
2323 return nil
2424 }
2525
26- let worker : Worker
26+ private let worker : Worker
2727
2828 init ( library: EditorAssetsLibrary ) {
2929 self . worker = . init( library: library)
@@ -40,69 +40,102 @@ class CachedAssetSchemeHandler: NSObject, WKURLSchemeHandler {
4040 await worker. stop ( urlSchemeTask)
4141 }
4242 }
43+ }
4344
44- actor Worker {
45- struct TaskInfo {
46- var webViewTask : WKURLSchemeTask
47- var fetchAssetTask : Task < Void , Never >
45+ private actor Worker {
46+ struct TaskInfo {
47+ var webViewTask : WKURLSchemeTask
48+ var fetchAssetTask : Task < Void , Never >
4849
49- func cancel( ) {
50- fetchAssetTask. cancel ( )
51- }
52- }
50+ func cancel( ) {
51+ fetchAssetTask. cancel ( )
52+ }
53+ }
54+
55+ let library : EditorAssetsLibrary
56+ var tasks : [ ObjectIdentifier : TaskInfo ] = [ : ]
57+
58+ init ( library: EditorAssetsLibrary ) {
59+ self . library = library
60+ }
5361
54- let library : EditorAssetsLibrary
55- var tasks : [ ObjectIdentifier : TaskInfo ] = [ : ]
62+ deinit {
63+ for (_, task) in tasks {
64+ task. cancel ( )
65+ }
66+ }
5667
57- init ( library: EditorAssetsLibrary ) {
58- self . library = library
68+ func start( _ task: WKURLSchemeTask ) {
69+ guard let url = task. request. url, let httpURL = CachedAssetSchemeHandler . originalHTTPURL ( from: url) else {
70+ task. didFailWithError ( URLError ( . badURL) )
71+ return
5972 }
6073
61- deinit {
62- for (_, task) in tasks {
63- task. cancel ( )
74+ let taskKey = ObjectIdentifier ( task)
75+
76+ let fetchAssetTask = Task { [ library, weak self] in
77+ do {
78+ let ( response, content) = try await library. cacheAsset ( from: httpURL, webViewURL: url)
79+
80+ await self ? . tasks [ taskKey] ? . webViewTask. didReceive ( response)
81+ await self ? . tasks [ taskKey] ? . webViewTask. didReceive ( content)
82+
83+ await self ? . finish ( with: nil , taskKey: taskKey)
84+ } catch {
85+ await self ? . finish ( with: error, taskKey: taskKey)
6486 }
6587 }
88+ tasks [ taskKey] = . init( webViewTask: task, fetchAssetTask: fetchAssetTask)
89+ }
6690
67- func start( _ task: WKURLSchemeTask ) {
68- guard let url = task. request. url, let httpURL = CachedAssetSchemeHandler . originalHTTPURL ( from: url) else {
69- task. didFailWithError ( URLError ( . badURL) )
70- return
71- }
91+ func stop( _ task: WKURLSchemeTask ) {
92+ let taskKey = ObjectIdentifier ( task)
93+ tasks [ taskKey] ? . cancel ( )
94+ tasks [ taskKey] = nil
95+ }
96+
97+ private func finish( with error: Error ? , taskKey: ObjectIdentifier ) {
98+ guard let task = tasks [ taskKey] else { return }
7299
73- let taskKey = ObjectIdentifier ( task)
100+ if let error {
101+ task. webViewTask. didFailWithError ( error)
102+ } else {
103+ task. webViewTask. didFinish ( )
104+ }
105+ tasks [ taskKey] = nil
106+ }
107+ }
108+
109+ @available ( iOS 26 . 0 , * )
110+ extension CachedAssetSchemeHandler : URLSchemeHandler {
111+ func reply( for request: URLRequest ) -> AsyncThrowingStream < URLSchemeTaskResult , Error > {
112+ AsyncThrowingStream { [ library = worker. library] continuation in
113+ let task = Task {
114+ guard let url = request. url,
115+ let httpURL = CachedAssetSchemeHandler . originalHTTPURL ( from: url) else {
116+ continuation. yield ( with: . failure( URLError ( . badURL) ) )
117+ continuation. finish ( )
118+ return
119+ }
74120
75- let fetchAssetTask = Task { [ library, weak self] in
76121 do {
77122 let ( response, content) = try await library. cacheAsset ( from: httpURL, webViewURL: url)
123+ try Task . checkCancellation ( )
78124
79- await self ? . tasks [ taskKey] ? . webViewTask. didReceive ( response)
80- await self ? . tasks [ taskKey] ? . webViewTask. didReceive ( content)
81-
82- await self ? . finish ( with: nil , taskKey: taskKey)
125+ continuation. yield ( with: . success( . response( response) ) )
126+ continuation. yield ( with: . success( . data( content) ) )
83127 } catch {
84- await self ? . finish ( with: error, taskKey: taskKey)
128+ try Task . checkCancellation ( )
129+ continuation. yield ( with: . failure( error) )
85130 }
131+ continuation. finish ( )
86132 }
87- tasks [ taskKey] = . init( webViewTask: task, fetchAssetTask: fetchAssetTask)
88- }
89-
90- func stop( _ task: WKURLSchemeTask ) {
91- let taskKey = ObjectIdentifier ( task)
92- tasks [ taskKey] ? . cancel ( )
93- tasks [ taskKey] = nil
94- }
95133
96- private func finish( with error: Error ? , taskKey: ObjectIdentifier ) {
97- guard let task = tasks [ taskKey] else { return }
98-
99- if let error {
100- task. webViewTask. didFailWithError ( error)
101- } else {
102- task. webViewTask. didFinish ( )
134+ continuation. onTermination = {
135+ if case . cancelled = $0 {
136+ task. cancel ( )
137+ }
103138 }
104- tasks [ taskKey] = nil
105139 }
106140 }
107141}
108-
0 commit comments