Await an async function does not wait until the function finished

I have some code like this:

class AClass {
    func functionA() async throws {
        print("call functionB before")
        try await functionB()
        print("call functionB end")
    }

    func functionB() async throws {
        print("enter functionB")
        try await ClassB.doSomething()
        try await ClassC.doSomething()
        print("leave functionB")
    }
}

but it prints:

call functionB before
call functionB end
enter functionB
leave functionB

the try await does not wait functionB to execute finish

this method was auto-generated from Objective-C code

You'd have to provide some more information; outright like that that should not be possible, so there's something else going on here.

What's your environment, how are those functionA function being called and are you sure it is exactly like that snippet etc?

1 Like

I don't think that's likely, either. There seems to be a Task wrapperred inside the updateUserInfo method. The real snippets are:

   func updateUserInfo() async throws {
        ...
        try await UserService.updateUserInfo()
        try await SyncManager.shared().sync()
    }

   func onboarding() async throws {
        let controller = SignupController.default()
        guard controller.onboardingType == .signup else {
            try await updateUserInfo()
            let vm = MyStatusViewModel.shared
            vm.switchStatus()
            return
        }
       ...
    }

My environment is:

macOS: 15.3.1
Xcode: Version 16.2 (16C5032a)
iOS: 18.2
Swift: 6.0.3

It may be the case that while yeah the methods are async they do create an Unstructured Task anyway which isn’t great but would explain what you’re seeing perhaps?

I mean you say “returns before completes” but just adding prints to this snippet are you actually sure that’s what’s happening, and not some effects of the funcs being from some unstructured task?

Sorry but it’s hard to think of anything else, perhaps if you could provide a reproducer we could dig more into it.

I got it, it's my fault, there is a condition check in the updateUserInfo method to prevent multiple calls, and the updateUserInfo method is called from another method, the code should be like this:

            let vm = MyStatusViewModel.shared
            vm.switchStatus()
            try await updateUserInfo()

Thank you very much for your patience and help.

In order to avoid unnecessary misunderstandings to others, do you have the authority to help me delete this post? @ktoso

It looks like functionA isn't truly waiting for functionB to finish before continuing. Are you sure ClassB.doSomething() and ClassC.doSomething() are properly marked as async and awaited? Also, check if they are running tasks on a detached thread, which might be causing the unexpected behavior. Try using await Task.sleep(...) for debugging to see execution order more clearly.