Post not yet marked as solved
Good day! It seems to be a bug in Xcode that preview can be showed correctly with async code wrapped in Task, for ex:
struct MyView: View {
var onTapped: (() async -> Bool)?
var body: some View {
Button {
Task {
guard await onTapped?() ?? true else { return }
}
.....
} label: {
Text("Tap me")
}
}
}
Crash log
Post not yet marked as solved
I'm writing an app that performs actions in a web browser automatically on user's behalf. Currently my app uses OperationQueue to perform asynchronous work. I'm trying to rewrite the app to use async/await instead. Note, that it is necessary for my app to limit the number of concurrently executing work items. Otherwise the app may run into server throttling issues.
However, I can't find an equivalent to OperationQueue's maxConcurrentOperationCount parameter in the new concurrency model. Is there a way to limit the number of concurrently running "lanes" of execution without resorting to using OperationQueue / DispatchQueue / NSLock ?
Post not yet marked as solved
How can we call async functions in did set blocks? This code will trigger a compilation error:
'didSet' accessor cannot have specifier 'async'
@Published var lastLocation: CLLocation? {
didSet async {
await pinPosition()
}
}
Post not yet marked as solved
My app crashed when launch.
The crash report:
OS Version: iPhone OS 15.4 (19E5209h)
Release Type: Beta
Report Version: 104
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Termination Reason: DYLD 4 Symbol missing
Symbol not found: _$sSo25NSURLSessionWebSocketTaskC10FoundationE4sendyyAbCE7MessageOYaKF
Referenced from: /private/var/containers/Bundle/Application/43FB5827-DE90-4FCF-A716-11A7FD5BE11E/Kingbox.app/Kingbox
Expected in: /usr/lib/swift/libswiftFoundation.dylib
(terminated at launch; ignore backtrace)
Triggered by Thread: 0
Thread 0 Crashed:
0 dyld 0x00000001056506d0 __abort_with_payload + 8
1 dyld 0x00000001056562c8 abort_with_payload_wrapper_internal + 104 (terminate_with_reason.c:102)
2 dyld 0x00000001056562fc abort_with_payload + 16 (terminate_with_reason.c:124)
3 dyld 0x00000001056267e8 dyld4::halt(char const*) + 328 (DyldProcessConfig.cpp:2067)
4 dyld 0x0000000105623920 dyld4::prepare(dyld4::APIs&, dyld3::MachOAnalyzer const*) + 3560 (dyldMain.cpp:0)
5 dyld 0x0000000105621c84 start + 488 (dyldMain.cpp:864)
Demangle the symbol:
_$sSo25NSURLSessionWebSocketTaskC10FoundationE4sendyyAbCE7MessageOYaKF
(extension in Foundation):__C.NSURLSessionWebSocketTask.send((extension in Foundation):__C.NSURLSessionWebSocketTask.Message) async throws -> ()
Post not yet marked as solved
When using Task { ... } in Swift 5.5, I'm unclear if retain cycles might be an issue or not. For example:
class ViewController: UIViewController {
private var rows = [String]()
private var tableView: UITableView?
func populateRows() {
Task {
rows = (try? await getRowsFromNetwork()) ?? []
tableView?.reloadData()
}
}
}
Will populateRows retain the view controller for the life of the task because it references rows and tableView?
If the view controller goes out of scope, I'd like it to have the freedom to deallocate without populateRows retaining it. This syntax compiles, but I don't know if it makes sense:
class ViewController: UIViewController {
private var rows = [String]()
private var tableView: UITableView?
func populateRows() {
Task { [weak self] in
self?.rows = (try? await self?.getRowsFromNetwork()) ?? []
self?.tableView?.reloadData()
}
}
}
I don't mind if the task continues to run. (I'm not worried about canceling it.) I just want to understand if there is a way to avoid retaining the view controller in the task, and if that happens automatically or if something like [weak self] is needed.
Hi,
when working with SwiftUI @Published variables need to be set from the main thread, but at the same time, cannot be defined as @MainActor.
The easy solution is a simple forced sync or async execution on the main thread, but it seems like this does not exist in the world of async/await and Tasks - at least I did not find it.
Instead I found that all demo's from Apple is a quite sad solution. The full method is marked as @MainActor even though this is often only relevant for the last line.
The question is either that I can execute a setter on main only OR that I can mark my SwiftUI code as being on main and thus being able to accept @MainActor @Published
Is there really no solution? If so where do I have to propose/request a solution for this.
I feel like every developer had written his own version of Thread.performOnMain, but here I want something using Task and that the compiler can verify.
All the best
Christoph
Post not yet marked as solved
For the following example I'm expecting if one of the concurrent tasks has thrown an error, the rest unfinished tasks must be cancelled.
But it isn't what I see. If task2 has thrown first, the task1 will continue execution till completion. But it works as expecting in vice-verse, failing task1 first, results task2 cancellation.
The log in case if task2 has thrown first:
task1 BEGIN
task2 BEGIN
task2 completed
task2 catch CancellationError()
task2 END
task1 completed // It's not expecting to see this log
task1 catch CancellationError()
task1 END
Failed: CancellationError()
The log in case if task1 has thrown first (works as expected, see there is no 'task2 completed' log. As soon as task1 has thrown, the entire try await(,) throws as well.):
task1 BEGIN
task2 BEGIN
task1 completed
task1 catch CancellationError()
task1 END
Failed: CancellationError()
task2 catch CancellationError()
task2 END
Code is below:
async let t1 = task1()
async let t2 = task2()
do {
_ = try await (t1, t2)
} catch {
print("Failed: \(error)")
}
func task1() async throws -> Int {
print("task1 BEGIN")
defer { print("task1 END") }
do {
try await Task.sleep(nanoseconds: UInt64(3 * 1_000_000_000))
print("task1 completed")
throw CancellationError()
} catch {
print("task1 catch \(error)")
throw error
}
}
func task2() async throws -> Int {
print("task2 BEGIN")
defer { print("task2 END") }
do {
try await Task.sleep(nanoseconds: UInt64(1 * 1_000_000_000))
print("task2 completed")
throw CancellationError()
} catch {
print("task2 catch \(error)")
throw error
}
}
Post not yet marked as solved
As I can see, all the async APIs in XCode13.0 beta requires a deployment target of iOS 15.0, is that means that I cannot use async/await under iOS 15.0?
I have a table to which I've added a refreshControl and when I pull down the table to refresh the data, I reset the array that feeds the table with data and then immediately request new data through an API call.
Until now, I have used completion handlers and protocols to get the data into the table view but I want to move the logic to async/await because of the complexity needed by the network calls and the pyramid of nested closures.
Populating the view in viewDidLoad works fine but with pullToRefresh selector I get an error:
Thread 1: EXC_BAD_ACCESS (code=1, address=0xbcf917df8160)
override func viewDidLoad() {
super.viewDidLoad()
setupView()
setupTableView()
setupTableRefreshControl()
Task {
await getBalances() //async network call
myTable.reloadData()
}
}
func setupTableRefreshControl() {
myTable.refreshControl = UIRefreshControl()
myTable.refreshControl?.addTarget(self, action: #selector(didPullToRefresh), for: .valueChanged)
}
Code that crashes app:
@objc func didPullToRefresh() async {
balance.reset() // reset array to []
Task {
await getBalances() //async network call
myTable.reloadData()
}
}
After I updated xcode to 13.3 version, almost all mt spm project warns.
SourcePackages/checkouts/SwiftUI-MediaPicker/SwiftUI.UIViewControllerRepresentable:7:24: Static method '_makeView(view:inputs:)' isolated to global actor 'MainActor' can not satisfy corresponding requirement from protocol 'View'
It's pretty bad, because I don' wanna any warnings.
The function in question is the following.
func records(for ids: [CKRecord.ID], desiredKeys: [CKRecord.FieldKey]? = nil) async throws -> [CKRecord.ID : Result<CKRecord, Error>]
Note that the returned value looks like a dictionary of the form [CKRecord.ID : Result<CKRecord, Error>], but the input is an array of CKRecord.IDs.
There are similar functions, but they return a tuple. Like the below example.
func records(matching query: CKQuery, inZoneWith zoneID: CKRecordZone.ID? = nil, desiredKeys: [CKRecord.FieldKey]? = nil, resultsLimit: Int = CKQueryOperation.maximumResults) async throws -> (matchResults: [(CKRecord.ID, Result<CKRecord, Error>)], queryCursor: CKQueryOperation.Cursor?)
Note that matchedResults is an array of tuples consisting of [(CKRecord.ID, Result<CKRecord, Error>)].
I would have thought that the return type in the first function would also be of the form [(CKRecord.ID, Result<CKRecord, Error>)].
What am I missing?
Post not yet marked as solved
Hi,
We have an API that I'm trying to prototype some async await extensions for. Most of our asynchronous methods are cancelable by returning an object that implements our AGSCancelable protocol that includes a cancel() method.
Here's the code I have to try to extend a geocoding method on our AGSLocatorTask class:
extension AGSLocatorTask {
func geocode(withSearchText text: String) async throws -> [AGSGeocodeResult] {
typealias GeocodeContinuation = CheckedContinuation<[AGSGeocodeResult], Error>
var cancelable: AGSCancelable?
return try await withTaskCancellationHandler(handler: {
cancelable?.cancel()
}, operation: {
return try await withCheckedThrowingContinuation({ (continuation: GeocodeContinuation) in
cancelable = self.geocode(withSearchText: text) { results, error in
if let error = error {
continuation.resume(throwing: error)
} else {
continuation.resume(returning: results!)
}
}
})
})
}
}
This works great, but I have to comment out the cancelable?.cancel() call or else I get a Reference to captured var 'cancelable' in concurrently-executing code static analysis error (see attached screenshot).
Could someone explain how to fix this, or is this a bug in the Xcode beta?
Many thanks, and thanks for a great WWDC!!
Post not yet marked as solved
I am trying to understand as to why following piece of code throws an assertion. What I am trying to do is to call asyncFunc() on main thread/main actor from call site. I don't want to decorate asyncFunc with @MainActor as I want the function to be thread agnostic.
func asyncFunc() async -> String? {
dispatchPrecondition(condition: .onQueue(.main))
return "abc"
}
func callSite() {
Task { @MainActor in
await asyncFunc()
}
}
My understanding was that Task { @MainActor ...} would execute all the following code on MainActor/main thread.
I am running Mac OS 12.1 and Xcode 13.2.
My code is the following:
import Foundation
import Cocoa
func trapezoid(_ begin: Double, _ end: Double,_ n: Int) async -> Double {
let hc = (end-begin)/Double(n)
var h = begin
var result = 0.0
for _ in 0...n{
result += h*h + (h+hc)*(h+hc)
h = h+hc
}
return result * (hc/2)
}
Task{
let answer1 = await trapezoid(0, 1, 10000)
let answer2 = await trapezoid(1, 2, 10000)
print(answer1)
print(answer2)
}
With playgrounds I get the following correct result:
0.33343334500044286
2.333733355000306
However, when I use the exact same code in an Xcode project using Command Line Tools, the program just returns with exit code 0 and no output. I am not sure what my error is or if it is an Xcode bug.
Post not yet marked as solved
Anybody converting from CKQueryOperation to the new CloudKit async await methods? If so, what do you think? I'm currently playing with
func records(matching query: CKQuery, inZoneWith zoneID: CKRecordZone.ID? = nil, desiredKeys: [CKRecord.FieldKey]? = nil, resultsLimit: Int = CKQueryOperation.maximumResults) async throws -> (matchResults: [(CKRecord.ID, Result<CKRecord, Error>)], queryCursor: CKQueryOperation.Cursor?)
and
func records(continuingMatchFrom queryCursor: CKQueryOperation.Cursor, desiredKeys: [CKRecord.FieldKey]? = nil, resultsLimit: Int = CKQueryOperation.maximumResults) async throws -> (matchResults: [(CKRecord.ID, Result<CKRecord, Error>)], queryCursor: CKQueryOperation.Cursor?)
They seem to work fine and eliminate completion handlers.
Post not yet marked as solved
Can we use async await on under iOS 15?
Post not yet marked as solved
I'm new to async/await, and am currently migrating my completion handler code to Swift 5.5's concurrency features.
After generating an sync alternative in Xcode to my function func fetchMatchRecords(completion: @escaping ([Match]) -> Void), it becomes func fetchMatchRecords() async -> [Match].
I'm not sure how it would be used in the context of UIKit and diffable data sources.
In a viewDidLoad, previously it would be
MatchHistoryController.shared.fetchMatchRecords() { matches in
DispatchQueue.main.async {
self.dataSource.apply(self.initialSnapshot(), animatingDifferences: false)
}
}
But I'm not sure how it would be used now
Task {
await MatchHistoryController.shared.fetchMatchRecords()
}
self.dataSource.apply(self.initialSnapshot(), animatingDifferences: false)
How would I make sure that the snapshot is applied only after awaiting a successful fetch result?
Here's the definition of initialSnapshot() that I used:
func initialSnapshot() -> NSDiffableDataSourceSnapshot<Section, Match> {
var snapshot = NSDiffableDataSourceSnapshot<Section, Match>()
snapshot.appendSections([.main])
snapshot.appendItems(MatchHistoryController.shared.matches)
return snapshot
}
Post not yet marked as solved
I'm seeing an error trying to test out async let. It seems like this should work, based on the async/let and structured concurrency session videos.
Here's the code:
func doIt() async -> String {
let t = TimeInterval.random(in: 0.25 ... 2.0)
Thread.sleep(forTimeInterval: t)
return String("\(Double.random(in: 0...1000))")
}
async {
async let a = doIt()
async let b = doIt()
async let c = doIt()
async let d = doIt()
let results = await [a, b, c, d]
for result in results {
print(" \(result)")
}
}
But, I get this error for every "async let" statement:
error: AsyncLetSwift55WWDC21.playground:12:15: error: expression is 'async' but is not marked with 'await'
async let a = doIt()
^
await
Am I missing something key, or is this a bug?
I'm running this in the Xcode 13.0 beta, in a Playground.
Thanks!!
Post not yet marked as solved
New error in XCode 13 Beta 4: "Generic parameter 'Success' could not be inferred"
No error in earlier XCode 13 Beta.
What's the fix? THe above line is from Apple example code: "DrawTogether"