Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

How to use SharedReaderKey with AsyncStream? #142

Unanswered
zunda-pixel asked this question in Q&A
Discussion options

Second @SharedReader doesn't work in ContentView.
Storage has AsyncStream Task every projectUrl.
projectUrl provides Stream RemoteValues like Firebase RemoteConfig.
Can Sharing resolve this pattern?

AsyncStream(API project) provides realtime values([String: String]).

Project Values
project1 ["key1": "value1", "key2": "value2"]
project2 ["key1": "value11", "key2": "value22"]
Screenshot 2025年03月30日 at 13 03 26
struct RemoteValue: SharedReaderKey {
 struct IDStore: Hashable {
 var key: String
 var projectUrl: URL
 }
 
 var id: IDStore { IDStore(key: key, projectUrl: projectUrl) }
 
 var key: String
 var projectUrl: URL
 var storage: Storage
 init(key: String, projectUrl: URL) {
 @Dependency(\.defaultStorage) var storage
 self.storage = storage
 self.key = key
 self.projectUrl = projectUrl
 }
 
 static func streamValues(url: URL) -> AsyncStream<[String: String]> {
 return AsyncStream { continuation in
 Task {
 for i in 1..<100000 {
 try? await Task.sleep(for: .seconds(1))
 let fetchData: [String: String] = (0..<5).reduce(
 into: [String: String](),
 { 0ドル["\(1ドル)"] = "| \(url) | value: \(1ドル + i) |"}
 )
 continuation.yield(fetchData)
 }
 }
 }
 }
 
 public typealias Value = String?
 public func load(context: LoadContext<Value>, continuation: LoadContinuation<Value>) {
 continuation.resumeReturningInitialValue()
 }
 public func subscribe(
 context: Sharing.LoadContext<Value>,
 subscriber: Sharing.SharedSubscriber<Value>
 ) -> Sharing.SharedSubscription {
 storage.tasks.withLock { tasks in
 guard tasks[projectUrl] == nil || tasks[projectUrl]?.isCancelled == true else {
 return
 }
 tasks[projectUrl] = Task {
 for await pairs in Self.streamValues(url: projectUrl) {
 subscriber.yield(pairs[key])
 }
 }
 }
 return SharedSubscription {
 storage.tasks.withLock { tasks in
 tasks[projectUrl]?.cancel()
 }
 }
 }
}
 
final class Storage: Sendable {
 let tasks: Mutex<[URL: Task<Void, Never>]> = .init([:])
}
enum DefaultStorageKey: DependencyKey {
 static var liveValue: Storage { Storage() }
}
 
struct ContentView: View {
 @SharedReader(.remoteValue("1", projectUrl: .project1)) var value1to1
 @SharedReader(.remoteValue("2", projectUrl: .project1)) var value1to2
 @SharedReader(.remoteValue("1", projectUrl: .project2)) var value2to1
 @SharedReader(.remoteValue("2", projectUrl: .project2)) var value2to2
 
 var body: some View {
 List {
 Text(value1to1 ?? "value1to1 not found")
 Text(value1to2 ?? "value1to2 not found")
 Text(value2to1 ?? "value2to1 not found")
 Text(value2to2 ?? "value2to2 not found")
 }
 }
}
extension URL {
 static let project1 = URL(string: "https://api.server.com/stream-remote/project1")!
 static let project2 = URL(string: "https://api.server.com/stream-remote/project2")!
}
extension SharedReaderKey {
 static func remoteValue(_ key: String, projectUrl: URL) -> Self
 where Self == RemoteValue {
 RemoteValue(key: key, projectUrl: projectUrl)
 }
}
extension DependencyValues {
 var defaultStorage: Storage {
 get { self[DefaultStorageKey.self] }
 set { self[DefaultStorageKey.self] = newValue }
 }
}
#Preview {
 ContentView()
 .frame(maxWidth: 500, maxHeight: 500)
}
You must be logged in to vote

Replies: 0 comments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
Q&A
Labels
None yet
1 participant

AltStyle によって変換されたページ (->オリジナル) /