I have an asynchronous function that returns the result of an App Store query (was the query successful or not displayed in an alert). I am having trouble getting the result out of the task--Cannot find 'result' in scope. If I move let gotTitle = result ? "Success" : "The Request Failed" to within the task I see the warning "Initialization of immutable value 'gotTitle' was never used".
The Apple documentation on Task talks about using value or result to get data out of a task, but it isn't clear on how to do that. I have also stepped through the code with the debugger. It is showing correctly result = true and gotTitle = Success within the task.
struct TestAlert: View {
var gotTitle: String = ""
@State private var presentAlert = false
var body: some View {
VStack {
Button(action: {
Task {
let result = await restore()
print (result)
}
let gotTitle = result ? "Success" : "The Request Failed"
print(gotTitle)
}) {
Text("Restore Purchase")
}
}
.alert(gotTitle, isPresented: $presentAlert, actions: {
})
}
func restore() async -> Bool {
return ((try? await AppStore.sync()) != nil)
}
}
You said:
Yes, as presented in your question,
result
is a local variable inside the task, so you can't refer to it outside of theTask
(unless you save it, or the title string, in a property of thestruct
).Yes, you have defined
gotTitle
to be a local variable that just happens to have the same name as the property of the same name.So, before I go to the solution, let's make a few observations so we understand what is going on. The key issue is that a
Task
with anawait
inside it runs asynchronously. Consider:Note that I have moved the
let gotTitle
inside theTask
block. You can’t referenceresult
outside of this block of code.Anyway, when you tap on the button, you will see the following in the console:
Note the sequence of events:
Hopefully, this illustrates why it makes no sense to refer to
result
where the printing of “after task submitted” is taking place. You haven’t even gotten to the declaration/assignment ofresult
by that point.So, the moral of the story is that if you want something updated after the asynchronous task, it needs to be immediately after the
await
line, inside theTask
(or whatever context it is in). If you put it outside of theTask
, it means that it won’t wait for the asynchronousTask
to finish.So, how would you access the result out of the
Task
block. You would save it to anObservedProperty
(which, coincidentally, helps separate the business logic from the view):So, the performance of the request (and the current state) is pulled out of the view and the state of the request is captured in the
AppStoreRestoreRequest
.