Hi all. I need to save an array of strings in userdefaults. I am using
NSKeyedArchiver.archivedData(withRootObject: rootObject, requiringSecureCoding: false)
to convert array of string to data and then save it in userdefaults.
Inorder to retrieve the data back, I am using
let data = self.userDefaults.data(forKey: "key")!
let unarchiver = try NSKeyedUnarchiver(forReadingFrom: data)
unarchiver.requiresSecureCoding = false
let array = unarchiver.decodeObject(forKey: NSKeyedArchiveRootObjectKey) as? NSObject
This was working perfectly till iOS 18. From iOS 18 in couple of devices, we are getting empty string array while we retrieve the value back from userdefaults. We observed this in an iPhone 12 pro and iPhone 15 running on iOS 18. iPhone 12 pro is facing this issue almost once everyday. In iPhone 15 this happens once in 2-3 days.
Tried printing raw data directly from userdefaults. And I can see some data available. But when we convert that back to array of string, I am getting empty. Tried adding logs in catch block. But couldn't get any. What might be the cause of this issue?
Swift
RSS for tagSwift is a powerful and intuitive programming language for Apple platforms and beyond.
Posts under Swift tag
200 Posts
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I am developing a sample authorization plugin to sync the user’s local password to the network password. During the process, I prompt the user to enter both their old and new passwords in custom plugin. After the user enters the information, I use the following code to sync the passwords:
try record.changePassword(oldPssword, toPassword: newPassword)
However, I have noticed that this is clearing all saved keychain information, such as web passwords and certificates. Is it expected behavior for record.changePassword to clear previously stored keychain data?
If so, how can I overcome this issue and ensure the keychain information is preserved while syncing the password?
Thank you for your help!
As of iOS 18.3 SDK, Core Bluetooth is still mostly an Objective-C framework: key objects like CBPeripheral inherit from NSObjectProtocol and does not conform to Sendable.
CBCentralManager has a convenience initializer that allows the caller to provide a dispatch_queue for delegate callbacks. I want my Swift package that implements Core Bluetooth to conform to Swift 6 strict concurrency checking.
It is unsafe to dispatch the delegate events onto my own actor, as the passed in objects are presumably not thread-safe. What is the recommended concurrency safe way to implement Core Bluetooth in Swift 6 with strict concurrency checking enabled?
Hi,
I have a file provider based MacOS application where i have a drive added and am trying to download a folder from that drive.
The folder has sub folders and large files in it.
After some time of download started, i keep getting below error.
error: ["The operation could not be completed. Cannot allocate memory", [code: 12, domain: "NSPOSIXErrorDomain"]
The download action is triggered via Finder's download icon(cloud icon with down arrow).
I am using native URLSession to download the files from server. No third party library is used.
What could be the possible reasons for "can not allocate memory" issue?
I'm experiencing a persistent issue with CloudKit sharing in my iOS application. When attempting to present a UICloudSharingController, I receive the error message "Unknown client: ChoreOrganizer" in the console.
App Configuration Details:
App Name: ChoreOrganizer
Bundle ID: com.ProgressByBits.ChoreOrganizer
CloudKit Container ID: iCloud.com.ProgressByBits.ChoreOrganizer
Core Data Model Name: ChoreOrganizer.xcdatamodeld
Core Data Entity: Chore
Error Details:
The error "Unknown client: ChoreOrganizer" occurs when I present the UICloudSharingController
This happens only on the first attempt to share; subsequent attempts during the same app session don't show the error but sharing still doesn't work
All my code executes successfully without errors until UICloudSharingController is presented
Implementation Details:
I'm using NSPersistentCloudKitContainer for Core Data synchronization and UICloudSharingController for sharing. My implementation creates a custom CloudKit zone, saves both a record and a CKShare in that zone, and then presents the sharing controller.
Here's the relevant code:
@MainActor
func presentSharing(from viewController: UIViewController) async throws {
// Create CloudKit container
let container = CKContainer(identifier: containerIdentifier)
let database = container.privateCloudDatabase
// Define custom zone ID
let zoneID = CKRecordZone.ID(zoneName: "SharedChores", ownerName: CKCurrentUserDefaultName)
do {
// Check if zone exists, create if necessary
do {
_ = try await database.recordZone(for: zoneID)
} catch {
let newZone = CKRecordZone(zoneID: zoneID)
_ = try await database.save(newZone)
}
// Create record in custom zone
let recordID = CKRecord.ID(recordName: "SharedChoresRoot", zoneID: zoneID)
let rootRecord = CKRecord(recordType: "ChoreRoot", recordID: recordID)
rootRecord["name"] = "Shared Chores Root" as CKRecordValue
// Create share
let share = CKShare(rootRecord: rootRecord)
share[CKShare.SystemFieldKey.title] = "Shared Tasks" as CKRecordValue
// Save both record and share in same operation
let recordsToSave: [CKRecord] = [rootRecord, share]
_ = try await database.modifyRecords(saving: recordsToSave, deleting: [])
// Present sharing controller
let sharingController = UICloudSharingController(share: share, container: container)
sharingController.delegate = shareDelegate
// Configure popover
if let popover = sharingController.popoverPresentationController {
popover.sourceView = viewController.view
popover.sourceRect = CGRect(
x: viewController.view.bounds.midX,
y: viewController.view.bounds.midY,
width: 1, height: 1
)
popover.permittedArrowDirections = []
}
viewController.present(sharingController, animated: true)
} catch {
throw error
}
}
Steps I've already tried:
Verified correct bundle ID and container ID match in all places (code, entitlements file, Developer Portal)
Added NSUbiquitousContainers configuration to Info.plist
Ensured proper entitlements in the app
Created and configured proper provisioning profiles
Tried both default zone and custom zone for sharing
Various ways of saving the record and share (separate operations, same operation)
Cleaned build folder, deleted derived data, reinstalled the app
Tried on both simulator and physical device
Confirmed CloudKit container exists in CloudKit Dashboard with correct schema
Verified iCloud is properly signed in on test devices
Console Output:
1. Starting sharing process
2. Created CKContainer with ID: iCloud.com.ProgressByBits.ChoreOrganizer
3. Using zone: SharedChores
4. Checking if zone exists
5. Zone exists
7. Created record with ID: <CKRecordID: 0x3033ebd80; recordName=SharedChoresRoot, zoneID=SharedChores:__defaultOwner__>
8. Created share with ID: <CKRecordID: 0x3033ea920; recordName=Share-C4701F43-7591-4436-BBF4-6FA8AF3DF532, zoneID=SharedChores:__defaultOwner__>
9. About to save record and share
10. Records saved successfully
11. Creating UICloudSharingController
12. About to present UICloudSharingController
13. UICloudSharingController presented
Unknown client: ChoreOrganizer
Additional Information:
When accessing the CloudKit Dashboard, I can see that data is being properly synced to the cloud, indicating that the basic CloudKit integration is working. The issue appears to be specific to the sharing functionality.
I would greatly appreciate any insights or solutions to resolve this persistent "Unknown client" error. Thank you for your assistance.
I'm attempting to create a proof of concept of a static library, distributed as an XCFramework, which has two local XCFramework dependencies.
The reason for this is because I'm working to provide a single statically linked library to a customer, instead of providing them with the static library plus the two dependencies.
The Issue
With a fairly simple example project, I'm not able to access any code from the static library without the complier throwing a "No such module" error and saying that it cannot find one of the dependent modules.
Project Layout
I have an example project that has some example targets with basic example code.
Example Project on Github
Target: FrameworkA
Mach-0 Type: Dynamic
Build Mergable Library: Yes
Skip Install: No
Build Libraries For Distribution: Yes
Target: FrameworkB
Mach-0 Type: Dynamic
Build Mergable Library: Yes
Skip Install: No
Build Libraries For Distribution: Yes
XCFrameworks are being generated from these two targets using Apple's recommendations. I've verified that the mergable metadata is present in both framework's Info.plist files.
Each exposes a single struct which will return an example String.
Finally I have my SDK target:
Target: ExampleKit
Mach-0 Type: Static
Build Mergable Library: No
Create Merged Binary: Manual
Skip Install: No
Build Libraries For Distribution: Yes
The two .xcframework files are in the Target's folder structure as well. The "Link Binary With Libraries" build phase includes them and they're Required.
Inside of the ExampleKit target, I have a single public struct which has two static properties which return the example strings from FrameworkA and FrameworkB.
I then have another script which generates an XCFramework from this target.
Expectations
Based on Apple's documentation and the "Meet Mergable Libraries" WWDC session I would expect that I could make a simple iOS app, link the ExampleKit.xcframework, import ExampleKit inside of a file, and be able to access the single public struct present in ExampleKit. Unfortunately, all I get is "No such module FrameworkA".
I would expect that FrameworkA and FrameworkB would have been merged into ExampleKit? I'm really unsure of where to go from here in debugging this. And more importantly, is this even a possible thing to do?
Hi,
I’m practicing with NavigationSplitView for macOS and customizing the sidebar. I’ve managed to adjust most parts, but I couldn’t remove the sidebar’s divider. It seems like it’s not possible in modern SwiftUI. My AppKit knowledge is also not very strong.
How can I remove the sidebar divider?
I want to use a plain background. I also solved it by creating my own sidebar, but I wanted to try it using NavigationSplitView.
No real intruduction for this, so I'll get to the point:
All this code is on GitHub: https://github.com/the-trumpeter/Timetaber-for-iWatch
But first, sorry;
/*
I got roasted,
last time I posted;
for not defining my stuff.
This'll be different,
but's gonna be rough;
'cuz there's lots and lots
to get through:
*/
//this is 'Timetaber Watch App/Define (No expressions)/Courses_vDef.swift' on the GitHub:
struct Course {
let name: String
let icon: String
let room: String
let colour: String
let listName: String
let listIcon: String
let joke: String
init(name: String, icon: String, room: String? = nil, colour: String,
listName: String? = nil, listIcon: String? = nil, joke: String? = nil)
{
self.name = name
self.icon = icon
self.room = room ?? "None"
self.colour = colour
self.listName = listName ?? name
self.listIcon = listIcon ?? (icon+".circle.fill")
self.joke = joke ?? ""
}
}
//this is 'Timetaber Watch App/TimeManager_fDef.swift' on the GitHub:
func getCurrentClass(date: Date) -> Array<Course> {
//returns the course in session depending on the input date
//it is VERY long but
//all you really need to know is what it returns:
//basically: return [rightNow, nextUp]
}
/*
I thought that poetry
would be okay,
But poorly thought things through:
For I'll probably find
that people online
will treat my rhymes like spew.
*/
So into the question:
I have a bunch of views, all (intendedly) watching two variables inside of a class:
//Github: 'Timetaber Watch App/TimetaberApp.swift'
class GlobalData: ObservableObject {
@Published var currentCourse: Course = getCurrentClass(date: .now)[0] // the current timetabled class in session.
@Published var nextCourse: Course = getCurrentClass(date: .now)[1] // the next timetabled class in session
}
...and a bunch of views using them in different ways as follows:
(Sorry, don't have the characters to define functions called in these)
import SwiftUI
//Github: 'Timetaber Watch App/Views/HomeView.swift'
struct HomeView: View {
@StateObject var data = GlobalData()
var body: some View {
//HERE:
let icon = data.currentCourse.icon
let name = data.currentCourse.name
let colour = data.currentCourse.colour
let room = roomOrBlank(course: data.currentCourse)
let next = data.nextCourse
VStack {
//CURRENT CLASS
Image(systemName: icon)
.foregroundColor(Color(colour))//add an SF symbol element
.imageScale(.large)
.font(.system(size: 25).weight(.semibold))
Text(name)
.font(.system(size:23).weight(.bold))
.foregroundColor(Color(colour))
.padding(.bottom, 0.1)
//ROOM
Text(room+"\n")
.multilineTextAlignment(.center)
.foregroundStyle(.gray)
.font(.system(size: 15))
if next.name != noSchool.name {
Spacer()
//NEXT CLASS
Text(nextPrefix(course: next))
.font(.system(size: 15))
Text(getNextString(course: next))
.font(.system(size: 15))
.multilineTextAlignment(.center)
}
}.padding()
}
}
// Github: 'Timetaber Watch App/Views/ListView.swift'
struct listTemplate: View {
@StateObject var data = GlobalData()
var listedCourse: Course = failCourse(feedback: "lT.12")
var courseTime: String = ""
init(course: Course, courseTime: String) {
self.courseTime = courseTime
self.listedCourse = course
}
var body: some View {
let localroom = if listedCourse.room == "None" {
"" } else { listedCourse.room }
let image = if listedCourse.listIcon == "custom1" {
Image(.paintbrushPointedCircleFill)
} else { Image(systemName: listedCourse.listIcon) }
HStack{
image
.foregroundColor(Color(listedCourse.colour))
.padding(.leading, 5)
Text(listedCourse.name)
.bold()
Spacer()
Text(courseTime)
Text(localroom).bold().padding(.trailing, 5)
}
.padding(.bottom, 1)
.background(data.currentCourse.name==listedCourse.name ? Color(listedCourse.colour).colorInvert(): nil) //HERE
}
}
struct listedDay: View {
let day: Dictionary<Int, Course>
var body: some View {
let dayKeys = Array(day.keys).sorted(by: <)
List {
ForEach((0...dayKeys.count-2), id: \.self) {
let num = $0
listTemplate(course: day[dayKeys[num]] ?? failCourse(feedback: "lD.53"), courseTime: time24toNormal(time24: dayKeys[num]))
}
}
}
}
struct ListView: View {
var body: some View {
if storage.shared.termRunningGB && weekdayFunc(inDate: .now) != 1
&& weekdayFunc(inDate: .now) != 7 {
ScrollView {
listedDay(
day: getTimetableDay(
isWeekA:
getIfWeekIsA_FromDateAndGhost(
originDate: .now,
ghostWeek: storage.shared.ghostWeekGB
),
weekDay: weekdayFunc(inDate: .now)
)
)
}
} else if !storage.shared.termRunningGB {
Text("There's no term running.\nThe day's classes will be displayed here.")
.multilineTextAlignment(.center)
.foregroundStyle(.gray)
.font(.system(size: 13))
} else {
Text("No school today.\nThe day's classes will be displayed here.")
.multilineTextAlignment(.center)
.foregroundStyle(.gray)
.font(.system(size: 13))
}
}
}
//There's one more view but I can't fit it for characters.
//On GitHub: 'Timetaber Watch App/Views/SettingsView.swift'
So...
THE FUNCTION:
This function is called when changes are made that will affect the correct output of getCurrentClass. It is intended to reload the views and the current/next variables to reflect those changes.\
//GHub: 'Timetaber Watch App/StorageManager.swift'
func reload() -> Void {
@ObservedObject var globalData: GlobalData //this line is erroring, I don't know how to fix it. Is this even the best/proper way to do this?
let courseData = getCurrentClass(date: .now)
globalData.currentCourse = courseData[0]
globalData.nextCourse = courseData[1]
//Variable '_globalData' used by function definition before being initialized
//that is the error appearing on those above two redefinitions.
print("Setup done\n")
}
Thanks!
-Gill
In my app I need to have access to the users desktop, and I would like to implement the standard dialogue for the user to give permission for this access at launch. I do not want to use the NSOpenPanel() for the user to select the desktop, as I dont think that is an elegant solution.
However I am having issues implementing this.
I use the following code to be granted access to the Desktop URL:
let accessGranted = desktopURL.startAccessingSecurityScopedResource()
However no dialogue box appears and the call returns false
I have also included "Desktop Usage Description" in my plist.
Here is my code
@State var message:String = "Good Luck!"
var body: some View {
VStack {
Button("Get Desktop files") {
accessDesktopWithPermission()
}
Text(message)
}
.padding()
}
//: –—–—–—–—–—–—–—–—–—–—–—–—–—–— ://
func accessDesktopWithPermission(){
guard let desktopURL = getDesktopURL() else{
return
}
let accessGranted = desktopURL.startAccessingSecurityScopedResource()
if accessGranted{
if let content = try? FileManager.default.contentsOfDirectory(at: desktopURL, includingPropertiesForKeys: nil ){
message = "Found \(content.count) on Desktop"
}
else{
message = "issue loading file from desktop"
}
}
else{
message = "Access denied to:\(desktopURL )"
}
}
obviously I have setup something incorrectly so I have also attached my code if anyone is interested to take a look.
[https://www.openscreen.co/DesktopAccess.zip)
I have a very simple CoreData model that has 1 entity and 2 attributes.
This code works fine:
.onChange(of: searchText) { _, text in
evnts.nsPredicate = text.isEmpty ? nil :NSPredicate(format: "eventName CONTAINS %@ " , text )
but I'd like to also search with the same text string for my second attribute (which is a Date). I believe an OR is appropriate for two conditions (find either one). See attempted code below:
evnts.nsPredicate = text.isEmpty ? nil : NSPredicate(format: "(eventName CONTAINS %@) OR (dueDate CONTAINS %i) " , text )
This crashes immediately %@ does the same. Is there a way to accomplish this?
How is SwiftUI not an option below?
In Swift 6, stricter concurrency rules can lead to challenges when making SwiftUI views conform to Equatable. Specifically, the == operator required for Equatable must be nonisolated, which means it cannot access @MainActor-isolated properties. This creates an error when trying to compare views with such properties:
Error Example:
struct MyView: View, Equatable {
let title: String
let count: Int
static func ==(lhs: MyView, rhs: MyView) -> Bool {
// Accessing `title` here would trigger an error due to actor isolation.
return lhs.count == rhs.count
}
var body: some View {
Text(title)
}
}
Error Message:
Main actor-isolated operator function '==' cannot be used to satisfy nonisolated protocol requirement; this is an error in the Swift 6 language mode.
Any suggestions?
Thanks
FB: FB15753655 (SwiftUI View cannot conform custom Equatable protocol in Swift 6.)
This is an issue that occurred while using SwiftUI.
Cannot find '$state' in scope
The other view finds properties normally.
May I know why the error is occurring?
The following code is the full text of the code that causes problems.
import SwiftUI
@Observable
class HomeState {
var title: String = "Home"
}
struct HomeView: View {
@Binding var state: HomeState
var body: some View {
Text(state.title)
}
}
#Preview {
@Previewable @State var state: HomeState = .init()
HomeView(state: $state) /// Error: Cannot find '$state' in scope
}
The same error occurs when using the String type rather than the object.
What did I do wrong?
I am experiencing a crash when performing a batch delete and merging changes on a Core Data store that uses NSPersistentCloudKitContainer. The crash appears to be triggered when positive fractional Decimal values are stored in a TransactionSplit entity (those values are aggregated via a derived attribute in the AccountTransaction entity). If I store whole numbers or negative fractional decimals, deletion seems to work correctly. I suspect that the issue is related to the internal representation of positive fractional decimals in conjunction with a derived attribute.
Data Model Setup:
Account (1:N relationship → AccountTransaction)
AccountTransaction (1:N relationship → TransactionSplit), which contains a derived attribute (e.g., “splits.amount.@sum”) that computes the sum over the “amount” attribute on its related TransactionSplit objects.
TransactionSplit, which contains a stored Decimal attribute named “amount” (of type Decimal/NSDecimalNumber).
Steps to Reproduce:
Insert sample data where each TransactionSplit’s “amount” is set to a positive fractional value (e.g., 1000.01), by using code similar to:
func createSampleData() {
// Execute all creation on the context’s queue.
let checkingAccount = Account(context: context)
checkingAccount.id = UUID()
checkingAccount.name = "Main Checking"
let randomTransactionCount = 1000
for _ in 0..<randomTransactionCount {
let transaction = AccountTransaction(context: context)
transaction.id = UUID()
transaction.account = checkingAccount
let randomValue = Double.random(in: 5...5000)
let decimalValue = NSDecimalNumber(value: randomValue)
let split1 = TransactionSplit(context: context)
split1.id = UUID()
split1.amount = decimalValue
split1.transaction = transaction
let split2 = TransactionSplit(context: context)
split2.id = UUID()
split2.amount = decimalValue
split2.transaction = transaction
}
save()
}
The AccountTransaction’s derived attribute automatically aggregates the sum of its related TransactionSplit amounts.
Perform a batch deletion using NSBatchDeleteRequest (with resultType set to .resultTypeObjectIDs) on your entities and merge the changes back into your main context:
private func delete(_ fetchRequest: NSFetchRequest<NSFetchRequestResult>) {
let batchDeleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
batchDeleteRequest.resultType = .resultTypeObjectIDs
// ⚠️ When performing a batch delete we need to make sure we read the result back
// then merge all the changes from that result back into our live view context
// so that the two stay in sync.
if let delete = try? context.execute(batchDeleteRequest) as? NSBatchDeleteResult {
let changes = [NSDeletedObjectsKey: delete.result as? [NSManagedObjectID] ?? []]
NSManagedObjectContext.mergeChanges(fromRemoteContextSave: changes, into: [context])
}
}
Save the context after deletion.
I am trying to implement "Live activity" to my app. I am following the Apple docs.
Link: https://developer.apple.com/documentation/activitykit/displaying-live-data-with-live-activities
Example code:
struct LockScreenLiveActivityView: View {
let context: ActivityViewContext<PizzaDeliveryAttributes>
var body: some View {
VStack {
Spacer()
Text("\(context.state.driverName) is on their way with your pizza!")
Spacer()
HStack {
Spacer()
Label {
Text("\(context.attributes.numberOfPizzas) Pizzas")
} icon: {
Image(systemName: "bag")
.foregroundColor(.indigo)
}
.font(.title2)
Spacer()
Label {
Text(timerInterval: context.state.deliveryTimer, countsDown: true)
.multilineTextAlignment(.center)
.frame(width: 50)
.monospacedDigit()
} icon: {
Image(systemName: "timer")
.foregroundColor(.indigo)
}
.font(.title2)
Spacer()
}
Spacer()
}
.activitySystemActionForegroundColor(.indigo)
.activityBackgroundTint(.cyan)
}
}
Actually, the code is pretty straightforward. We can use the timerInterval for count-down animation. But when the timer ends, I want to update the Live Activity view. If the user re-opens the app, I can update it, but what happens if the user doesn't open the app? Is there a way to update the live activity without using push notifications?
I’m trying to create a property wrapper that that can manage shared state across any context, which can get notified if changes happen from somewhere else.
I'm using mutex, and getting and setting values works great. However, I can't find a way to create an observer pattern that the property wrappers can use.
The problem is that I can’t trigger a notification from a different thread/context, and have that notification get called on the correct thread of the parent object that the property wrapper is used within.
I would like the property wrapper to work from anywhere: a SwiftUI view, an actor, or from a class that is created in the background. The notification preferably would get called synchronously if triggered from the same thread or actor, or otherwise asynchronously. I don’t have to worry about race conditions from the notification because the state only needs to reach eventuall consistency.
Here's the simplified pseudo code of what I'm trying to accomplish:
// A single source of truth storage container.
final class MemoryShared<Value>: Sendable {
let state = Mutex<Value>(0)
func withLock(_ action: (inout Value) -> Void) {
state.withLock(action)
notifyObservers()
}
func get() -> Value
func notifyObservers()
func addObserver()
}
// Some shared state used across the app
static let globalCount = MemoryShared<Int>(0)
// A property wrapper to access the shared state and receive changes
@propertyWrapper
struct SharedState<Value> {
public var wrappedValue: T {
get { state.get() }
nonmutating set { // Can't set directly }
}
var publisher: Publisher {}
init(state: MemoryShared) {
// ...
}
}
// I'd like to use it in multiple places:
@Observable
class MyObservable {
@SharedState(globalCount)
var count: Int
}
actor MyBackgroundActor {
@SharedState(globalCount)
var count: Int
}
@MainActor
struct MyView: View {
@SharedState(globalCount)
var count: Int
}
What I’ve Tried
All of the examples below are using the property wrapper within a @MainActor class. However the same issue happens no matter what context I use the wrapper in: The notification callback is never called on the context the property wrapper was created with.
I’ve tried using @isolated(any) to capture the context of the wrapper and save it to be called within the state in with unchecked sendable, which doesn’t work:
final class MemoryShared<Value: Sendable>: Sendable {
// Stores the callback for later.
public func subscribe(callback: @escaping @isolated(any) (Value) -> Void) -> Subscription
}
@propertyWrapper
struct SharedState<Value> {
init(state: MemoryShared<Value>) {
MainActor.assertIsolated() // Works!
state.subscribe {
MainActor.assertIsolated() // Fails
self.publisher.send()
}
}
}
I’ve tried capturing the isolation within a task with AsyncStream. This actually compiles with no sendable issues, but still fails:
@propertyWrapper
struct SharedState<Value> {
init(isolation: isolated (any Actor)? = #isolation, state: MemoryShared<Value>) {
let (taskStream, continuation) = AsyncStream<Value>.makeStream()
// The shared state sends new values to the continuation.
subscription = state.subscribe(continuation: continuation)
MainActor.assertIsolated() // Works!
let task = Task {
_ = isolation
for await value in taskStream {
_ = isolation
MainActor.assertIsolated() // Fails
}
}
}
}
I’ve tried using multiple combine subjects and publishers:
final class MemoryShared<Value: Sendable>: Sendable {
let subject: PassthroughSubject<T, Never> // ...
var publisher: Publisher {} // ...
}
@propertyWrapper
final class SharedState<Value> {
var localSubject: Subject
init(state: MemoryShared<Value>) {
MainActor.assertIsolated() // Works!
handle = localSubject.sink {
MainActor.assertIsolated() // Fails
}
stateHandle = state.publisher.subscribe(localSubject)
}
}
I’ve also tried:
Using NotificationCenter
Making the property wrapper a class
Using NSKeyValueObserving
Using a box class that is stored within the wrapper.
Using @_inheritActorContext.
All of these don’t work, because the event is never called from the thread the property wrapper resides in.
Is it possible at all to create an observation system that notifies the observer from the same context as where the observer was created?
Any help would be greatly appreciated!
For some time now Xcode has been downloading crash reports from users of my app about crashes related to arrays. One of them looks like this:
...
Code Type: ARM-64
Parent Process: launchd [1]
User ID: 501
Date/Time: 2024-07-18 14:59:40.4375 +0800
OS Version: macOS 15.0 (24A5289h)
...
Crashed Thread: 0
Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000001, 0x00000001045048b8
Termination Reason: Namespace SIGNAL, Code 5 Trace/BPT trap: 5
Terminating Process: exc handler [1771]
Thread 0 Crashed:
0 MyApp 0x00000001045048b8 specialized Collection.map<A>(_:) + 596
1 MyApp 0x00000001045011e4 MyViewController.validateToolbarButtons() + 648 (MyViewController.swift:742)
...
The relevant code looks like this:
class MyViewController {
func validateToolbarButtons() {
let indexes = tableView.clickedRow == -1 || tableView.selectedRowIndexes.contains(tableView.clickedRow) ? tableView.selectedRowIndexes : IndexSet(integer: tableView.clickedRow)
let items = indexes.map({ myArray[$0] })
...
}
}
The second crash looks like this:
...
Code Type: X86-64 (Native)
Parent Process: launchd [1]
User ID: 502
Date/Time: 2024-07-15 15:53:35.2229 -0400
OS Version: macOS 15.0 (24A5289h)
...
Crashed Thread: 0
Exception Type: EXC_BAD_INSTRUCTION (SIGILL)
Exception Codes: 0x0000000000000001, 0x0000000000000000
Termination Reason: Namespace SIGNAL, Code 4 Illegal instruction: 4
Terminating Process: exc handler [13244]
Thread 0 Crashed:
0 libswiftCore.dylib 0x00007ff812904fc0 _assertionFailure(_:_:flags:) + 288
1 MyApp 0x0000000101a31e04 specialized _ArrayBuffer._getElementSlowPath(_:) + 516
2 MyApp 0x00000001019d04eb MyObject.myProperty.setter + 203 (MyObject.swift:706)
3 MyApp 0x000000010192f66e MyViewController.controlTextDidChange(_:) + 190 (MyViewController.swift:166)
...
And the relevant code looks like this:
class MyObject {
var myProperty: [MyObject] {
get {
...
}
set {
let items = newValue.map({ $0.id })
...
}
}
}
What could cause such crashes? Could they be caused by anything other than concurrent access from multiple threads (which I'm quite sure is not the case here, as I only access these arrays from the main thread)?
In my app, I've been using ModelActors in SwiftData, and using actors with a custom executor in Core Data to create concurrency safe services.
I have multiple actor services that relate to different data model components or features, each that have their own internally managed state (DocumentService, ImportService, etc).
The problem I've ran into, is that I need to be able to use multiple of these services within another service, and those services need to share the same context. Swift 6 doesn't allow passing contexts across actors.
The specific problem I have is that I need a master service that makes multiple unrelated changes without saving them to the main context until approved by the user.
I've tried to find a solution in SwiftData and Core Data, but both have the same problem which is contexts are not sendable. Read the comments in the code to see the issue:
/// This actor does multiple things without saving, until committed in SwiftData.
@ModelActor
actor DatabaseHelper {
func commitChange() throws {
try modelContext.save()
}
func makeChanges() async throws {
// Do unrelated expensive tasks on the child context...
// Next, use our item service
let service = ItemService(modelContainer: SwiftDataStack.shared.container)
let id = try await service.expensiveBackgroundTask(saveChanges: false)
// Now that we've used the service, we need to access something the service created.
// However, because the service created its own context and it was never saved, we can't access it.
let itemFromService = context.fetch(id) // fails
// We need to be able to access changes made from the service within this service,
/// so instead I tried to create the service by passing the current service context, however that results in:
// ERROR: Sending 'self.modelContext' risks causing data races
let serviceFromContext = ItemService(context: modelContext)
// Swift Data doesn't let you create child contexts, so the same context must be used in order to change data without saving.
}
}
@ModelActor
actor ItemService {
init(context: ModelContext) {
modelContainer = SwiftDataStack.shared.container
modelExecutor = DefaultSerialModelExecutor(modelContext: context)
}
func expensiveBackgroundTask(saveChanges: Bool = true) async throws -> PersistentIdentifier? {
// Do something expensive...
return nil
}
}
Core Data has the same problem:
/// This actor does multiple things without saving, until committed in Core Data.
actor CoreDataHelper {
let parentContext: NSManagedObjectContext
let context: NSManagedObjectContext
/// In Core Data, I can create a child context from a background context.
/// This lets you modify the context and save it without updating the main context.
init(progress: Progress = Progress()) {
parentContext = CoreDataStack.shared.newBackgroundContext()
let childContext = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
childContext.parent = parentContext
self.context = childContext
}
/// To commit changes, save the parent context pushing them to the main context.
func commitChange() async throws {
// ERROR: Sending 'self.parentContext' risks causing data races
try await parentContext.perform {
try self.parentContext.save()
}
}
func makeChanges() async throws {
// Do unrelated expensive tasks on the child context...
// As with the Swift Data example, I am unable to create a service that uses the current actors context from here.
// ERROR: Sending 'self.context' risks causing data races
let service = ItemService(context: self.context)
}
}
Am I going about this wrong, or is there a solution to fix these errors?
Some services are very large and have their own internal state. So it would be very difficult to merge all of them into a single service. I also am using Core Data, and SwiftData extensively so I need a solution for both.
I seem to have trapped myself into a corner trying to make everything concurrency save, so any help would be appreciated!
Hello,
I am developing a visionOS application and am interested in obtaining detailed data of users’ hands through ARKit, including but not limited to Transform and rotation angle. I have reviewed Happy Beem, but it appears to only introduce the method of identifying the user’s specific gestures.
Could you please advise on how to obtain the Transform and rotation angle of the user’s hand?
Thank you.
I am writing a SPM based project for MacOS. In this project? I need to access MacOS Keychain.
I am write a swift test built by SPM testTarget(). I can see it generates a bundle ./.build/x86_64-apple-macosx/debug/MyProjectTests.xctest with an executable:
% file ./.build/x86_64-apple-macosx/debug/MyProjectPackageTests.xctest/Contents/MacOS/MyProjectPackageTests
./.build/x86_64-apple-macosx/debug/MyProjectPackageTests.xctest/Contents/MacOS/MyProjectPackageTests: Mach-O 64-bit bundle x86_64
This bundle file cannot be executed. How can I execute its tests?
I tried with xcodebuild test-without-building -xctestrun ./.build/x86_64-apple-macosx/debug/MyProjectPackageTests.xctest -destination 'platform=macOS' without any chance.
Obviously the next question is can I 'simply' add entitlement to this bundle with codesign to fix my enttilement error.
My error when running the test is A required entitlement isn't present.
Hi all, I am looking for a futureproof way of getting the Screen Resolution of my display device using SwiftUI in MacOS. I understand that it can't really be done to the fullest extent, meaning that the closest API we have is the GeometeryProxy and that would only result in the resolution of the parent view, which in the MacOS case would not give us the display's screen resolution. The only viable option I am left with is NSScreen.frame.
However, my issue here is that it seems like Apple is moving towards SwiftUI aggressively, and in order to futureproof my application I need to not rely on AppKit methods as much. Hence, my question: Is there a way to get the Screen Resolution of a Display using SwiftUI that Apple itself recommends? If not, then can I rely safely on NSScreen's frame API?