Post

Replies

Boosts

Views

Activity

How to make an entity move in a RealityView so that collisions can be detected
I'm trying to detect when two entities collide. The following code shows a very basic set-up. How do I get the upperSphere to move? If I set its physicsBody.mode to .dynamic it moves with gravity (and the collision is reported), but when in kinematic mode it doesn't respond to the impulse: struct CollisionView: View { @State var subscriptions: [EventSubscription] = [] var body: some View { RealityView { content in let upperSphere = ModelEntity(mesh: .generateSphere(radius: 0.04)) let lowerSphere = ModelEntity(mesh: .generateSphere(radius: 0.04)) upperSphere.position = [0, 2, -2] upperSphere.physicsBody = .init() upperSphere.physicsBody?.mode = .kinematic upperSphere.physicsMotion = PhysicsMotionComponent() upperSphere.generateCollisionShapes(recursive: false) lowerSphere.position = [0, 1, -2] lowerSphere.physicsBody = .init() lowerSphere.physicsBody?.mode = .static lowerSphere.generateCollisionShapes(recursive: false) let sub = content.subscribe(to: CollisionEvents.Began.self, on: nil) { _ in print("Collision!") } subscriptions.append(sub) content.add(upperSphere) content.add(lowerSphere) Task { try? await Task.sleep(for: .seconds(2)) print("Impulse applied") upperSphere.applyLinearImpulse([0, -1, 0], relativeTo: nil) } } } }
3
0
163
1d
Passing locale into a RegexBuilder as a parameter
I am building a tokeniser, and would like to hold this as a struct, passing in a locale during initiation. Here's the gist of what I would want to write: struct Tokeniser { private let locale: Locale private let integerRegex: Regex init(locale: Locale) { self.locale: Locale self.integerRegex = Regex { Capture { .localizedInteger(locale: locale) } transform: { Token.number($0) } } } func parse(text: String) -> Token { if let match = try integerRegex.firstMatch(in: text) { //... other code here } } \\...other code here } As Regex is generic the compiler suggests to set the integerRegex's type to Regex<Any>, but this triggers another set of compiler issues that I have not been able to figure out what the type should be. So then I tried to write something like this (inspired by SwiftUI): var integerRegex: some Regex { Capture { .localizedInteger(locale: locale) } transform: { Token.number($0) } } But again, the compiler prompts me to enter Regex. The only way I have to be able to get the struct to compiler is to create lazy variables, which then have the side effect that I have to mark my functions as mutable, which have downstream issues when they are called from with SwiftUI structs. lazy var integerRegex = Regex { Capture { .localizedInteger(locale: locale) } } mutating func parse(text: String) -> Token { if let match = try integerRegex.firstMatch(in: text) { } } How can I code this?
0
0
182
Oct ’23
Issues testing StoreKit in Xcode after AppBundle ID change
I'm developing across two Macs: one Apple Silicon and an Intel laptop (used for performance and compatibility testing). I've been testing my StoreKit2 implementation, and have come across a couple of issues. From time to time something appears to become corrupted, and StoreKit2 says it has a 'connection' issue. Deleting the folder com.apple.storekitagent, which a sub folder Octane, restarting the machine appears to fix this. The second issue I cannot appear to resolve. I have needed to change the App Bundle ID. I did this whilst developing on the M2 Mac without problem. But now when I try and run back on the Intel Mac I am getting a set of unfinished transactions which I can either process, nor delete (they are not appearing in Xcode's StoreKit debug window. I've tried deleting the folder com.apple.storekitagent, and restarting the machine, but to no avail. Note if I reset back to my original App Bundle ID then all works as before. Here is a sample of errors I am receiving: Error finishing transaction 110: Error Domain=ASDErrorDomain Code=500 "Unhandled exception" UserInfo={NSUnderlyingError=0x600001863cf0 {Error Domain=AMSErrorDomain Code=301 "Invalid Status Code" UserInfo={NSLocalizedDescription=Invalid Status Code, AMSURL=http://localhost:49242/WebObjects/MZFinance.woa/wa/inAppTransactionDone?REDACTED, AMSStatusCode=404, AMSServerPayload={ error = "Transaction not found"; }, NSLocalizedFailureReason=The response has an invalid status code}}, storefront-country-code=USA, client-environment-type=XcodeTest(file:///Users/peggers/Library/Caches/com.apple.storekitagent/Octane/com.bristolbaycodefactory.photo-organista/), AMSServerErrorCode=0, NSLocalizedFailureReason=An unknown error occurred, NSLocalizedDescription=Unhandled exception} Any further ideas on how to reset or solve this issue?
0
1
569
Mar ’23
Security scoped bookmark and external drives
I'm writing a photo management app where the document stores the location of folders (in which image files reside). These are added by the user, and saved as security scoped bookmarks. All this appeared to be working. However, I tested a use-case where the user starts working on one machine where they add a folder, which resides on an external drive. This works, as long as they remain the on the same machine. However, if they move to another machine, plug in the external drive and then load up the document it fails to resolve the bookmark, throws the following error: Error Domain=NSCocoaErrorDomain Code=259 "The file couldn’t be opened because it isn’t in the correct format." For completeness here is the code to resolve the bookmark: do { let url = try URL( resolvingBookmarkData: data, options: Self.bookmarkResolutionOptions, relativeTo: nil, bookmarkDataIsStale: &amp;isStale ) } catch { print(error) /// ... error handling code here } Do I therefore assume that I cannot achieve this, and will have to ask the user to re-authorise this folder on the second machine?
0
0
977
Nov ’22
What does this TSAN exception indicate?
When I run my code with TSAN enabled I am getting an EXC_BAD_ACCESS exception thrown. I am seeing the following error in debug navigator: #0 0x0000000104becb44 in __tsan::ThreadClock::release(__tsan::DenseSlabAllocCache*, __tsan::SyncClock*) () The stack trace is not in my code. Without TSAN I am seeing the following in the console: (Fig) signalled err=-16993 Anybody seen this before? This is under the new Beta 6 Xcode running under Ventura 13.0 Beta (22A5331f), on an M1 Mac.
1
1
794
Aug ’22
GlobalActor directive doesn't guarantee a function will be called on that actor?
Assuming I have defined a global actor: @globalActor actor MyActor { static let shared = MyActor() } And I have a class, in which a couple of methods need to act under this: class MyClass { @MyActor func doSomething(undoManager: UndoManager) { // Do something here undoManager?.registerUndo(withTarget: self) { $0.reverseSomething(undoManager: UndoManager) } } @MyActor func reverseSomething(undoManager: UndoManager) { // Do the reverse of something here print(\(Thread.isMainThread) /// Prints true when called from undo stack undoManager?.registerUndo(withTarget: self) { $0.doSomething(undoManager: UndoManager) } } } Assume the code gets called from a SwiftUI view: struct MyView: View { @Environment(\.undoManager) private var undoManager: UndoManager? let myObject: MyClass var body: some View { Button("Do something") { myObject.doSomething(undoManager: undoManager) } } } Note that when the action is undone the 'reversing' func it is called on the MainThread. Is the correct way to prevent this to wrap the undo action in a task? As in: @MyActor func reverseSomething(undoManager: UndoManager) { // Do the reverse of something here print(\(Thread.isMainThread) /// Prints true undoManager?.registerUndo(withTarget: self) { Task { $0.doSomething(undoManager: UndoManager) } } }
0
0
787
Jul ’22
GCD TSAN issue: Data race in generic specialization <Foundation.UUID>
The XCODE TSAN thread analyser is throwing up a threading issue: Data race in generic specialization <Foundation.UUID> of Swift._NativeSet.insertNew(_: __owned τ_0_0, at: Swift._HashTable.Bucket, isUnique: Swift.Bool) -> () at 0x10a16b300 This only occurs in a release build, and its Data race in generic specialization that has my attention. It pin-points the addID function. But I cannot see the issue. Here is the relevant code snippet: final class IDBox { let syncQueue = DispatchQueue(label: "IDBox\(UUID().uuidString)", attributes: .concurrent) private var _box: Set<UUID> init() { self._box = [] } var box: Set<UUID> { syncQueue.sync { self._box } } func addID(_ id: UUID) { syncQueue.async(flags: .barrier) { self._box.insert(id) } } }
0
0
506
May ’22
NSFilePresenter update not firing on iPad - does on Mac with identical code.
I am writing an App with both Mac and iPad versions that saves its state to a file. The user can store the file in their iCloud and open it both on the Mac and iPad simultaneously. If an update is made on either device the other will update their state to match. This has been achieved using an NSFilePresenter / NSFileCoordinator approach. Both platforms are using identical code. At present when I make a change on the iPad, a few moments later the Mac updates as expected. However, this does not happen the other way around. If I update the data on the Mac the iPad never appears to receive an update. I've tried this on the simulator also. I get similar behaviour, but can get the iPad to update it I use the simulator's Sync With iCloud function. Any ideas of what I may be doing wrong - as clearly the code works in one direction!
1
0
1.3k
Feb ’22
SwiftUI app outputting CVDisplayLink related messages to console?
I'm getting a lot of output on the console as I run a MacOS based SwiftUI app I'm developing, for example: 2021-12-08 12:40:14.439565+0000 SpDriveApp[6801:159299] [] [0x7fe6e7830820] CVCGDisplayLink::setCurrentDisplay: 1892262333 2021-12-08 12:40:14.439785+0000 SpDriveApp[6801:159299] [] [0x7fe6e7830800] CVDisplayLinkCreateWithCGDisplays count: 1 [displayID[0]: 0x70c9a1bd] [CVCGDisplayLink: 0x7fe6e7830820] 2021-12-08 12:40:14.439827+0000 SpDriveApp[6801:159299] [] [0x7fe6e7830800] CVDisplayLinkStart 2021-12-08 12:40:14.439853+0000 SpDriveApp[6801:159299] [] [0x7fe6e7830820] CVDisplayLink::start 2021-12-08 12:40:14.439993+0000 SpDriveApp[6801:182706] [] [0x60000f698460] CVXTime::reset Has anyone else seen this? Have I accidentally switched on a diagnostic tool, or is there something else I am doing wrong?
11
0
3k
Dec ’21
Running FileManager.default.enumerator on different tasks
I'm writing a function where a directory and its descendants are scanned to produce a list of files. The function is part of a class, FileScanner. Here's a simplified version of the function: func scanFolder(_ folderURL: URL) async { // Set up configuration for directory search, varies based on need to search sub directories let resourceKeysArray: [URLResourceKey] = [.nameKey, .isDirectoryKey, .fileResourceTypeKey, .creationDateKey, .contentModificationDateKey, .contentTypeKey] let resourceKeysSet = Set&lt;URLResourceKey&gt;(resourceKeysArray) let options = FileManager.DirectoryEnumerationOptions(arrayLiteral: [.skipsHiddenFiles, .skipsPackageDescendants]) if let enumerator = FileManager.default.enumerator(at: folderURL, includingPropertiesForKeys: resourceKeysArray, options: options) { await folderScanStatus.markRunning() while await !folderScanStatus.cancelled, let fileURL = enumerator.nextObject() as? URL { print("\(id) found \(fileURL.path)") // Logging for debug purposes foundFiles.append(fileURL) } } } The code is async, as it has to call some async functions (I've left a couple in for illustration.) The user can have multiple scans in process simultaneously. For each one a new FileScanner is created, and de-inited once the scan has completed - the results are copied across elsewhere. scanFolder is called from within a Task: Task { await scanFolder(someURL) } I am finding that if two of these processes run at once, they can actually interfere with each other - i.e. one can scan the directory of the other. I added some logging to highlight the issue. The log line shows the ID of the scanner, and the file it has found. In this run there were two scanners: EDF43558-608E-47A4-81E5-97B9707B1D0F, scanning /Volumes/Back-up A/ 982EC712-D79E-4785-A1BA-3B53F85967F0, scanning /Users/TEST/ And here's some extracts from the log showing them working as expected: 982EC712-D79E-4785-A1BA-3B53F85967F0 found /Users/TEST/Files/R_24_04-04.txt EDF43558-608E-47A4-81E5-97B9707B1D0F found /Volumes/Back-up A/180704f01.txt And here's an example showing Scanner 982EC712-D79E-4785-A1BA-3B53F85967F0 finding a file that the other one also picked up: 982EC712-D79E-4785-A1BA-3B53F85967F0 found /Volumes/Back-up A/19839f92.txt : EDF43558-608E-47A4-81E5-97B9707B1D0F found /Volumes/Back-up A/19839f92.txt Any ideas why this is happening? I was under the impression FileManager was thread safe?
3
0
1.6k
Nov ’21
Swift value type semantics and impact of bindings
I was recently looking at Apple's sample code for a ReferenceFileDocument based SwiftUI document app: Building a Document-Based App with SwiftUI The two main data types, Checklist and ChecklistItem, are defined as structs. There is also a helper struct BindingCollection that converts a binding to a collection of elements into a collection of bindings to the individual elements. The app relies on bindings to these structs. However, in some ways, isn't a binding to a struct circumnavigating value-type semantics? Any piece of code that is passed the Binding can alter the value, rather than a copy of the value? How does SwiftUI know that the struct has been updated without a publisher? Last question: if I'd been writing this app myself, I would have made Checklist a class, conforming to ObservableObject publishing its items property. This would have avoided the helper function, and use of bindings. What are the benefits of the struct / binding approach in the example code?
0
0
608
Aug ’21
MainActor.run failing to run closure when called from within a detached task
I have encountered an issue when trying to update the status of a detached task, by passing a closure to MainActor.run. To illustrate the issue consider a function that counts the number of files in a folder and its sub-directories. It runs in a Task.detached closure, as I don't want it blocking the main thread. Every 10,000th file it updates a Published property fileCount, by passing a closure to MainThread.run. However, the UI is failing to update and even giving me a spinning beach ball. The only way to stop this is by inserting await Task.sleep(1_000_000_000) before the call to MainThread.run. Here's the code: final class NewFileCounter: ObservableObject { @Published var fileCount = 0 func findImagesInFolder(_ folderURL: URL) { let fileManager = FileManager.default Task.detached { var foundFileCount = 0 let options = FileManager.DirectoryEnumerationOptions(arrayLiteral: [.skipsHiddenFiles, .skipsPackageDescendants]) if let enumerator = fileManager.enumerator(at: folderURL, includingPropertiesForKeys: [], options: options) { while let _ = enumerator.nextObject() as? URL { foundFileCount += 1 if foundFileCount % 10_000 == 0 { let fileCount = foundFileCount await Task.sleep(1_000_000_000) // <-- Only works with this in...comment out to see failure await MainActor.run { self.fileCount = fileCount } } } let fileCount = foundFileCount await MainActor.run { self.fileCount = fileCount } } } } } The code works if I revert to the old way of achieving this: final class OldFileCounter: ObservableObject { @Published var fileCount = 0 func findImagesInFolder(_ folderURL: URL) { let fileManager = FileManager.default DispatchQueue.global(qos: .userInitiated).async { let options = FileManager.DirectoryEnumerationOptions(arrayLiteral: [.skipsHiddenFiles, .skipsPackageDescendants]) var foundFileCount = 0 if let enumerator = fileManager.enumerator(at: folderURL, includingPropertiesForKeys: [], options: options) { while let _ = enumerator.nextObject() as? URL { foundFileCount += 1 if foundFileCount % 10_000 == 0 { let fileCount = foundFileCount DispatchQueue.main.async { self.fileCount = fileCount } } } let fileCount = foundFileCount DispatchQueue.main.async { self.fileCount = fileCount } } } } } What am I doing wrong? BTW - if you want to try out this code, here is a test harness. Be sure to pick a folder with lots of files in it and its sub-folders. import SwiftUI @main struct TestFileCounterApp: App { var body: some Scene { WindowGroup { ContentView() } } } struct ContentView: View { @State private var showPickerOld = false @StateObject private var fileListerOld = OldFileCounter() @State private var showPickerNew = false @StateObject private var fileListerNew = NewFileCounter() var body: some View { VStack { Button("Select folder to count files using DispatchQueue...") { showPickerOld = true } Text("\(fileListerOld.fileCount)").foregroundColor(.green) .fileImporter(isPresented: $showPickerOld, allowedContentTypes: [.folder], onCompletion: processOldSelectedURL ) Divider() Button("Select folder to count files using Swift 5.5 concurrency...") { showPickerNew = true } Text("\(fileListerNew.fileCount)").foregroundColor(.green) .fileImporter(isPresented: $showPickerNew, allowedContentTypes: [.folder], onCompletion: processNewSelectedURL ) } .frame(width: 400, height: 130) } private func processOldSelectedURL(_ result: Result<URL, Error>) { switch result { case .success(let url): fileListerOld.findImagesInFolder(url) case .failure: return } } private func processNewSelectedURL(_ result: Result<URL, Error>) { switch result { case .success(let url): fileListerNew.findImagesInFolder(url) case .failure: return } } }```
7
0
2.5k
Aug ’21
SwiftUI macOS document app architecture in a concurrent world
I'm trying to figure out the correct structure for a macOS document app using SwiftUI and Swift 5.5 concurrency features. I want to demonstrate updating a document's data asynchronously, in a thread safe manner, with the ability to read / write the data to a file, also thread-safe and in the background. Yet I am struggling to: write clean code - some of it looks inelegant at best, more like clunky, compared to my prior apps which used DispatchQueues etc implement Codeable conformance for an actor I'm seeking ideas, corrections and advice on how to improve on this. I've posted the full code over at GitHub, as I will only highlight some particular elements here. This is a minimum viable app, just for proof-of-concept purposes. The app The app displays a list of Records with a button to add more. It should be able to save and reload the list from a file. Current approach / design I've chosen the ReferenceFileDocument protocol for the Document type, as this is what I would use in a future app which has a more complex data structure. (i.e. I'm not planning on using a pure set of structs to hold a documents' data) Document has a property content of type RecordsModelView representing the top-level data structure. RecordsModelView is annotated with @MainActor to ensure any updates it receives will be processed on the main thread. RecordsModelView has a property of type RecordsModel. This is an actor ensuring read/write of its array of Records are thread safe, but not coordinated via the MainActor for efficiency. The app assumes that the func to add an item takes a long time, and hence runs it from with a Task. Although not demonstrated here, I am also making the assumption that addRecord maybe called from multiple background threads, so needs to be thread safe, hence the use of an actor. The code compiles and runs allowing new items to be added to the list but... Issues Firstly, I can't annotate Document with @MainActor - generates compiler errors I cannot resolve. If I could I think it might solve some of my issues... Secondly, I therefore have a clunky way for Document to initialise its content property (which also has to be optional to make it work). This looks nasty, and has the knock on effect of needing to unwrap it everywhere it is referenced: final class Document: ReferenceFileDocument { @Published var content: RecordsViewModel? init() { Task { await MainActor.run { self.content = RecordsViewModel() } } } // Other code here } Finally, I can't get the RecordsModel to conform to Encodable. I've tried making encode(to encoder: Encoder) async, but this does not resolve the issue. At present, therefore RecordsModel is just conformed to Decodable. func encode(to encoder: Encoder) async throws { // <-- Actor-isolated instance method 'encode(to:)' cannot be used to satisfy a protocol requirement var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(records, forKey: .records) }
1
0
1.7k
Aug ’21