HomeiOS DevelopmentSwift async/await what it the substitute of DispatchQueue.major.async

Swift async/await what it the substitute of DispatchQueue.major.async


You requested:

Can I nonetheless use DispatchQueue.major.async?

If you’re in an async methodology and wish to dispatch one thing to the principle queue, probably the most literal equal could be:

MainActor.run { ... }

However it’s extra prudent to easily mark the tactic (or its class) with @MainActor. Not solely will this be certain that it runs it on the principle thread, however you get compile-time warnings in the event you try to name it from the incorrect actor.

So, in case your view mannequin is marked with @MainActor, the guide working of the duty on the MainActor turns into pointless. That is very true when coping with printed properties of an noticed object.

For instance, think about:

@MainActor
class ViewModel: ObservableObject {
    @Printed var values: [Int] = []

    func fetchData() async {
        let foo = await ...
        values = foo.values
    }
}

After which

struct ContentView: View {
    @ObservedObject var viewModel = ViewModel()

    var physique: some View {
        Record {
            ...
        }
        .refreshable {
            await viewModel.fetchData()
        }

    }
}

(Observe, I made fetchData an async methodology and await it inside refreshable in order that the spinner precisely displays when the async course of is working.)

See WWDC 2021 video Swift concurrency: Replace a pattern app. That’s admittedly illustrating the transition of a UIKit app, however contains examples of @MainActor and MainActor.run.


Observe, whereas @MainActor, largely eliminates the necessity for MainActor.run { … }, there are nonetheless some situations the place you would possibly use this run sample. Particularly, if you’re on another actor and wish to run, for instance, three separate @MainActor features in succession on the principle thread, you possibly can wrap the collection of them inside a single MainActor.run { … } block, thereby working all three with a single dispatch to the principle actor, moderately than three separate calls.


Above, I centered on the salient parts, however right here is my full MCVE:

struct ContentView: View {
    @ObservedObject var viewModel = ViewModel()

    var physique: some View {
        Record {
            ForEach(viewModel.values, id: .self) { worth in
                Textual content("(worth)")
            }
        }
        .refreshable {
            await viewModel.fetchData()
        }

    }
}

struct Foo: Decodable{
    let json: [Int]
}

@MainActor
class ViewModel: ObservableObject {
    @Printed var values: [Int] = []

    func fetchData() async {
        do {
            let foo = attempt await object(Foo.self, for: request)
            values = foo.json
        } catch {
            print(error)
        }
    }

    func object<T: Decodable>(_ kind: T.Sort, for request: URLRequest) async throws -> T {
        let (knowledge, response) = attempt await URLSession.shared.knowledge(for: request)

        guard let response = response as? HTTPURLResponse else {
            throw URLError(.badServerResponse)
        }

        guard 200 ... 299 ~= response.statusCode else {
            throw ApiError.failure(response.statusCode, knowledge)
        }

        return attempt JSONDecoder().decode(T.self, from: knowledge)
    }

    var request: URLRequest = {
        let url = URL(string: "https://httpbin.org/something")!
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.httpBody = "[1,2,3,4,5]".knowledge(utilizing: .utf8)
        request.addValue("software/json", forHTTPHeaderField: "Content material-Sort")
        request.addValue("software/json", forHTTPHeaderField: "Settle for")

        return request
    }()
}

enum ApiError: Error {
    case failure(Int, Information)
}

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments