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?
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
Is there anyway to suppress the very verbose console output I am getting with MacOS Monterey and SwiftUI code? Here's a snippet of the output:
2021-07-20 09:58:18.267602+0100 BBCFTEST[19341:1880374] IMKInputSession (deactivate) CFRunLoopObserver kCFRunLoopExit (State change BEGIN) - innerRunLoopCount=1, otherInnerRunLoopDetected=0
2021-07-20 09:58:18.267637+0100 BBCFTEST[19341:1880374] IMKInputSession (deactivate) CFRunLoopObserver kCFRunLoopExit (State change END) - innerRunLoopCount=0, otherInnerRunLoopDetected=0
2021-07-20 09:58:18.270063+0100 BBCFTEST[19341:1880374] IMKInputSession (deactivate) CFRunLoopRunInMode exited, (kCFRunLoopRunStopped)
2021-07-20 09:58:18.270109+0100 BBCFTEST[19341:1880374] IMKInputSession (deactivate) CFRunLoopRunInMode (kIMKXPCPrivateRunLoopMode) ] RunLoopFinished(1)/Stopped(2) - Run result = 2, (Invocation already done = 1) (Sentinel IsZombie = 0)
2021-07-20 09:58:18.270147+0100 BBCFTEST[19341:1880374] IMKInputSession (deactivate) CFRunLoopRunInMode() LOOP DONE!
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
}
}
}```
I'm trying to understand a design pattern for accessing the isolated state held in an actor type from within a SwiftUI view.
Take this naive code:
actor Model: ObservableObject {
@Published var num: Int = 0
func updateNumber(_ newNum: Int) {
self.num = newNum
}
}
struct ContentView: View {
@StateObject var model = Model()
var body: some View {
Text("\(model.num)") // <-- Compiler error: Actor-isolated property 'num' can not be referenced from the main actor
Button("Update number") {
Task.detached() {
await model.updateNumber(1)
}
}
}
}
Understandably I get the compiler error Actor-isolated property 'num' can not be referenced from the main actor when I try and access the isolated value. Yet I can't understand how to display this data in a view. I wonder if I need a ViewModel that observes the actor, and updates itself on the main thread, but get compile time error Actor-isolated property '$num' can not be referenced from a non-isolated context.
class ViewModel: ObservableObject {
let model: Model
@Published var num: Int
let cancellable: AnyCancellable
init() {
let model = Model()
self.model = model
self.num = 0
self.cancellable = model.$num // <-- compile time error `Actor-isolated property '$num' can not be referenced from a non-isolated context`
.receive(on: DispatchQueue.main)
.sink { self.num = $0 }
}
}
Secondly, imagine if this code did compile, then I would get another error when clicking the button that the interface is not being updated on the main thread...again I'm not sure how to effect this from within the actor?
Given that type UUID is a struct I thought it would be Sendable. But the compiler generates a warning:
struct S: Sendable {
var int: Int
var id: UUID // <-- Stored property 'id' of 'Sendable'-conforming struct 'S' has non-sendable type 'UUID'
}
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<URLResourceKey>(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?
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)
}
}
}
}
Topic:
Graphics & Games
SubTopic:
RealityKit
Hello,
I am looking to create a shader to update an entity's rendering. As a basic example say I want to recolour an entity, but leave its original textures showing through:
I understand with VisionOS I need to use Reality Composer Pro to create the shader, but I'm lost as how to reference the original colour that I'm trying to update in the node graph. All my attempts appear to completely override the textures in the entity (and its sub-entities) that I want to impact. Also the tutorials / examples I've looked at appear to create materials, not add an effect on top of existing materials.
Any hints or pointers?
Assuming this is possible, I've been trying to load the material in code, and apply to an entity. But do I need to do this to all child entities, or just the topmost?
do {
let entity = MyAssets.createModelEntity(.plane) // Loads from bundle and performs config
let material = try await ShaderGraphMaterial(named: "/Root/TestMaterial", from: "Test", in: realityKitContentBundle)
entity.applyToChildren {
$0.components[ModelComponent.self]?.materials = [material]
}
root.addChild(entity)
} catch {
fatalError(error.localizedDescription)
}
Topic:
Spatial Computing
SubTopic:
Reality Composer Pro
Tags:
RealityKit
Reality Composer Pro
Shader Graph Editor
visionOS
I'm unable to compile my project for UnitTests at present - get a load of Cannot Find XXXXX in Scope errors.
Anybody else getting this, or ideas of how to resolve.
I've tried cleaning the build folder, restarting Xcode, checking my unit test code file is only a member of the test target.
Code compiles for the debug and production builds.
I am unable to get VisionOS 2.0 (simulator) to receive the GCControllerDidConnect notification and thus am unable to setup support for a gamepad. However, it works in VisionOS 1.2.
For VisionOS 2.0 I've tried adding:
.handlesGameControllerEvents(matching: .gamepad) attribute to the view
Supports Controller User Interaction to Info.plist
Supported game controller types -> Extended Gamepad to Info.plist
...but the notification still doesn't fire. It does when the code is run from VisionOS 1.2 simulator, both of which have the Send Game Controller To Device option enabled.
Here is the example code. It's based on the Xcode project template. The only files updated were ImmersiveView.swift and Info.plist, as detailed above:
import SwiftUI
import GameController
import RealityKit
import RealityKitContent
struct ImmersiveView: View {
var body: some View {
RealityView { content in
// Add the initial RealityKit content
if let immersiveContentEntity = try? await Entity(named: "Immersive", in: realityKitContentBundle) {
content.add(immersiveContentEntity)
}
NotificationCenter.default.addObserver(
forName: NSNotification.Name.GCControllerDidConnect,
object: nil, queue: nil) { _ in
print("Handling GCControllerDidConnect notification")
}
}
.modify {
if #available(visionOS 2.0, *) {
$0.handlesGameControllerEvents(matching: .gamepad)
} else {
$0
}
}
}
}
extension View {
func modify<T: View>(@ViewBuilder _ modifier: (Self) -> T) -> some View {
return modifier(self)
}
}
Does anyone have experience of creating their own EntityActions?
Say for example I wanted one that faded up the opacity of an entity, then once it had completed set another property on one of the entity's components.
I understand that I could use the FromToByAction to control the opacity (and have this working), but I am interested to learn how to create my own dedicated EntityAction, and finding the documentation hard to fathom.
I got as far as creating a struct conforming to EntityAction protocol:
var animatedValueType: (any AnimatableData.Type)?
}
Subscribing to update events on this:
FadeUpAction.subscribe(to: .updated) { event in
guard let animationState = event.animationState else {
return
}
// My animation state is always nil, so I never get here!
let newValue = \\\Some Calc...
animationState.storeAnimatedValue(newValue)
}
And setting it up as an animation on an entity:
let action = FadeUpAction()
if let animation = try? AnimationResource.makeActionAnimation(
for:action,
duration: 2.0,
bindTarget: .opacity
) {
entity.playAnimation(animation)
}
...but haven't been able to understand how to extract the current timeDelta or set the value in the event handler.
Any pointers?
Hello,
I am trying to use the subdivision mesh rendering option.
I can see it working in RealityComposerPro:
But not when loading asset and displaying in Simulator:
Using this code:
import SwiftUI
import RealityKit
import RealityKitContent
struct AirspaceView: View {
// MARK: - VIEW BODY
var body: some View {
RealityView { content in
if let a = try? await Entity(named: "Models/Test/Test.usdc", in: realityKitContentBundle) {
content.add(a)
}
}
}
}
Any ideas why?
As I understand it there are two ways I can track a hand, or a joint, in RealityKit:
either, create an AnchorEntity, for example AnchorEntity(.hand(.left, location: .palm))
or, set up an ARSession with a HandTrackingProvider ( a lot more code which I haven't repeated here).
Assuming this is correct, when would I want to use one over the other?
In ARKit for visionOS, I can track the user's head with a HeadAnchor, but it will not give the location. However, I can get the device's transform by calling queryDeviceAnchor(atTimestamp: CACurrentMediaTime()) on a WorldTrackingProvider.
Why the difference? - if I know the device's transform, I effectively know the head's transform.
When using a TextField with axis to set to .vertical on iOS, it sets a bound selection parameter to an erroneous value. Whilst on MacOS it performs as expected.
Take the following code:
import SwiftUI
@main
struct SelectionTestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
@FocusState private var isFocused: Bool
@State private var text = ""
@State private var textSelection: TextSelection? = nil
var body: some View {
TextField("Label", text: $text, selection: $textSelection, axis: .vertical)
.onChange(of: textSelection, initial: true) {
if let textSelection {
print("textSelection = \(textSelection)")
} else {
print("textSelection = nil")
}
}
.focused($isFocused)
.task {
isFocused = true
}
}
}
Running this on MacOS target gives the following on the console:
textSelection = nil
textSelection = TextSelection(indices: SwiftUI.TextSelection.Indices.selection(Range(0[any]..<0[any])), affinity: SwiftUI.TextSelectionAffinity.downstream)
Running the code on iOS gives:
textSelection = TextSelection(indices: SwiftUI.TextSelection.Indices.selection(Range(1[any]..<1[any])), affinity: SwiftUI.TextSelectionAffinity.upstream)
textSelection = TextSelection(indices: SwiftUI.TextSelection.Indices.selection(Range(1[any]..<1[any])), affinity: SwiftUI.TextSelectionAffinity.upstream)
Note here the range is 1..<1 - which is incorrect.
Also of side interest this behaviour changes if you remove the axis parameter:
textSelection = nil
Am I missing something, or is this a bug?