In other words, you do a shallow enumeration of a given directory, then repeat the shallow enumeration on whatever directories you find. This is actually the same thing you'd do with getattrlistbulk.
Right. For some reason I thought it would be less efficient.
Have or haven't? How are you copying files? FYI, if server side copying is an issue, this post has a code snippet for that.
Have. To copy files, I'm just calling copyfile. I didn't know about server-side copying, but that may explain why every now and then a user complains that my app is slow, though they never got back to me explaining their setup or comparing the speed of my app to the that of the Finder.
What's the actual failure? The copy itself failing, display issue(s), etc?
I'm not sure, they simply replied "I just tried [in the Finder] and it did indeed loop!" I assume the "Preparing X files" display when starting a copy operation just kept counting up
On the technical, the resource usage difference can easily be quite large, since "wide" hierarchies are much more common than "deep" hierarchies
That makes sense. My app does a deep scan to determine what files to copy, then copies them, and finally stores the directory hierarchy so it can be compared with the next scan. My users also assume that the app kind of runs in the background and doesn't use too much resources, so I think I'll stick to recursion for now.
Post
Replies
Boosts
Views
Activity
[quote='795660022, DTS Engineer, /thread/759712?answerId=795660022#795660022']
You can check if a particularl file system supports it by looking for "VOL_CAP_INT_COPYFILE" from "getattrlist".
[/quote]
The linked documentation for getattrlist reads
VOL_CAP_INT_COPYFILE If this bit is set the volume format implementation supports the (private and undocumented) copyfile() function.
Is this the same copyfile function we can use today, or something else? Or was it “private and undocumented“ some long time ago?
So when VOL_CAP_INT_COPYFILE is set the volume supports server-side copying, but we still have to figure out if it‘s faster than copyfile, right? How would we check that?
One of it's options is skipsSubdirectoryDescendants, which lets you disable recursion.
But then I get a shallow enumeration. I still want to scan an entire directory hierarchy.
The "copyfile" Unix API will let you do that but the Finder isn't using that either, which is why the Finder can do server side SMB copying, which copyfile cannot
I've noticed that, which is why I've been using copyfile for a long time now myself.
In terms of why the Finder isn't having issue
I think you misunderstood. I said that the Finder is having the same issue.
Thanks. I already created FB15864883 two days ago, but I thought that I must be missing something since it would be unlikely that the invite API would have been around for years without a proper way to set up a game with it.
Thanks for your detailed response. Flattening sounds like a good idea, although I'm a little bit reluctant to adopt it since this would likely mean that if one day I switch to FileManager.default.enumerator(at:includingPropertiesForKeys:errorHandler:) the bug would appear again (unless it has been fixed in the meantime).
The user just confirmed to me that when copying the folder in the Finder, the same looping issue occurs. So I was wondering: wouldn't FileManager.default.enumerator(at:includingPropertiesForKeys:errorHandler:) (which I assume is used by the Finder) profit from using iteration instead of recursion as well? If we put the memory benefits you mentioned aside, are there any downsides to using iteration instead of recursion?
[quote='813727022, DTS Engineer, /thread/766035?answerId=813727022#813727022']
The big difference I can think of here is that contentsOfDirectory(atPath:) only looks at the first directory level (it's "shallow", not "deep"), which means in never recurses, which significantly changes how it interacts with SMB.
[/quote]
Thank you very much for your detailed help.
The customer agreed to run a new test app which uses FileManager.default.enumerator(at:includingPropertiesForKeys:errorHandler:) instead of recursive getattrlistbulk calls, and it loops as well. So it seems like something weird was changed in getattrlistbulk in macOS 15.
Here's what they say regarding to their server model:
My original server was from HP. I rebuilt it about 8-9 years ago and has nothing to do with HP, I just left the naming convention for consistency. I think the issue is likely with Windows 10 Storage Spaces. I use Storage Spaces to pool the disk space for redundancy. It’s kind of like drive mirroring.
I'm somewhat happy to learn that it's not a fault in my implementation. I guess the only thing I can do now is to wait if I get any response in Feedback Assistant, right? Or can you already tell that this won't likely be fixed in a future macOS release (if it's a macOS issue at all) and is something to be fixed in the customer's setup (Windows 10 Storage Spaces, which I've never heard of before)?
I haven't had the issue since updating to macOS 15.1 and haven't got any more reports from users either, but I will update you if I do.
Thanks, I wasn't aware that you can allow apps to run from the Privacy section of the System Settings. It's kind of hidden, but I guess that's the point to discourage users from doing so?
Still, there's the question: why is this warning shown for my developer-signed app, only after uploading and downloading it again from my website?
Hi @DTS Engineer ,
do you have any information about what is causing this crash so that we can look for a workaround? I'm close to publishing my game on the App Store, but this is one of two bugs that prevents me from doing so. Should I open a TSI? Thanks in advance for your help.
[quote='810759022, DTS Engineer, /thread/766035?answerId=810759022#810759022']
The big test I would add here is to call contentsOfDirectory(at:includingPropertiesForKeys:options:) as well or, even better, enumerate the directory with CFURLEnumeratorCreateForDirectoryURL(). Either of those should end up calling getattrlistbulk and a failure in either would be good confirmation that the problem isn't actually with your code.
[/quote]
Thanks for all your detailed insights. I understand that the URL version of try FileManager.default.contentsOfDirectory(atPath: path).count is faster, but both should call getattrlistbulk, and since at the very beginning I mentioned that it indeed returns a reasonable file count, it would seem that... there is indeed something wrong with my code? Although you also mentioned that you don't see any obvious failure point in it.
I updated my feedback report FB15497909 on October 28 by uploading the sysdiagnose and other tests performed by the user, but haven't heard anything yet. Are you already aware of it? Are you able to tell where the issue might be?
[quote='809783022, Bill3D, /thread/766249?answerId=809783022#809783022, /profile/Bill3D']
Yes, it does crash on the iPad simulator. It didn't crash for me on the iPhone simulator
[/quote]
Confirmed. Thanks for the workaround.
Note: occasionally the hang doesn't happen while debugging the app in Xcode, but until now it always happened when profiling the app in Instruments.
I was able to recreate the issue with a small sample project that repeatedly calls SCNView.projectPoint(_:) in a block dispatched to the main actor inside the SCNSceneRendererDelegate.renderer(_:didApplyAnimationsAtTime) method.
In my personal project, the issue happens when calling that method 6 times (in order to position 6 sprites in the overlay SpriteKit scene that should follow objects in the SceneKit scene), but in the sample I call it 200 times to reliably reproduce the issue.
As mentioned previously, the hangs only happen when running the app in fullscreen, but I noticed that when moving the mouse to the top of the screen to show the menu bar, the game runs smoothly. As soon as the menu bar disappears again, or if I click a main menu item to show the submenu, the game immediately hangs again and shows maybe 2 or even less frames per second. Sometimes the hangs continue happening unless I show the menu bar again, but sometimes the game begins running smoothly again after a couple seconds.
This is again confirmed by Instruments.
Interestingly, if I comment out the line
Task { @MainActor in
and the corresponding closing curly bracket 4 lines down, there is no hang anymore, not in fullscreen, and not when clicking the main menu:
Is this an issue with SCNView.projectPoint(_:)? Or with the delegate method? Or with doing SceneKit things on the main thread? I thought that we're supposed to add nodes and do modifications on the main thread, so how could I avoid thread races if in this delegate method the only solution is not to use the main thread?
class GameViewController: NSViewController, SCNSceneRendererDelegate {
var scnView: SCNView?
override func viewDidLoad() {
super.viewDidLoad()
let scene = SCNScene(named: "art.scnassets/ship.scn")!
let ship = scene.rootNode.childNode(withName: "ship", recursively: true)!
ship.runAction(.customAction(duration: 999, action: { node, t in
Task { @MainActor in
node.eulerAngles.y = t
}
}))
let scnView = self.view as! SCNView
self.scnView = scnView
scnView.scene = scene
scnView.delegate = self
}
func renderer(_ renderer: any SCNSceneRenderer, didApplyAnimationsAtTime time: TimeInterval) {
Task { @MainActor in
for _ in 0..<200 {
let _ = scnView?.projectPoint(SCNVector3(x: 0, y: 0, z: 0))
}
}
}
}
[quote='779363022, difosfor, /thread/742147?answerId=779363022#779363022, /profile/difosfor']
I've tried to open your feedback ticket to add this information there as well, but wasn't able to open that.
[/quote]
You won't be able to open other developers' feedbacks, only Apple can.
11 months ago my feedback was updated with
Every time the pid changes will trigger new prompt for consent. This is as expected. (Everytime you re-build/run your project, your pid will change.)
I asked if this is documented, but never got a response.
Unfortunately I wasn't able to fix it, though I also noticed that when removing all SKLabelNode from my overlay scene the crash didn't happen anymore.