Discuss Swift.

Swift Documentation

Post

Replies

Boosts

Views

Activity

Understanding how ARC is different for Struct vs Class
Hi, I was trying to understand how swift manages it memory just wanted to verify my understanding on it. For Value Types i.e. Struct ARC (Automatic Reference Counting) is not there, Memory is Managed/Confined on the basis of scope of that Variable. And For Struct whenver we do assignment a Copy is been created. For Classes, Swift Manages Memroy with the help of ARC i.e. whenever I create a instance of class its reference count get increased and when we assign same instance to new variable then it also result in increment of Reference Count. The Memory will get deallocated when all the variables pointing to that object are no longer in use.
1
0
384
Aug ’24
How to pass Child Class reference as Parent Class
So I have this child class with a function that creates a perdetermined array of other classes. class DirectGame : GameParent { static func GetAllChallenges() -> Array<ChallengeParent>{ return [LockdownChallenge(game: self)] } } These other classes take in a GameParent class in the initalizer like so: class LockdownChallenge { var game : GameParent init(game: GameParent) { self.game = game } } However this line return [LockdownChallenge(game: self)] is throwing the error "Cannot convert value of type 'DirectGame.Type' to expected argument type 'GameParent'" How do I pass in a reference to DirectGame into the initalizer of ChallengeParent?
2
0
326
Aug ’24
How ARC works withUnsafeMutablePointer Interface.
I am using withUnsafeMutablePointer to get raw pointer from Data. Once I get a Pointer I follow these steps: I create a Wrapper using that Pointer. After that I increase it ARC and pass it as a opaque to C++ When I was on First Step if my thread get suspended and after some time if it resumes then is there a possibility that the Memory will get freed due to ARC. Adding basic Code Flow depicting what i am doing. public class DataHolder { public init () {} public var data_wrapper : Data? } func InternalReceiveHandler (_ pContent : Data?) -> Void { var holder : DataHolder = DataHolder.init () withUnsafeMutablePointer (to : &pContent) { data_pointer in holder.data_wrapper = Data.init (noBytesCopy : data_pointer, count : no_of_bytes, deallocator : .none) return Unmanaged.passRetained (holder).toOpaque () } } Is there a possibility that when I am creating the wrapper my thread get suspended and when it get resumed the Memory the pointer was pointing can be freed by ARC.
5
0
453
Aug ’24
"Undefined symbol: __swift_FORCE_LOAD_$_swiftCompatibility56" or "Symbol not found: (_objc_claimAutoreleasedReturnValue)"
I'm working on a Payment SDK integrating Storekit2 for Unity games. The workflow is as follows: build the swift project that exposes objective c interface to static libraries, then archive them into xcframework embed the xcframework into native unity plugin where we call objective-c functions from C# export the unity project to Xcode project build the game Xcode project When deployment target of swift project is set to iOS15 No matter what iOS version target is set in the game Xcode project, I got build error: Undefined symbol: __swift_FORCE_LOAD_$_swiftCompatibility56 When deployment target of swift project is set to iOS16 And set the deployment target of game project to iOS15 (I need to let the payment sdk to work on iOS15 as Storekit2 and swift concurrency shipped with iOS15). I can build the game Xcode project, and it works on iOS16+ device. But when I run on iOS15 device, I got runtime error: 2024-08-26 18:17:29.289078+0900 ***[1404:95780] Error loading /var/containers/Bundle/Application/123/***/Frameworks/UnityFramework.framework/UnityFramework: dlopen(/var/containers/Bundle/Application/123/***/Frameworks/UnityFramework.framework/UnityFramework, 0x0109): Symbol not found: (_objc_claimAutoreleasedReturnValue) Referenced from: '/private/var/containers/Bundle/Application/123/***/Frameworks/UnityFramework.framework/UnityFramework' Expected in: '/usr/lib/libobjc.A.dylib' 2024-08-26 18:17:29.418604+0900 ***[1404:95780] Error loading /var/containers/Bundle/Application/123/***/Frameworks/UnityFramework.framework/UnityFramework: dlopen(/var/containers/Bundle/Application/123/***/Frameworks/UnityFramework.framework/UnityFramework, 0x0109): Symbol not found: (_objc_claimAutoreleasedReturnValue) Referenced from: '/private/var/containers/Bundle/Application/123/***/Frameworks/UnityFramework.framework/UnityFramework' Expected in: '/usr/lib/libobjc.A.dylib' If I chose not to build framework into static libraries but dynamic ones, I can avoid this problem but Unity cannot handle dynamic libraries well when exporting to Xcode project so I have no choice here but to stick to static ones. minimum reproduction I made a minimum reproduction project to exclude the process of unity. a fresh new empty objective-c app project embed the xcframework built with target iOS15 call a function in the framework in applicationDidFinishLaunch set the deployment target of main target of the app project to iOS15. build the project I still get Undefined symbol: __swift_FORCE_LOAD_$_swiftCompatibility56 versions Xcode version 15.4 Test iOS device version 15.8
7
0
993
Aug ’24
How to prevent screen recording from iOS 18 onwards as isCaptured is deprecated from iOS 18 ?
I am developing an iPhone app related to finance and currently I am using isCaptured value to prevent screen recording by checking the isCaptured value and if it is true then I blur the video recording. It was working fine while using UIScreen.main.isCaptured till iOS 17 . But for iOS 18 it became deprecated and it is not working any more. Below is the obj-c code block. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions { if (@available(iOS 11.0, *)) { BOOL isCaptured = [[UIScreen mainScreen] isCaptured]; if(isCaptured){ // Do the action for hiding the screen recording } } else{ // Fallback on earlier versions } return YES; } The replacement sceneCaptureState is working only for a scene-based app which uses UISceneDelegate lifecycle but it's not working for the old structure so now i have that problem, my iPhone app is very big and does not support scenes at all since we are following UIAppDelegate life cycle for years, what shall I do to prevent screen recording from iOS 18 onwards ? Note: My iPhone app does not support any scene configuration Please help me in this. Regards, Carol
2
1
583
Aug ’24
withCheckedContinuation crashes on Xcode 16
We are using a 3rd party SDK which crashes on iOS 18 in certain scenarios. They say they need Apple to fix this bug ahead of release https://github.com/swiftlang/swift/issues/75952 but I'm skeptical since it is only a few weeks away most likely. The bug seems pretty bad so is there any chance it will be fixed before iOS 18? We aim for a same-day release so would be great to know if we need to remove the 3rd party SDK or not.
5
1
1.5k
Aug ’24
BGTaskScheduler with
I’m trying to use BGProcessingTaskRequest to fetch step data in the background and send it. However, when I combine BGProcessingTaskRequest, HKObserverQuery, and healthStore.enableBackgroundDelivery, the results sometimes return zero. When I don’t schedule the BGProcessingTaskRequest, the data retrieved using HKObserverQuery and HKSampleQueryDescriptor is correct. // Register Smart Walking Sync Task func registerSmartWalkingSync() { #if !targetEnvironment(simulator) BGTaskScheduler.shared.register(forTaskWithIdentifier: BGTaskIdentifier.smartwalking.rawValue, using: nil) { task in guard let task = task as? BGProcessingTask else { return } self.handleSmartWalkingSync(task: task) } #endif } func scheduleSmartWalkingSync(in seconds: TimeInterval? = nil, at date: Date? = nil) { let newRequest = BGProcessingTaskRequest(identifier: BGTaskIdentifier.smartwalking.rawValue) newRequest.requiresNetworkConnectivity = true newRequest.requiresExternalPower = false if let seconds = seconds { newRequest.earliestBeginDate = Date().addingTimeInterval(seconds) } else if let date = date { newRequest.earliestBeginDate = date } do { try BGTaskScheduler.shared.submit(newRequest) debugPrint("✅ [BGTasksManager] scheduled for Smart Walking Sync") } catch { FirebaseConnection.shared.recordException(error) debugPrint("❌ [BGTasksManager] error: \(error)") } } // Handle Smart Walking Sync Task func handleSmartWalkingSync(task: BGProcessingTask) { debugPrint("🔄 [BGTasksManager] sync \(task.identifier) sync started") scheduleSmartWalkingSync(in: SYNC_SMARTWALKING_TIME_INTERVAL) let queue = OperationQueue() let operation = HealthActivitiesOperation() operation.completionBlock = { Task { do { try await operation.sync() task.setTaskCompleted(success: !operation.isCancelled) debugPrint("✅ [BGTasksManager] sync \(task.identifier) completed successfully") } catch { FirebaseConnection.shared.recordException(error) task.setTaskCompleted(success: false) debugPrint("❌ [BGTasksManager] sync \(task.identifier) error: \(error)") } } } task.expirationHandler = { operation.cancel() } queue.addOperation(operation) } // MARK: - HealthKit Background Delivery internal func enableBackgroundDeliveryForAllTypes() async throws { for type in allTypes.filter({ type in type != HKQuantityType(.heartRate) }) { try await healthStore.enableBackgroundDelivery(for: type, frequency: .daily) } debugPrint("✅ [HealthKitManager] Enable Background Delivery") } internal func observeHealthKitQuery(predicate: NSPredicate?) async throws -> Set<HKSampleType> { let queryDescriptors: [HKQueryDescriptor] = allTypes .map { type in HKQueryDescriptor(sampleType: type, predicate: predicate) } return try await withCheckedThrowingContinuation { continuation in var hasResumed = false let query = HKObserverQuery(queryDescriptors: queryDescriptors) { query, updatedSampleTypes, completionHandler, error in if hasResumed { return } if let error = error { continuation.resume(throwing: error) } else { continuation.resume(returning: updatedSampleTypes ?? []) } hasResumed = true completionHandler() } healthStore.execute(query) } } internal func getHealthActivity(by date: Date, predicate: NSCompoundPredicate, sampleTypes: Set<HKSampleType>) async throws -> HealthActivityData { var data = HealthActivityData(steps: 0, calories: 0, distance: 0.0, distanceCycling: 0.0, totalDuration: 0, date: date, heartRate: nil) for sampleType in sampleTypes { guard let quantityType = sampleType as? HKQuantityType else { continue } switch quantityType { case HKQuantityType(.stepCount): let stepCount = try await getDescriptor( date: date, type: quantityType ).result(for: healthStore) .statistics(for: date)?.sumQuantity()?.doubleValue(for: HKUnit.count()) data.steps = stepCount ?? 0.0 // Calculate total duration using HKSampleQueryDescriptor let totalDurationDescriptor = HKSampleQueryDescriptor( predicates: [.quantitySample(type: quantityType, predicate: predicate)], sortDescriptors: [SortDescriptor(\.endDate, order: .reverse)] ) let stepSamples = try await totalDurationDescriptor.result(for: healthStore) data.totalDuration += stepSamples .reduce(0) { $0 + $1.endDate.timeIntervalSince($1.startDate) } / 60.0 default: debugPrint("Unknown quantity type") } } return data }
2
0
361
Aug ’24
PTT framework problem after idle ( recording muted by OS )kaj23
We have been successfully using the PTT (Push-to-Talk) framework in our application since the release of iOS 17. Audio is recorded by pressing a PTT button and speaking after the PTT framework initiates an AVAudioSession. While the PTT framework has generally worked well since the iOS 17 release, we have received reports that, on occasion, after the app has been idle for a while ( when I have seen it my phone has been in flightmode over night), it suddenly records only silent audio. This issue does not occur every time but sporadically. For users experiencing this problem, pressing the PTT button results in no “PTT framework start sound,” and only “empty sound” is recorded. The only solution to restore audio is restarting the device. Restarting the app alone is insufficient, though leaving the PTT channel and rejoining it also resolves the issue. I have reproduced the problem several times and observed that everything appears normal within the app. We receive an active AVAudioSession from the PTT framework, and it seems like the app is recording, but all recorded sound packets are silent. Upon reviewing logs from the phone (via the Console app), I noticed that the app is muted when starting the recording and unmuted after stopping the recording. For example: • Start recording ≈ 15:01:30 • Stop recording ≈ 15:01:44 • 15:01:30.124144+0100 audiomxd -CMSessionMgr- MXCoreSessionSetProperty: Session ‘sid:0xa80037, AppName(2717), ‘prim’’ isRecordingMuted updated to ‘1’ • 15:01:44.384208+0100 audiomxd -CMSessionMgr- MXCoreSessionSetProperty: Session ‘sid:0xa80037, AppName(2717), ‘prim’’ isRecordingMuted updated to ‘0’ When the system functions normally, the isRecordingMuted flag toggles between 0 and 1, but remains at 0 (non-muted) during recording. After stopping the recording, this state does not change anymore, unlike in the error state. There is no difference in behavior whether the app is in the foreground or background when starting the transmission, or whether the PTT framework’s “Talk” button is used once the device enters the “error state.” I have filed a bug report with logs provided on 28 November 2023 that is still open but no feedback. We now have customers that are reporting this issue again on 17.5.1 and its starting to be a big issue. Anyone else that have similar problems ?
0
0
297
Aug ’24
Error in OutlineListView on MAC OS 15..1 with Swifdata recursive relationship
I have a model "Objetive" with recursive iteration. In the user interface I can see all the Items, as expected, and I can expands all those that have children. However, I encounter an error when attempting to compact anyone with children that I have previously expanded, But only when I'm using Mac OS 15.1 On iOS 18.1 Works perfectly. The error happens in List, Outlinegroup or Table. struct ObjectiveTable: View{ @Query(filter: #Predicate<Objective>{$0.parent == nil}) var all : [Objective] @State var selected : Objective? var body: some View{ VStack{ List(all ,children: \Objective.sonsNIL){ line in Text(line.name) } } } } @Model final class Objective{ @Attribute(.unique) var id = UUID() var name: String var parent: Objective? = nil @Relationship(deleteRule: .cascade, inverse: \Objective.parent) var sons: [Objective] = [] var sonsNIL: [Objective]?{ get{ if sons.count < 1{ return nil } else{ return sons } } } ... ERROR Row index -1 out of row range (numberOfRows: 14) for <SwiftUI.SwiftUIOutlineListView: 0x129852200> ( 0 CoreFoundation 0x000000018c834ec0 __exceptionPreprocess + 176 1 libobjc.A.dylib 0x000000018c31acd8 objc_exception_throw + 88 2 AppKit 0x00000001903eb304 -[NSTableRowData availableRowViewWhileUpdatingAtRow:] + 0 3 SwiftUI 0x00000001bb365224 $s7SwiftUI0A17UIOutlineListViewC11removeItems2at8inParent13withAnimationy10Foundation8IndexSetV_ypSgSo07NSTableeL7OptionsVtF + 1388 4 SwiftUI 0x00000001bb3656f8 $s7SwiftUI0A17UIOutlineListViewC11removeItems2at8inParent13withAnimationy10Foundation8IndexSetV_ypSgSo07NSTableeL7OptionsVtFTo + 252 5 CoreFoundation 0x000000018c7a28b4 invoking + 148 6 CoreFoundation 0x000000018c7a272c -[NSInvocation invoke] + 428 7 CoreFoundation 0x000000018c7d7958 -[NSInvocation invokeWithTarget:] + 64 8 AppKit 0x000000019052a110 -[NSObjectAnimator forwardInvocation:] + 1512 9 CoreFoundation 0x000000018c7a0ee4 forwarding + 964 10 CoreFoundation 0x000000018c7a0a60 CF_forwarding_prep_0 + 96 11 SwiftUI 0x00000001bb37e458 $s7SwiftUI22OutlineListCoordinatorC19recursivelyDiffRows_4with2by9expandAllyAA0a9UIOutlineD4ViewC_AA0dC4ItemCAA0nD4TreeVAA14ExpansionStateOtF + 37012 12 SwiftUI 0x00000001bb3802b8 $s7SwiftUI22OutlineListCoordinatorC19recursivelyDiffRows_4with2by9expandAllyAA0a9UIOutlineD4ViewC_AA0dC4ItemCAA0nD4TreeVAA14ExpansionStateOtF + 44788 13 SwiftUI 0x00000001bb37538c $s7SwiftUI22OutlineListCoordinatorC8diffRows2of2toyAA0a9UIOutlineD4ViewC_AA0kD4TreeVtF + 120 14 SwiftUI 0x00000001bb36f3d4 $s7SwiftUI22OutlineListCoordinatorC6update4diff04viewD4Tree18idSelectionChanged010navigationk4SeedL0011templateRowL011transactionySb_AA04ViewdI0VS3bAA11TransactionVtFyycfU_yyXEfU + 220 15 SwiftUI 0x00000001bb369044 $s7SwiftUI22OutlineListCoordinatorC24withSelectionUpdateGuard33_BE7B171B0BEE2A9E27ED12968C3771F8LLyySS_yyXEtF + 1320 16 SwiftUI 0x00000001bb36f2d4 $s7SwiftUI22OutlineListCoordinatorC6update4diff04viewD4Tree18idSelectionChanged010navigationk4SeedL0011templateRowL011transactionySb_AA04ViewdI0VS3bAA11TransactionVtFyycfU + 708 17 SwiftUICore 0x00000002277cb578 $sIeg_ytIegr_TRTA + 28 18 SwiftUICore 0x0000000227a6d2b8 $s7SwiftUI6UpdateO15dispatchActionsyyFZ + 1236 19 SwiftUICore 0x0000000227a6c79c $s7SwiftUI6UpdateO3endyyFZ + 212 20 SwiftUICore 0x0000000227f6061c $sSo9NSRunLoopC7SwiftUIE11addObserveryyyycFZySo05CFRunbF3RefaSg_So0gB8ActivityVSvSgtcfU_Tf4ddd_n + 176 21 CoreFoundation 0x000000018c7c17a8 CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION + 36 22 CoreFoundation 0x000000018c7c1694 __CFRunLoopDoObservers + 552 23 CoreFoundation 0x000000018c7c0380 CFRunLoopRunSpecific + 648 24 HIToolbox 0x0000000197c000cc RunCurrentEventLoopInMode + 292 25 HIToolbox 0x0000000197c05d1c ReceiveNextEventCommon + 220 26 HIToolbox 0x0000000197c06020 _BlockUntilNextEventMatchingListInModeWithFilter + 76 27 AppKit 0x0000000190303650 _DPSNextEvent + 660 28 AppKit 0x0000000190c2a408 -[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 688 29 AppKit 0x00000001902f675c -[NSApplication run] + 480 30 AppKit 0x00000001902cd02c NSApplicationMain + 888 31 SwiftUI 0x00000001ba77045c $s7SwiftUI6runAppys5NeverOSo21NSApplicationDelegate_So11NSResponderCXcFTf4e_nAA07TestingdG0C_Tg5Tm + 160 32 SwiftUI 0x00000001babf4854 $s7SwiftUI6runAppys5NeverOxAA0D0RzlF + 84 33 SwiftUI 0x00000001baf04134 $s7SwiftUI3AppPAAE4mainyyFZ + 224 34 Marlo SystemManagement.debug.dylib 0x0000000100ce6130 $s22Marlo_SystemManagement0a1_bC3AppV5$mainyyFZ + 40 35 Marlo SystemManagement.debug.dylib 0x0000000100ce61fc __debug_main_executable_dylib_entry_point + 12 36 dyld 0x000000018c358274 start + 2840 ) FAULT: NSTableViewException: Row index -1 out of row range (numberOfRows: 14) for <SwiftUI.SwiftUIOutlineListView: 0x129852200>; (user info absent)
0
1
253
Aug ’24
How can I share code between app and widget that contains uiapplication?
OK, so I'm trying to share some utils classes for logging. The problem is a use-case where I want to create a debug notification. However, inside the app, I want to show a popup instead if the app is showing, but I can't share that code because it uses UIApplication.shared.ApplicationState. I've tried gating it off with all sorts of methods, @available etc. but I get compilation error "unavailable for application extensions" Example of me trying: static func doNotification(_ header: String, message: String) { //so I'm trying to gate off the code that only can be called in an extension , and in addition I have @available below if(isAppExtension()){ doNotificationFromExtension(header, message: message) }else{ doNotificationFromApp(header, message: message) } } @available(iOSApplicationExtension, unavailable) static func doNotificationFromApp(_ header: String, message: String) { let state = UIApplication.shared.applicationState if state != .active { //my dialog handler in-app popup }else{ NotifUtils.createLocalNotification(message, header: header, category: NOTIFICATION_CATEGORY_DEBUG, playSound: false) } } //here I know that I'm in an extension, so app isn't showing - always local notification static func doNotificationFromExtension(_ header: String, message: String) { NotifUtils.createLocalNotification(message, header: header, category: NOTIFICATION_CATEGORY_DEBUG, playSound: false) } static func isAppExtension() -> Bool { return Bundle.main.executablePath?.contains(".appex/") ?? false } Is there any way to share the code like this? The reason I want to do this is because I have various live activity code that I'd want to re-use, but this is a show.-stopper.
3
0
421
Aug ’24
Sudden errors that never happened before
Hello, I've been working on my macos app for months, today I opened XCode, and it's full of the same errors "Value of type 'URL' has no member 'url''" and "Cannot convert value of type 'Binding' to expected argument type 'CGFloat'". I didn't change ANYTHING, I didn't update nor remove anything, the 3rd party module I'm using didn't get updated, this is all out of the blue! I tried to clean the build folder, erase the derivated data, rebuild a new project, these errors won't go away...worst part is that another of my app use the same codes and there I see the errors but the app still compiles and build!!
0
0
283
Aug ’24
.onMove does not work properly
Hello, I have a problem with the .onMove function. I believe I have set everything up properly. However, the moving does not seem to be working correctly. When I try to move the item, it is highlighted first, as it is supposed to be. Then, while I am moving it through the list, it disappears for some reason, and at the end of the move, it comes back to its initial place. (I use iOS 16.0 minimum, so I don't have to include the EditButton(). It works the same in the edit mode tho) import SwiftUI struct Animal: Identifiable { var id = UUID() var name: String } struct ListMove: View { @State var animals = [Animal(name: "Dog"), Animal(name: "Cat"), Animal(name: "Cow"), Animal(name: "Goat"), Animal(name: "Chicken")] var body: some View { List { ForEach(animals) { animal in Text(animal.name) } .onMove(perform: move) } } func move(from source: IndexSet, to destination: Int) { animals.move(fromOffsets: source, toOffset: destination) } } #Preview { ListMove() }
2
0
348
Aug ’24
Implement UNUserNotificationCenterDelegate in iOS app using Swift6
I've got a problem with compatibility with Swift6 in iOS app that I have no idea how to sort it out. That is an extract from my main app file @MainActor @main struct LangpadApp: App { ... @State private var notificationDataProvider = NotificationDataProvider() @UIApplicationDelegateAdaptor(NotificationServiceDelegate.self) var notificationServiceDelegate var body: some Scene { WindowGroup { TabView(selection: $tabSelection) { ... } .onChange(of: notificationDataProvider.dateId) { oldValue, newValue in if !notificationDataProvider.dateId.isEmpty { tabSelection = 4 } } } } init() { notificationServiceDelegate.notificationDataProvider = notificationDataProvider } } and the following code shows other classes @MainActor final class NotificationServiceDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate { var notificationDataProvider: NotificationDataProvider? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -&gt; Bool { UNUserNotificationCenter.current().delegate = self return true } func setDateId(dateId: String) { if let notificationDataProvider = notificationDataProvider { notificationDataProvider.dateId = dateId } } nonisolated func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async { // After user pressed notification let content = response.notification.request.content if let dateId = content.userInfo["dateId"] as? String { await MainActor.run { setDateId(dateId: dateId) } } } nonisolated func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -&gt; UNNotificationPresentationOptions { // Before notification is to be shown return [.sound, .badge, .banner, .list] } } @Observable final public class NotificationDataProvider : Sendable { public var dateId = "" } I have set Strict Concurrency Checking to 'Complete.' The issue I'm facing is related to the delegate class method, which is invoked after the user presses the notification. Current state causes crash after pressing notification. If I remove "nonisolated" keyword it works fine but I get the following warning Non-sendable type 'UNNotificationResponse' in parameter of the protocol requirement satisfied by main actor-isolated instance method 'userNotificationCenter(_:didReceive:)' cannot cross actor boundary; this is an error in the Swift 6 language mode I have no idea how to make it Swift6 compatible. Does anyone have any clues?
0
11
533
Aug ’24
Await expectations with Swift Testing?
I'm used to wait for expectations when using XCTest, but I'm completely stumped by the seemingly-absent option for expecting some parts of my code to be called in Swift Testing 🤔 Consider the following: protocol MyAPI { func getData() async throws -> String } class MockAPI: MyAPI { let stub: () async throws -> String init(stub: @escaping () async throws -> String = { "hello" }) { self.stub = stub } func getData() async throws -> String { try await stub() } } Which is being used in my view model: class MyViewModel: ObservableObject { private let api: MyAPI @Published var data: String init(api: MyAPI) { self.api = api } func refresh() async throws { self.data = try await api.getData() } } When I wrote tests in the past, I would simply override the stub of the MockAPI implementation and fulfill an expectation in there: class MyViewModelTests: XCTestCase { func testModelCallsAPIOnRefresh() async throws { let expectCallsAPI = expectation("Model should call API") let api = MockAPI { expectCallsAPI.fulfill() return "hello" } let model = MyViewModel(api: api) try await model.refresh() await fulfillment(of: [expectCallsAPI], timeout: 1) } } How would I go about checking that my model does indeed call the API when using Swift Testing?
1
0
479
Aug ’24
Interface fails to work because I have a class named Context.
Bug When you try to extend from NSViewRepresentable but you have a class named Context swift throws a error message that doesn't help at all. Type 'MetalViewRepresentable' does not conform to protocol 'NSViewRepresentable' Steps to reproduce Create a MacOS App Copy this code struct MetalViewRepresentable: NSViewRepresentable { @Binding var metalView: MTKView func makeNSView(context: Context) -> some NSView { metalView } func updateNSView(_ uiView: NSViewType, context: Context) { } } Write this line of code in any file class Context {}
0
0
215
Aug ’24
How does the threshold in DeviceActivityEvent work
Hey everyone, I'm working on implementing an AppLimit, where after accumulating x minutes of Screen Time for an app, it should be blocked. It works fine on the first day, but stops functioning correctly on subsequent days. What I'm Doing I start a 24/7 schedule with a DeviceActivityEvent that has a specified Screen Time threshold. In my DeviceActivityMonitor, I'm reacting to the eventDidReachThreshold. Once the accumulated time is reached, the app is blocked. This works as expected on the first day. Issues I'm Experiencing / Questions Second Day Issue: On the second day, the app is no longer blocked after the Screen Time threshold is reached, even though it worked on the first day. This leads me to suspect that a DeviceActivityEvent is "consumable". Is this correct? Pre-existing Screen Time Issue: If a user has already surpassed the Screen Time threshold before monitoring starts, the app isn't blocked once the schedule is set up. This leads to 2 issues: I would expect that the accumulated amount of time after starting the schedule would result in the call of eventDidReachThreshold. But it is never called It could also be the case that the previously accumulated time is being kept in mind, but that would mean the apps should be blocked, which isn't the case. Does the threshold account for accumulated Screen Time before the schedule begins? I haven't tested setting a limit of 10 minutes, accumulating 3 minutes of Screen Time, then starting the schedule and accumulating the remaining time, but I'm curious if anyone has encountered this behavior. Does anyone have an explanation for this behavior? Any help would be greatly appreciated!
1
0
436
Aug ’24