Swift concurrency: Update a sample app

RSS for tag

Discuss the WWDC21 session Swift concurrency: Update a sample app.

Posts under wwdc21-10194 tag

15 Posts

Post

Replies

Boosts

Views

Activity

Swift 5.5 Concurrency: how to serialize async Tasks to replace an OperationQueue with maxConcurrentOperationCount = 1?
I’m currently migrating my app to use the concurrency model in Swift. I want to serialize Tasks to make sure they are executed one after the other (no paralellism). In my use case, I want to listen to notifications posted by the NotificationCenter and execute a Task every time a new notification is posted. But I want to make sure no previous task is running. It's the equivalent of using an OperationQueue with maxConcurrentOperationCount = 1. For example, I’m using CloudKit with Core Data in my app and I use persistent history tracking to determine what changes have occurred in the store. In this Synchronizing a Local Store to the Cloud Sample Code, Apple uses an operation queue for handling history processing tasks (in CoreDataStack). This OperationQueue has a maximum number of operations set to 1. private lazy var historyQueue: OperationQueue = { let queue = OperationQueue() queue.maxConcurrentOperationCount = 1 return queue }() When a Core Data notification is received, a new task is added to this serial operation queue. So if many notifications are received, they will all be performed one after the other one in a serial way. @objc func storeRemoteChange(_ notification: Notification) { // Process persistent history to merge changes from other coordinators. historyQueue.addOperation { self.processPersistentHistory() } } In this Loading and Displaying a Large Data Feed Sample Code, Apple uses Tasks to handle history changes (in QuakesProvider). // Observe Core Data remote change notifications on the queue where the changes were made. notificationToken = NotificationCenter.default.addObserver(forName: .NSPersistentStoreRemoteChange, object: nil, queue: nil) { note in Task { await self.fetchPersistentHistory() } } I feel something is wrong in the second project as Tasks could happen in any order, and not necessarily in a serial order (contrary to the first project where the OperationQueue as a maxConcurrentOperationCount = 1). Should we use an actor somewhere to make sure the methods are serially called? I thought about an implementation like this but I’m not yet really comfortable with that: actor PersistenceStoreListener { let historyTokenManager: PersistenceHistoryTokenManager = .init() private let persistentContainer: NSPersistentContainer init(persistentContainer: NSPersistentContainer) { self.persistentContainer = persistentContainer } func processRemoteStoreChange() async { print("\(#function) called on \(Date.now.formatted(date: .abbreviated, time: .standard)).") } } where the processRemoteStoreChange method would be called by when a new notification is received (AsyncSequence): notificationListenerTask = Task { let notifications = NotificationCenter.default.notifications(named: .NSPersistentStoreRemoteChange, object: container.persistentStoreCoordinator) for await _ in notifications { print("notificationListenerTask called on \(Date.now.formatted(date: .abbreviated, time: .standard)).") await self.storeListener?.processRemoteStoreChange() } }
1
0
5.9k
Mar ’22
Append a dictionary array to another dictionary array in Swift
have two quote dictionaries I'm trying to append after an in-app purchase. I have tried several different methods to append the dictionaries together but I'm still getting an error "No exact matches in call to instance method 'append'" I have established variables for each array to then append the array within the struct. Any thoughts? Is there a better method I should use to add the quotes from the array called QuoteDetails2 to the initial array QuoteDetails? Here is the code I'm trying to correct: var topQuotes = [QuoteDetails]() var additionalQuotes = [QuoteDetails2]() public struct QuoteProvider { static func all() -> [QuoteDetails] { return [ QuoteDetails( id: “1”, texts: “High school is fun”, authors: “SM” ), QuoteDetails( id: “2”, texts: “Middle School is fun”, authors: "A. Philip Randolph" ), QuoteDetails( id: “3”, texts: “The playground is fun”, authors: "Booker T. Washington" ), QuoteDetails( id: “4”, texts: "Hold on to your dreams of a better life and stay committed to striving to realize it.", authors: “KJ” ) ] } static func all2() -> [QuoteDetails2] { return [ QuoteDetails2( id: "1", texts: "The cat ran fast”, authors: " ME” ), QuoteDetails2( id: "2", texts: “The dog ran fast.”, authors: " ME” ), QuoteDetails2( id: "3", texts: "End life problems”, authors: “ME” ) ] } func showPremiumQuotes() { if UserDefaults.standard.bool(forKey: "premiumQuotes") == true { topQuotes.append(contentsOf: additionalQuotes) } } /// - Returns: A random item. static func random() -> QuoteDetails { let allQuotes = QuoteProvider.all() let randomIndex = Int.random(in: 0..<allQuotes.count) return allQuotes[randomIndex] } }
0
0
1.1k
Mar ’22
Configuring Crashlytics Without Using CocoaPods Not Getting Crash Reports
Hi, For my app, I tried to configure the Firebase Crashlytics. For configuring I’m not using the pod file. Installed Firebase Without Using CocoaPods. For that I followed the following link: https://mokacoding.com/blog/setting-up-firebase-without-cocoapods/ Then I added GoogleService-Info.plist to the project from the Firebase account. After that, I changed the DEBUG_INFORMATION_FORMAT from DWARF to dwarf-with-dsym in Build options. Then I added the Run script in the Build phase. Added the following script: "${PROJECT_DIR}/ProjectName/GoogleService-Info.plist" -p ios "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}" For install build only selected Based on the dependency analysis is selected Then in input files, I added the following: ${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME} $(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH) Changed the Scheme from debug to release. I could not able to get the crash from crashlytics console. Is any issue is with the run scrips? I appreciate your help in advance.
0
0
1.3k
Feb ’22
UIPageViewController is slow when there are multiple pages with dynamic contents
I have a page view controller. it has at most 30 pages. each page contains a collection view. in collection view, i have to show information which contains images and text from server. and it will have at most 500 contents. Please note that, my pageViewController is in tabBarController. So, When i tap on one of my tabs, the pageViewController will be shown. The issue is, During first initialization of my pageViewController it's very very slow. take almost 3~4 seconds depends on how many pages and contents are in pageViewController. My query is , how to overcome this issue? as a side note, i am downloading from server through async operation.
0
0
667
Dec ’21
Want to know for loop parallel using swift 5.5
Hello developers, I already see parallel code using constant number of parallel like this from official site. async let firstPhoto = downloadPhoto(named: photoNames[0]) async let secondPhoto = downloadPhoto(named: photoNames[1]) async let thirdPhoto = downloadPhoto(named: photoNames[2]) let photos = await [firstPhoto, secondPhoto, thirdPhoto] show(photos) But I want to use this to variable size of works. for photoName in photoNames { async let ... = downloadPhoto(named: photoName) } let photos = await ... show(photos) Does swift 5.5 support this case??? By any chance, do I use TaskGroup? I use TaskGroup already, but I want to know that swift supports it.
2
0
2.0k
Oct ’21
Xcode13 XCFramework binary package problem
when I upgrade xcode13 and distribution some base components with xcframework, I got some issue below: property 'bounds' isolated to global actor 'MainActor' can not be referenced from this synchronous context 17:49:37 17:49:37 @_Concurrency.MainActor(unsafe) public func setPlaceholder(text: Swift.String, Width: CoreGraphics.CGFloat = UIScreen.main.bounds.size.witdth) when general swiftinterface file with Xcode13, will auto add @_Concurrency for some UI-related function. but UIKit property UIScreen.main.bounds.size.witdth is not mask as _Concurrency. I try to add @objcMembers to swift Class, the problem is missed. I think It's an Xcode13 issue~~~
0
0
444
Oct ’21
TaskGroup in and Actor
I've had an issue in my project where I trigger a task from a SwiftUI View with the modifier .task. From there it calls and async function into an actor that has a TaskGroup that makes concurrent network calls that has a type of Void.self. I've noticed that sometimes the TaskGroup is either never called and will no longer be called. I'm wondering if perhaps a TaskGroup inside of an Actor that has a parent Task created outside the Actor is a problem? But it does seem to work if I change the Actor to a Class. Could someone help explain to me why this is?
0
0
685
Aug ’21
Deduplication of Tasks
A pretty common piece of work I'd like to generalize a Task version of is deduplicating work in callback logic by stashing the equivalent callbacks to be called when the shared underlying work is done. I have a fairly naive version of this working as it's own Task/actor/async/await soup import Foundation public actor Dupes<Key: Hashable, Success, Failure: Error> {     private var tasks = [Key:Task<Success, Failure>]() } public extension Dupes where Failure == Error {     func async(key: Key, priority: TaskPriority? = nil, operation: @escaping @Sendable () async throws -> Success) async throws -> Success {         if let task = tasks[key] {             return try await task.value         } else {             let task = Task(priority: priority) {                 try await operation()             }             tasks[key] = task             let data = try await task.value             tasks.removeValue(forKey: key)             return data         }     } } public extension Dupes where Failure == Never {     func async(key: Key, priority: TaskPriority? = nil, operation: @escaping @Sendable () async -> Success) async -> Success {         if let task = tasks[key] {             return await task.value         } else {             let task = Task(priority: priority) {                 await operation()             }             tasks[key] = task             let data = await task.value             tasks.removeValue(forKey: key)             return data         }     } } That can used like so if we had an async method that returns a value (bar()) based on some work that we know is shared based on the identifier 123 let foo = Foo() let dupes = Dupes<String, Int, Never>() Task.detached { await dupes.async(key: "123") {     await foo.bar() } } Task.detached { await dupes.async(key: "123") {     await foo.bar() } } In naive testing this seems to work. It feels really odd to be handing off to another actor for managing state that seems internal to whatever actor would need to avoid duplicate work. I tried defining similar methods on a custom actor or on an extension on Actor but passing the storage via keyPath or inout violates the mutability rules of actors (which to be fair makes sense). Is there an idiom for this kind of book keeping? A good real world example of this is network requests where I'd pass in a Hashable network request that makes or owns a URLRequest for me to hand off to URLSession. I don't want to download the same request twice and I don't want to write the same book keeping logic again and again.
0
0
912
Jul ’21
Xcode 13 beta 2 (13A5155e) uses two different versions of Concurrency for iOS and other platforms (e.g. macOS, watchOS, tvOS)
It is ridiculous to use two different versions of Concurrency API for different platforms. Xcode 13 beta 2 (13A5155e) uses two different versions of Concurrency for iOS and other platforms (e.g. macOS, watchOS, tvOS)!  // //  TestAsyncApp.swift //  Shared // // import SwiftUI @main struct TestAsyncApp: App {     var body: some Scene {         WindowGroup {             ContentView()         }     }          @available(iOS 15.0, macOS 12.0, watchOS 8.0, tvOS 15.0, *)     func testAsync() {         #if os(macOS) ||  os(watchOS) || os(tvOS) // will trigger error for iOS         Task {         } Task.detach { }         #elseif os(iOS) // will trigger deprecated warning for macOS, watchOS and tvOS         async {         } asyncDetached { }         #endif     } }
2
0
1.5k
Jun ’21
Xcode13.2.1 Swift Concurrency cause crash in iOS 12
dyld: Symbol not found: ___chkstk_darwin   Referenced from: //app.app/Frameworks/libswift_Concurrency.dylib (which was built for iOS 13.0)   Expected in: /usr/lib/libSystem.B.dylib  in //Frameworks/libswift_Concurrency.dylib
Replies
9
Boosts
0
Views
8.1k
Activity
Apr ’22
Help with autolayout in a scroll view
Why content view is having gap with scroll view on right side despite its trailing constraint set to 0 and scroll view constraints also (0,0,0,0) ?
Replies
0
Boosts
0
Views
593
Activity
Apr ’22
Swift 5.5 Concurrency: how to serialize async Tasks to replace an OperationQueue with maxConcurrentOperationCount = 1?
I’m currently migrating my app to use the concurrency model in Swift. I want to serialize Tasks to make sure they are executed one after the other (no paralellism). In my use case, I want to listen to notifications posted by the NotificationCenter and execute a Task every time a new notification is posted. But I want to make sure no previous task is running. It's the equivalent of using an OperationQueue with maxConcurrentOperationCount = 1. For example, I’m using CloudKit with Core Data in my app and I use persistent history tracking to determine what changes have occurred in the store. In this Synchronizing a Local Store to the Cloud Sample Code, Apple uses an operation queue for handling history processing tasks (in CoreDataStack). This OperationQueue has a maximum number of operations set to 1. private lazy var historyQueue: OperationQueue = { let queue = OperationQueue() queue.maxConcurrentOperationCount = 1 return queue }() When a Core Data notification is received, a new task is added to this serial operation queue. So if many notifications are received, they will all be performed one after the other one in a serial way. @objc func storeRemoteChange(_ notification: Notification) { // Process persistent history to merge changes from other coordinators. historyQueue.addOperation { self.processPersistentHistory() } } In this Loading and Displaying a Large Data Feed Sample Code, Apple uses Tasks to handle history changes (in QuakesProvider). // Observe Core Data remote change notifications on the queue where the changes were made. notificationToken = NotificationCenter.default.addObserver(forName: .NSPersistentStoreRemoteChange, object: nil, queue: nil) { note in Task { await self.fetchPersistentHistory() } } I feel something is wrong in the second project as Tasks could happen in any order, and not necessarily in a serial order (contrary to the first project where the OperationQueue as a maxConcurrentOperationCount = 1). Should we use an actor somewhere to make sure the methods are serially called? I thought about an implementation like this but I’m not yet really comfortable with that: actor PersistenceStoreListener { let historyTokenManager: PersistenceHistoryTokenManager = .init() private let persistentContainer: NSPersistentContainer init(persistentContainer: NSPersistentContainer) { self.persistentContainer = persistentContainer } func processRemoteStoreChange() async { print("\(#function) called on \(Date.now.formatted(date: .abbreviated, time: .standard)).") } } where the processRemoteStoreChange method would be called by when a new notification is received (AsyncSequence): notificationListenerTask = Task { let notifications = NotificationCenter.default.notifications(named: .NSPersistentStoreRemoteChange, object: container.persistentStoreCoordinator) for await _ in notifications { print("notificationListenerTask called on \(Date.now.formatted(date: .abbreviated, time: .standard)).") await self.storeListener?.processRemoteStoreChange() } }
Replies
1
Boosts
0
Views
5.9k
Activity
Mar ’22
Append a dictionary array to another dictionary array in Swift
have two quote dictionaries I'm trying to append after an in-app purchase. I have tried several different methods to append the dictionaries together but I'm still getting an error "No exact matches in call to instance method 'append'" I have established variables for each array to then append the array within the struct. Any thoughts? Is there a better method I should use to add the quotes from the array called QuoteDetails2 to the initial array QuoteDetails? Here is the code I'm trying to correct: var topQuotes = [QuoteDetails]() var additionalQuotes = [QuoteDetails2]() public struct QuoteProvider { static func all() -> [QuoteDetails] { return [ QuoteDetails( id: “1”, texts: “High school is fun”, authors: “SM” ), QuoteDetails( id: “2”, texts: “Middle School is fun”, authors: "A. Philip Randolph" ), QuoteDetails( id: “3”, texts: “The playground is fun”, authors: "Booker T. Washington" ), QuoteDetails( id: “4”, texts: "Hold on to your dreams of a better life and stay committed to striving to realize it.", authors: “KJ” ) ] } static func all2() -> [QuoteDetails2] { return [ QuoteDetails2( id: "1", texts: "The cat ran fast”, authors: " ME” ), QuoteDetails2( id: "2", texts: “The dog ran fast.”, authors: " ME” ), QuoteDetails2( id: "3", texts: "End life problems”, authors: “ME” ) ] } func showPremiumQuotes() { if UserDefaults.standard.bool(forKey: "premiumQuotes") == true { topQuotes.append(contentsOf: additionalQuotes) } } /// - Returns: A random item. static func random() -> QuoteDetails { let allQuotes = QuoteProvider.all() let randomIndex = Int.random(in: 0..<allQuotes.count) return allQuotes[randomIndex] } }
Replies
0
Boosts
0
Views
1.1k
Activity
Mar ’22
Configuring Crashlytics Without Using CocoaPods Not Getting Crash Reports
Hi, For my app, I tried to configure the Firebase Crashlytics. For configuring I’m not using the pod file. Installed Firebase Without Using CocoaPods. For that I followed the following link: https://mokacoding.com/blog/setting-up-firebase-without-cocoapods/ Then I added GoogleService-Info.plist to the project from the Firebase account. After that, I changed the DEBUG_INFORMATION_FORMAT from DWARF to dwarf-with-dsym in Build options. Then I added the Run script in the Build phase. Added the following script: "${PROJECT_DIR}/ProjectName/GoogleService-Info.plist" -p ios "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}" For install build only selected Based on the dependency analysis is selected Then in input files, I added the following: ${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME} $(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH) Changed the Scheme from debug to release. I could not able to get the crash from crashlytics console. Is any issue is with the run scrips? I appreciate your help in advance.
Replies
0
Boosts
0
Views
1.3k
Activity
Feb ’22
Cannot find type '<#Value: BinaryFloatingPoint#>' in scope
I tried to build your sample app Coffee Tracker WatchKit App under Xcode 13 and it failed with the message "Cannot find type '<#Value: BinaryFloatingPoint#>' in scope" on line 12 of CoffeeData. I was building the Starting Point, and the updated without modification, same result.
Replies
2
Boosts
0
Views
1.2k
Activity
Jan ’22
UIPageViewController is slow when there are multiple pages with dynamic contents
I have a page view controller. it has at most 30 pages. each page contains a collection view. in collection view, i have to show information which contains images and text from server. and it will have at most 500 contents. Please note that, my pageViewController is in tabBarController. So, When i tap on one of my tabs, the pageViewController will be shown. The issue is, During first initialization of my pageViewController it's very very slow. take almost 3~4 seconds depends on how many pages and contents are in pageViewController. My query is , how to overcome this issue? as a side note, i am downloading from server through async operation.
Replies
0
Boosts
0
Views
667
Activity
Dec ’21
Want to know for loop parallel using swift 5.5
Hello developers, I already see parallel code using constant number of parallel like this from official site. async let firstPhoto = downloadPhoto(named: photoNames[0]) async let secondPhoto = downloadPhoto(named: photoNames[1]) async let thirdPhoto = downloadPhoto(named: photoNames[2]) let photos = await [firstPhoto, secondPhoto, thirdPhoto] show(photos) But I want to use this to variable size of works. for photoName in photoNames { async let ... = downloadPhoto(named: photoName) } let photos = await ... show(photos) Does swift 5.5 support this case??? By any chance, do I use TaskGroup? I use TaskGroup already, but I want to know that swift supports it.
Replies
2
Boosts
0
Views
2.0k
Activity
Oct ’21
Xcode13 XCFramework binary package problem
when I upgrade xcode13 and distribution some base components with xcframework, I got some issue below: property 'bounds' isolated to global actor 'MainActor' can not be referenced from this synchronous context 17:49:37 17:49:37 @_Concurrency.MainActor(unsafe) public func setPlaceholder(text: Swift.String, Width: CoreGraphics.CGFloat = UIScreen.main.bounds.size.witdth) when general swiftinterface file with Xcode13, will auto add @_Concurrency for some UI-related function. but UIKit property UIScreen.main.bounds.size.witdth is not mask as _Concurrency. I try to add @objcMembers to swift Class, the problem is missed. I think It's an Xcode13 issue~~~
Replies
0
Boosts
0
Views
444
Activity
Oct ’21
want to save the text input data in TableViewController (keeping previous entries)
I have to enter first name ,last name , and mobile number which will be added using a button and then show it in the table view . and when the data is stored in table view the textfield should be blank for next entry. *note - textfield and tableview are in same view controller
Replies
0
Boosts
0
Views
505
Activity
Sep ’21
TaskGroup in and Actor
I've had an issue in my project where I trigger a task from a SwiftUI View with the modifier .task. From there it calls and async function into an actor that has a TaskGroup that makes concurrent network calls that has a type of Void.self. I've noticed that sometimes the TaskGroup is either never called and will no longer be called. I'm wondering if perhaps a TaskGroup inside of an Actor that has a parent Task created outside the Actor is a problem? But it does seem to work if I change the Actor to a Class. Could someone help explain to me why this is?
Replies
0
Boosts
0
Views
685
Activity
Aug ’21
how to transfer data from tableView to Collection View
I have TableView with section Each section have collection view I need to pass data from tableViewcontroller to Tableviewcell Please help me to pass the data between the controller Once I passed the data I will easily access the collection View Thank you in Advance. !
Replies
0
Boosts
0
Views
605
Activity
Jul ’21
Deduplication of Tasks
A pretty common piece of work I'd like to generalize a Task version of is deduplicating work in callback logic by stashing the equivalent callbacks to be called when the shared underlying work is done. I have a fairly naive version of this working as it's own Task/actor/async/await soup import Foundation public actor Dupes<Key: Hashable, Success, Failure: Error> {     private var tasks = [Key:Task<Success, Failure>]() } public extension Dupes where Failure == Error {     func async(key: Key, priority: TaskPriority? = nil, operation: @escaping @Sendable () async throws -> Success) async throws -> Success {         if let task = tasks[key] {             return try await task.value         } else {             let task = Task(priority: priority) {                 try await operation()             }             tasks[key] = task             let data = try await task.value             tasks.removeValue(forKey: key)             return data         }     } } public extension Dupes where Failure == Never {     func async(key: Key, priority: TaskPriority? = nil, operation: @escaping @Sendable () async -> Success) async -> Success {         if let task = tasks[key] {             return await task.value         } else {             let task = Task(priority: priority) {                 await operation()             }             tasks[key] = task             let data = await task.value             tasks.removeValue(forKey: key)             return data         }     } } That can used like so if we had an async method that returns a value (bar()) based on some work that we know is shared based on the identifier 123 let foo = Foo() let dupes = Dupes<String, Int, Never>() Task.detached { await dupes.async(key: "123") {     await foo.bar() } } Task.detached { await dupes.async(key: "123") {     await foo.bar() } } In naive testing this seems to work. It feels really odd to be handing off to another actor for managing state that seems internal to whatever actor would need to avoid duplicate work. I tried defining similar methods on a custom actor or on an extension on Actor but passing the storage via keyPath or inout violates the mutability rules of actors (which to be fair makes sense). Is there an idiom for this kind of book keeping? A good real world example of this is network requests where I'd pass in a Hashable network request that makes or owns a URLRequest for me to hand off to URLSession. I don't want to download the same request twice and I don't want to write the same book keeping logic again and again.
Replies
0
Boosts
0
Views
912
Activity
Jul ’21
Every 10-15 min. Screen going to black with error, Your computer needs to restart
Hi, After updating my MacBook Air 2017 to Big Sur 11.4, very often/many times I am getting black screen error - Reboot system due to Some error. I have even reinstalled OS by completely erasing my disk, still I am getting same error. Kindly help, as this is giving big interruptions to my work. Thank you. S Yugandhar
Replies
2
Boosts
0
Views
683
Activity
Jul ’21
Xcode 13 beta 2 (13A5155e) uses two different versions of Concurrency for iOS and other platforms (e.g. macOS, watchOS, tvOS)
It is ridiculous to use two different versions of Concurrency API for different platforms. Xcode 13 beta 2 (13A5155e) uses two different versions of Concurrency for iOS and other platforms (e.g. macOS, watchOS, tvOS)!  // //  TestAsyncApp.swift //  Shared // // import SwiftUI @main struct TestAsyncApp: App {     var body: some Scene {         WindowGroup {             ContentView()         }     }          @available(iOS 15.0, macOS 12.0, watchOS 8.0, tvOS 15.0, *)     func testAsync() {         #if os(macOS) ||  os(watchOS) || os(tvOS) // will trigger error for iOS         Task {         } Task.detach { }         #elseif os(iOS) // will trigger deprecated warning for macOS, watchOS and tvOS         async {         } asyncDetached { }         #endif     } }
Replies
2
Boosts
0
Views
1.5k
Activity
Jun ’21