Context
I'm writing an app that allows a user to select folders, and then scan them for files. The folder could be on the user's machine, iCloud or external storage. The app persists the details of these files and folders to a document, so the user can access the files or re-scan the folders in the future. The App is being written using the SwiftUI framework for MacOS and the iPad.
Problems
Given this is a Sandboxed app I need to create security-scoped bookmarks to be able to access the files and folders that have been persisted to the document. I have two questions:
How can I create a document-scoped bookmark, when using ReferenceFileDocument protocol. I need the document's URL, but I will never have access to this as I'm using the ReferenceFileDocument. I want to achieve something like this:
func fileWrapper(snapshot: MyDocument, configuration: WriteConfiguration) throws - FileWrapper {
:
let bookmarkDataToPersist = snapshort.sourceFolderURL.bookmarkData(options: .withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: documentURL)
:
}
2. Ideally the user would be able to:
* connect an external drive to their Mac
* select a folder on that drive
* save the document, which would persist a bookmark to that folder's URL
* send the document to an iPad (via email or iCloud drive)
* open the document using the iPad version of the App
* connect the external bookmark to the iPad
* re-scan the folder which was book marked in the document from the folder
But given the problem in 1) and the fact that document-bookmarks cannot point to folders, is there a way?
Any ideas or suggestions would be very welcome
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
How do you add a button in the toolbar to hide/show the sidebar?
The following code is stripped out from an app that compiles and works under MacOS 11. It shows a tab bar - clicking on an item will highlight it. Under the tab bar is a text edit field where one can edit the title of the selected tab.
There are 2 issues:
The tab title shown in the title editor is allows out of phase
from the selected tab
Irrespective of which tab item is selected, when the title is edited
it always updates the first tab
I'm not sure if I was very lucky that this code ever worked under Big Sur, or if there is an issue with Monterey. I'm definitely not holding this up as example code - I'm sure there are better ways to implement it, but seek opinions on whether it should work.
import SwiftUI
class Document: ObservableObject {
var tabs = [Tab(id: 0), Tab(id: 1)]
var viewSettings = ViewSettings()
}
class Tab: ObservableObject, Identifiable {
let id: Int
@Published var title: String
init(id: Int) {
self.id = id
self.title = "Tab \(id)"
}
}
class ViewSettings: ObservableObject {
@Published var activeTab: Int = 0
}
@main
struct Test: App {
@StateObject var document: Document = Document()
var body: some Scene {
WindowGroup {
ContentView()
.padding()
.environmentObject(document)
.environmentObject(document.viewSettings)
}
}
}
struct ContentView: View {
@EnvironmentObject var document: Document
@EnvironmentObject var viewSettings: ViewSettings
var body: some View {
TabBar(viewSettings: document.viewSettings)
TabEditView(activeTab: document.tabs[viewSettings.activeTab])
}
}
struct TabEditView: View {
@EnvironmentObject var viewSettings: ViewSettings
@ObservedObject var activeTab: Tab
@State var title: String = ""
init(activeTab: Tab) {
print("CONSOLE - Init TabEditView for tab \(activeTab.id)")
self.activeTab = activeTab
}
var body: some View {
HStack {
Text("Tab title:")
TextField("Tab title:", text: $title, onCommit: { activeTab.title = title })
.onAppear { title = activeTab.title }
.onChange(of: viewSettings.activeTab) { _ in
print("CONSOLE - Updating TextField from tab \(activeTab.id)")
title = activeTab.title
}
}
}
}
struct TabBar: View {
@EnvironmentObject var document: Document
@ObservedObject var viewSettings: ViewSettings
var body: some View {
HStack {
ForEach(document.tabs, content: TabItem.init)
}
}
}
struct TabItem: View {
@EnvironmentObject var viewSettings: ViewSettings
@ObservedObject var tab: Tab
init(_ tab : Tab) { self.tab = tab }
var body: some View {
Text(tab.title)
.padding(2)
.background(tab.id == viewSettings.activeTab ? .red : .clear)
.cornerRadius(4)
.onTapGesture {
viewSettings.activeTab = tab.id
}
}
}
How can one conform an actor to the Sequence protocol? The following code generates the compiler warning: Instance method 'makeIterator()' isolated to global actor 'MainActor' can not satisfy corresponding requirement from protocol 'Sequence'.
@MainActor class Test: Sequence {
private var contents: [Int] = []
func makeIterator() -> Array<Int>.Iterator {
contents.makeIterator()
}
}
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?
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)
}
}
}
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) }
}
}
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?
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?
Xcode is not not picking up when I make changes to my unit test files when running tests. The only way is to clean the whole project and rebuild again. Any ideas why?
I recently tried Xcode cloud and this behaviour started after removing that option
Does anyone have any guidance / experience using TriggerVolumes to detect collision rather than the Physics engine in Reality Kit.
Aside from not participating the physics engine are there any other downside or upsides to using them?
Hi,
I'm looking to update the metadata properties of a DNG image stored on disc, saving to a new file.
Using ImageIO's CGImageSource and CGImageDestination classes, I run into a problem where by the destination doesn't support the type of the source. For example:
let imageSourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary
if
let cgImageSource = CGImageSourceCreateWithURL(sourceURL as CFURL, imageSourceOptions),
let type = CGImageSourceGetType(cgImageSource) {
guard let imageDestination = CGImageDestinationCreateWithURL(destinationURL as CFURL, type, 1, nil) else {
fatalError("Unable to create image destination")
}
// Code to update properties and write out to destination url
}
}
When this code is executed I get the following errors on the command line when trying to create the destination:
2024-06-30 11:52:25.531530+0100 ABC[7564:273101] [ABC] findWriterForTypeAndAlternateType:119: *** ERROR: unsupported output file format 'com.adobe.raw-image'
2024-06-30 11:52:25.531661+0100 ABC[7564:273101] [ABC] CGImageDestinationCreateWithURL:4429: *** ERROR: CGImageDestinationCreateWithURL: failed to create 'CGImageDestinationRef'
I don't see a way to create a destination directly from a source? Yes, the code works for say a JPEG file but I want it to work for any image format that CGImageSource can work with?
When I run the debug memory graph from Xcode I'm getting a set of system objects with warnings.
Are there any tips on how to locate what might be causing these?
I implemented an EntityAction to change the baseColor tint - and had it working on VisionOS 2.x.
import RealityKit
import UIKit
typealias Float4 = SIMD4<Float>
extension UIColor {
var float4: Float4 {
if
cgColor.numberOfComponents == 4,
let c = cgColor.components
{
Float4(Float(c[0]), Float(c[1]), Float(c[2]), Float(c[3]))
} else {
Float4()
}
}
}
struct ColourAction: EntityAction {
// MARK: - PUBLIC PROPERTIES
let startColour: Float4
let targetColour: Float4
// MARK: - PUBLIC COMPUTED PROPERTIES
var animatedValueType: (any AnimatableData.Type)? { Float4.self }
// MARK: - INITIATION
init(startColour: UIColor, targetColour: UIColor) {
self.startColour = startColour.float4
self.targetColour = targetColour.float4
}
// MARK: - PUBLIC STATIC FUNCTIONS
@MainActor static func registerEntityAction() {
ColourAction.subscribe(to: .updated) { event in
guard let animationState = event.animationState else { return }
let interpolatedColour = event.action.startColour.mixedWith(event.action.targetColour, by: Float(animationState.normalizedTime))
animationState.storeAnimatedValue(interpolatedColour)
}
}
}
extension Entity {
// MARK: - PUBLIC FUNCTIONS
func changeColourTo(_ targetColour: UIColor, duration: Double) {
guard
let modelComponent = components[ModelComponent.self],
let material = modelComponent.materials.first as? PhysicallyBasedMaterial
else {
return
}
let colourAction = ColourAction(startColour: material.baseColor.tint, targetColour: targetColour)
if let colourAnimation = try? AnimationResource.makeActionAnimation(for: colourAction, duration: duration, bindTarget: .material(0).baseColorTint) {
playAnimation(colourAnimation)
}
}
}
This doesn't work in VisionOS 26. My current fix is to directly set the material base colour - but this feels like the wrong approach:
@MainActor static func registerEntityAction() {
ColourAction.subscribe(to: .updated) { event in
guard
let animationState = event.animationState,
let entity = event.targetEntity,
let modelComponent = entity.components[ModelComponent.self],
var material = modelComponent.materials.first as? PhysicallyBasedMaterial
else { return }
let interpolatedColour = event.action.startColour.mixedWith(event.action.targetColour, by: Float(animationState.normalizedTime))
material.baseColor.tint = UIColor(interpolatedColour)
entity.components[ModelComponent.self]?.materials[0] = material
animationState.storeAnimatedValue(interpolatedColour)
}
}
So before I raise this as a bug, was I doing anything wrong in the former version and got lucky? Is there a better approach?
I have found that following code runs without issue from Xcode, either in Debug or Release mode, yet crashes when running from the binary produced by archiving - i.e. what will be sent to the app store.
import SwiftUI
import AVKit
@main
struct tcApp: App {
var body: some Scene {
WindowGroup {
VideoPlayer(player: nil)
}
}
}
This is the most stripped down code that shows the issue. One can try and point the VideoPlayer at a file and the same issue will occur.
I've attached the crash log:
Crash log
Please note that this was seen with Xcode 26.2 and MacOS 26.2.