Post

Replies

Boosts

Views

Activity

SwiftUI - Open a file via a fileURL
I am writing a SwiftUI-based app and have the following requirements: Use a file browser (such as UIDocumentPickerViewController) to find an arbitrary file (not one that the application knows how to open) which is external to the app bundle but local to the device the app is running on - either in local storage or on an iCloud drive. Save this location. At a later time, open this file. The file should open in an app that knows how to open it or in a browser. Do all of the above in a way that works with multiple devices (synced via CloudKit/SwiftData). For example, select a file on my iCloud drive on my Mac, then save it (using CloudKit/SwiftData) and open it on an iPad that has an app that can open it. I am addressing requirement #1 using UIDocumentPickerViewController wrapped with a UIViewControllerRepresentable. It returns a security-scoped URL. (Note: this worries me because of requirement #4). I use the Bookmark API to implement requirement #2. For requirement #3, I load the bookmark data, convert it back to a security-scoped URL and either Link("Open", destination: url) or @Environment(\.openURL) private var openURL if url.startAccessingSecurityScopedResource() { defer { url.stopAccessingSecurityScopedResource() } openURL(url) { accepted in // do something here } } Both of these implementations fail. The Link call responds with "invalid input parameters" (Error Domain=NSOSStatusErrorDomain, Code=-50), the openURL() call just returns false. So, my questions are: Since it appears the Link and openURL work for internet URLs, but not for security-scoped file URLs, how to I cause a document to be opened (using an application which knows how to open it or a browser). Since UIDocumentPickerViewController is returning a security-scoped URL, how can I make this work on a different device than the one on which the user selected the document? (Assuming, of course, that we are talking about a document that is on an iCloud drive that both devices have access to).
3
0
3.6k
Jan ’25
How to control when a DatePicker "pops up"
I have a Date field that holds the scheduled start date for an activity.. However, activities can be unscheduled (i.e., waiting to be scheduled at some other time). I want to use Date.distantFuture to indicate that the activity is unscheduled. Therefore I am looking to implement logic in my UI that looks something like @State private var showCalendar: Bool = false if date == .distantFuture { Button("unscheduled") { showCalendar.toggle() }.buttonStyle(.bordered) } else { DatePicker(section: $date) } .popover(isPresented: $showCalendar) { <use DatePicker Calendar view> } But this approach requires that I access the DataPicker's Calendar view and I don't know how to do that (and I don't ever what my users to see "Dec 31, 4000"). Any ideas? (BTW, I have a UIKit Calendar control I could use, but I'd prefer to use the standard control if possible.)
4
0
111
Mar ’25
Automatic Code Signing Error
I am trying to update an old UIKit/CoreData app and am (among other changes) adding CloudKit synchronization support. I enabled CloudKit (ie, set up a new CloudKit domain, enabled CloudKit, Background Mode Remote Notifications, and Push Notifications. When I did this, automatic code signing failed. (see attached for the messages). I tried creating and downloading a new provisioning profile, but that did not help. FB19742743 Can someone help me? I have absolutely no idea of what to do next to get this app signed (and hopefully back into the AppStore soon).
2
0
222
Aug ’25
List of relationship members fails to update when member content changes
FB13099793 I have a view which lists detail information about a SwiftData object, including a list of the members of its relationship. The Problem: If I use a modal presentation to edit the content of a relationship-member, upon return, the member has been updated, but the view falis to show it. The view updates correctly on adding a new member to the relationship, deleting a member, etc. But I cannot get the List to update if the content of the member changes (in a modal presentation). A few requirements that may be of significance: (1) The relationship (and inverse) are defined as optional because it is an eventual requirement for this app to use CloudKit synchronization. (2) The display of the members must be ordered. For this reason, the member object contains a "ordinal" property which is used to sort the the members. The relevant parts of the models are: @Model final public class Build { public var bld: Int @Relationship(inverse: \ChecklistItem.build) public var checklist: [ChecklistItem]? public init(bld: Int) { self.bld = bld self.checklist = [] } } @Model final public class ChecklistItem { public var ordinal: Int public var title: String public var subtitle: String // etc. public var build: Build? public init(build: Build) { self.ordinal = -1 self.title = "" self.subtitle = "" self.build = build } } The relevant parts of the view which handles the display is shown below. (Please look at the notes that follow the code for a discussion of some issues.) struct buildDetailChecklistView: View { @Environment(\.modelContext) var context: modelContext @State private var selectedItem: ChecklistItem? = nil @Bindable var build: Build init(build: Build) { self.build = Build } var body: some View { VStack { // ... some other stuff } List { ForEach((build.checklist ?? []) .sorted(by: { (a,b) in a.ordinal < b.ordinal})) { item in RowView(item) // displays title, subtitle, etc. .swipeActions(edge: .trailing, allowsFullSwipe: false) { Button { deleteRow(item) } label: { Label("Delete", systemImage: "trash") } .tint(.red) } .swipeActions(edge: .leading, allowsFullSwipe: false) { Button { selectedItem = item } label: { Label("Edit", systemImage: "pencil.line") } .tint(.blue) } } .sheet(item: $selectedItem) { item in BuildDetailAddEditChecklistItem(item: item, handler: updateChecklist(_:)) } } } private func updateChecklist(_ item: ChecklistItem) { if let index = build.checklist!.firstIndex(where: { $0 == item }) { DispatchQueue.main.async { [index] in build.checklist!.remove(at: index) try? context.save() build.checklist!.insert(item, at: index) } } } } Notes: (1) I cannot use a @Query macro in this case because of limitations in #Predicate. Every predicate I tried (to match the ChecklistItem's build member with it's parent's build object crash.) (2) I don't want to use @Query anyway because there is no need for the extra fetch operation it implies. All of the data is already present in the relationship. There ought to be a new macro/propertyWrapper to handle this. (3) Dealing with the required sort operation on the relationship members [in the ForEach call] is very awkward. There ought to be a better way. (4) The BuildDetailAddEditChecklistItem() function is a modal dialog, used to edit the content of the specified ChecklistItem (for example, changing its subtitle). On return, I expected to see the List display the new contents of the selected item. IT DOES NOT. (5) The handler argument of BuildDetailAddEditChecklist() is one of the things I tried to "get the List's attention". The handler function is called on a successful return from the model dialog. The implementation of the handler function finds the selected item in the checklist, removes it, and inserts it back into the checklist. I expected that this would force an update, but it does not.
0
1
554
Sep ’23
Should I worry about this error message?
I have a SwiftData Model which includes a property of type Array. @Model final class Handler { public var id: UUID public var name: String public var mailingAddress: [String] . . . public init() { self.id = UUID() self.name = "" self.mailingAddress = [] . . . } When I use this Model in code, the mailingAddress field appears to work just as I would expect, but when saving it (running in Simulator), I see the following logged message: CoreData: fault: Could not materialize Objective-C class named "Array" from declared attribute value type "Array<String>" of attribute named mailingAddress Should I be worried about this?
0
1
501
Oct ’24
NavigationPath.append but .navigationDestination Not Being Called
I am trying to do a bit of fancy navigation in SwiftUI using NavigationPath and am having a problem. I have a root view with includes a button: struct ClassListScreen: View { @Bindable private var router = AppRouter.shared @State private var addCourse: Bool = false ... var body: some View { ... Button("Add Class") { router.currentPath.append(addCourse) }.buttonStyle(.borderedProminent) ... .navigationDestination(for: Bool.self){ _ in ClassAddDialog { course in sortCourses() } } } } router.currentPath is the NavigationPath associated with the operative NavigationStack. (This app has a TabView and each Tab has its own NavigationStack and NavigationPath). Tapping the button correctly opens the ClassAddDialog. In ClassAddDialog is another button: struct ClassAddDialog: View { @Bindable private var router = AppRouter.shared @State private var idString: String = "" ... var body: some View { ... Button("Save") { let course = ... ... (save logic) idString = course.id.uuidString var path = router.currentPath path.removeLast() path.append(idString) router.currentPath = path }.buttonStyle(.borderedProminent) ... .navigationDestination(for: String.self) { str in if let id = UUID(uuidString: str), let course = Course.findByID(id, with: context) { ClassDetailScreen(course: course) } } } } My intent here is that tapping the Save button in ClassAddDialog would pop that view and move directly to the ClassDetailScreen (without returning to the root ClassListScreen). The problem is that the code inside the navigationDestination is NEVER hit. (I.e., a breakpoint on the if let ... statement) never fires. I just end up on a (nearly) blank view with a warning triangle icon in its center. (And yes, the back button takes me to the root, so the ClassAddDialog WAS removed as expected.) And I don't understand why. Can anyone share any insight here?
0
1
80
Oct ’25
@Attribute 'unique' and complex keys
The 'unique' attribute is a really nice feature, BUT. In some of my apps, the unique identifier for an object is a combination of multiple attributes. (Example: a book title is not unique, but a combination of book title and author list is.) How do I model this with SwiftData? I cannot use @Attribute(.unique) on either the title OR the author list, but I want SwiftData to provide the same "insert or update" logic. Is this possible?
5
4
2.7k
Sep ’25