15.4 C
New York
Wednesday, September 11, 2024

ios – Throttle Outbound Community Requests in Swift


Inside my SwiftUI views I set off community requests to fetch information. There is not one API that returns all the information I want so I’ve to make a number of requests.

I wish to keep away from hitting the speed restrict of the API which is fairly low, 1 RPS.

I at the moment have:

struct SomeView: View {
  let id: String

  non-public func loadData() async throws {
    do {
      async let result1: () = api.loadUserComments(id)
      async let result2: () = api.loadUserData(id)
      async let result3: () = api.loadUserPosts(id)
      (_, _, _) = attempt await (result1, result2, result3)
    } catch {
      print("deal with error (error)")
    }
  }

  var physique: some View {
    Textual content("foo")
    // TODO: learn from swift information and render information
  }
  .process(id: id) {
     await loadData()
  }
}

which is not nice as a result of it does not deal with outbound fee limits and if a request fails then all of them are cancelled.

I attempted utilizing AsyncChannel from AsyncAlgorithms:

@Observable
class SharedViewModel {
  non-public let channel = AsyncChannel<() async throws -> Void>()
  non-public let taskInterval: Length = .seconds(1)
  
  func monitorChannel() async throws {
    for await block in channel {
      let begin = ContinuousClock.now
      attempt await block()
      let elapsed = ContinuousClock.now - begin
      let remaining = taskInterval - elapsed
      if remaining > .zero {
        attempt await Job.sleep(for: remaining)
      }
    }
  }
  
  func performOperation(identify: String) async throws {
      let id = UUID()
      print("(id): (identify): despatched to channel...")
      await channel.ship {
        print("(id): (identify): beginning...")
        // TODO: precise API calls
        attempt await Job.sleep(for: .seconds(20))
        print("(id): (identify): carried out!")
      }
    }
}


@major
struct myApp: App {
  @State non-public var sharedViewModel = SharedViewModel()

  var physique: some Scene {
    WindowGroup {
      ContentView()
    }
    .atmosphere(sharedViewModel)
  }
}

after which within the view I’ve:

struct SomeView: View {
  let id: String
  @Setting(SharedViewModel.self) non-public var sharedViewModel


  non-public func loadData() async throws {
    do {
      async let result1: () = sharedViewModel.performOperation(identify: "profile feedback")
      async let result2: () = sharedViewModel.performOperation(identify: "profile person information")
      async let result3: () = sharedViewModel.performOperation(identify: "tales")
      (_, _, _) = attempt await (result1, result2, result3)
    } catch {
      print("deal with error (error)")
    }
  }

  var physique: some View {
    Textual content("foo")
    // TODO: learn from swift information and render information
  }
  .process(id: id) {
     await loadData()
  }
  .process {
    do {
      attempt await sharedViewModel.monitorChannel()
    } catch {
      print("error monitoring channel (error)")
    }
  }
}

however this is not actually what I would like as a result of the duties get cancelled as I navigate between views that use sharedViewModel.

I am having hassle constructing a queue that’s shared throughout the app and in addition cancels the view particular duties when it navigates (I do not need them holding up the queue once they’re now not wanted).

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Latest Articles