Post not yet marked as solved
I have an SwiftUI app that uses CloudKit. I have model classes and I read and write data to CloudKit. I wanted to convert the app to use SwiftData. Here is a sample model class.
@Model class User {
var firstName: String?
var lastName: String?
var location: CLLocation?
var photo: Image?
}
When I read and write this to CloudKit the variables map like this:
String -> String
CLLocation -> LOCATION
Image -> ASSET
When I try to compile the above class, I get these error for CLLocation and Image.
Instance method 'setValue(forKey:to:)' requires that 'CLLocation' conform to 'PersistentModel'
Instance method 'setValue(forKey:to:)' requires that 'Image' conform to 'PersistentModel'
How can I use variable types such as CLLocation and Image with SwiftData?
In Xcode MyProject shows 2 GIT repositories, Apple and MyProject. I am using the MyProject repository and I don't know how the Apple repository got there and I can't delete it from within Xcode or from the command line. My project is in /Users/username/Apps/MyProject. I found that if I move MyProject to any other folder and open it, the Apple repository is gone. So, somehow Xcode is associating this Apple repository only with the /Users/uername/Apps/MyProject location. Can anybody tell me where Xcode might be storing information that the Apple repository belongs in MYProject only when it's in the /Users/username/Apps/MyProject folder so I can get rid of it?
Is there any way to get photo location information from a picked photo using the new Swift PhotosPicker?
Post not yet marked as solved
Can someone tell me why in the sample code below I am getting the error:
Converting function value of type '@MainActor (WebServices.User) -> CKRecord' to '(WebServices.User) -> CKRecord' loses global actor 'MainActor'
on this line:
try await deleteRecord(record: user, createRecord: createUserRecord)
I don't understand the error. If I pass in appSettings to WebServices I don't get this error, but if I have appSettings as an @EnvironmentObject I get this error.
Thanks.
import SwiftUI
import CloudKit
class WebServices: ObservableObject {
@EnvironmentObject var appSetting: AppSettings
private var publicDatabase : CKDatabase?
struct User: Identifiable, Hashable {
var username: String
var id: String = UUID().uuidString
}
func deleteUser(user: User) async throws {
try await deleteRecord(record: user, createRecord: createUserRecord)
}
private func createUserRecord(user:User) -> CKRecord {
return CKRecord(recordType: "User", recordID: CKRecord.ID(recordName: "username"))
}
func deleteRecord<RecordType: Hashable>(record: RecordType, createRecord: @escaping ((RecordType) -> CKRecord)) async throws {
let ckRecord = createRecord(record)
_ = try await publicDatabase?.deleteRecord(withID: ckRecord.recordID)
}
}
I converted an existing app to use NavigationSplitView, NavigationStack, NavigationLink(value:), and .navigationDestination(for:). I found that this causes a hang with an infinite loop when I tap on many of the NavigationLink(value:). This happens in may different places in the app. Over the past few months I have tried to figure out what was happening without any luck. I ended up creating a simple test app called NavigationLinkIssue that demonstrates one of the places where I have the hang/infinite loop.
The loop can be seen by doing this:
Run
Tap on Push Second View
Tap on Push New/Different Instantiation of First View
The problem seem to be related to the report Binding. If I don’t make report a binding the hang/infinite loop goes away. If I change report to an ObservedObject the hang/infinite loop goes away.
I contacted Apple Developer Support, and had a few replies, but in the end they replied:
To clarify the issue you are experiencing is not a bug, it is expected. To elaborate, In Case1: This is expected because the ContentView creates an instance of FirstView with a Binding to the report object, which is then passed to SecondView. When the NavigationLink in SecondView is clicked, it navigates back to FirstView, which creates a new instance of FirstView with a new Binding to report. This causes the ContentView to update and create a new instance of SecondView, which then navigates back to FirstView, and so on, resulting in an infinite loop.
I have spent a lot of time looking at this and I still don’t understand why a Binding should cause the loop, especially if and ObservedObject does not. It still seems like a bug to me. Can anybody explain why this is causing a loop? The full code is below.
import SwiftUI
import OSLog
final class NavigationModel: ObservableObject {
@Published var path = NavigationPath() {
didSet {
print("navigationModel.path.count: \(path.count)")
}
}
}
struct Report: Hashable {
var title: String = "Report Title"
var photo: UIImage? = UIImage(systemName: "z.circle")
}
private let logger = Logger()
struct ViewType: Identifiable, Hashable {
let id: String
}
private var viewTypes = [
ViewType(id: "First View"),
]
struct ContentView: View {
@StateObject private var navigationModel = NavigationModel()
@State var selection: Set<String> = [viewTypes[0].id]
@State var report = Report(title: "ContentView Report")
var body: some View {
NavigationSplitView {
List(viewTypes, selection: $selection) { viewType in
Text("\(viewType.id)")
}
} detail: {
if let viewTitle = selection.first {
switch viewTitle {
case "First View":
FirstView(report: $report)
default:
Text("Invalid View")
}
}
}
.environmentObject(navigationModel)
}
}
// FirstView
struct FirstView: View {
@EnvironmentObject var navigationModel: NavigationModel
@Binding var report: Report
private enum NavigationLinkValueFirstView {
case secondView
}
var body: some View {
NavigationStack(path: $navigationModel.path) {
NavigationLink(value: NavigationLinkValueFirstView.secondView) {
let _ = logger.debug("FirstView NavigationLink")
Text("Push Second View")
}
.navigationDestination(for: NavigationLinkValueFirstView.self) { value in
let _ = logger.debug("FirstView navigationDestination")
SecondView(report: $report)
}
}
.navigationTitle("First View")
}
}
// SecondView
struct SecondView: View {
@State var showTheView = false
@Binding var report: Report
private enum NavigationLinkValueSecondView {
case firstView
}
var body: some View {
NavigationLink(value: NavigationLinkValueSecondView.firstView) {
let _ = logger.debug("SecondView NavigationLink")
Text("Push New/Different Instantiation of First View")
}
.navigationDestination(for: NavigationLinkValueSecondView.self) { value in
FirstView(report: $report)
let _ = logger.debug("SecondView navigationDestination")
}
.navigationTitle("Second View")
}
}
Post not yet marked as solved
I have an app I wrote many years ago in Objective-C that I had converted it to Swift, and now I converted it to SwiftUI. When converting to SwiftUI I had all my model files as structs. I decided to convert to the new Swift Navigation API released in iOS16, since the old way is deprecated and I would be gaining some features that I have wanted for years. However, this causes multiple infinite loops that I have been trying to track down for months. I finally requested Apple Developer Technical support, which ended up being no help. I then narrowed this issue down to using a binding and I think it is a bug so I submitted a bug report FB12069067 to Apple.
The only solution I see, without Apple acknowledging this is a bug and fixing it, it to convert all my model files from structs to class as ObservableObjects, and instead of passing a binding I can use the observed object. I’d have to change a significant amount of code, but I see no other solution. I have found an article by Apple that seems to imply that I should use a class for my model files.
https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app
I’m curious what everyone else is doing. When using SwiftUI, is your model with struct/Binding or class/ObservableObject?
Post not yet marked as solved
I installed macOS 13 beta months ago because I needed it to do development work, and I got all the beta updates fine. Now that Mac OS 13.0 is out, how do I stop beta updates? I have never been enrolled in the public beta program and I don't see a beta profile installed. My MacBook Pro is telling me that it is going to install macOS 13.1 beta which I don't want it to do. My MacBook Pro is running macOS 13.0 (22A380). Thanks.
Post not yet marked as solved
I have an app using an NavigationSplitView with a list on the left and detail views on the right. When I select an item from the list on the left, the detail view on the should change and each detail view can push other views. I use a Navigation Stack in each root detail view. The NavigationStack does not seem to be working as expected.
I created a simple example app to show what I am seeing. In the app:
Select Atlantic from the list on the left
Tap on Atlantic View in the detail view to push to Atlantic Pushed View
Select Pacific from the list on the left
The view on the right still shows Atlantic Pushed View when I would expect it to show Pacific View. If on the detail view I tap the back arrow, it goes from Atlantic Pushed View to Pacific View which is not right.
It seems like when I selected Pacific from the left, it replace the root Atlantic view with the root Pacific view in the NavigationStack which is not correct. It also seems like no matter what I try, there is only one NavigationStack path used throughout the app.
The behavior I want and would expect is:
Select Atlantic from the list on the left
Tap on Atlantic View in the detail view to push to Atlantic Pushed View
Select Pacific from the list on the left, which which should show Pacific View
Select Atlantic from the list on the left, which should go back to Pushed Atlantic View
I am considering filing a big report but I wanted to see if I am missing something or is this just not working. My sample code it below.
import SwiftUI
struct Ocean: Identifiable, Hashable {
let id: String
}
private var oceans = [
Ocean(id: "Atlantic"),
Ocean(id: "Pacific"),
]
struct ContentView: View {
@State var selection: Set<String> = [oceans[0].id]
var body: some View {
NavigationSplitView {
List(oceans, selection: $selection) { ocean in
Text("\(ocean.id) Ocean")
}
.navigationTitle("Oceans")
} detail: {
if selection.first == "Atlantic" {
AtlanticView(selection: selection)
}
else if selection.first == "Pacific" {
PacificView(selection: selection)
}
else {
Text("Unknown Ocean")
}
}
}
}
struct AtlanticView: View {
@State var selection: Set<String>
@State private var atlanticPath = NavigationPath()
var body: some View {
NavigationStack(path: $atlanticPath ) {
VStack {
NavigationLink {
AtlanticPushedView(selection: selection)
} label: {
Text("Atlantic View\n\(selection.first!) Ocean")
}
}
}
}
}
struct AtlanticPushedView: View {
var selection: Set<String>
var body: some View {
Text("Pushed View\n\(selection.first!) Ocean")
}
}
struct PacificView: View {
var selection: Set<String>
@State private var pacificPath = NavigationPath()
var body: some View {
NavigationStack(path: $pacificPath ) {
NavigationLink {
PacificPushedView(selection: selection)
} label: {
Text("Pacific View\n\(selection.first!) Ocean")
}
}
}
}
struct PacificPushedView: View {
var selection: Set<String>
var body: some View {
Text("Pacific Pushed View\n\(selection.first!) Ocean")
}
}
Post not yet marked as solved
If I open the Shortcuts App, edit a shortcut, tap on Apps under Content Types, tap on Open App, then then click choose, why can't I find my app on the long list of apps? I implemented shortcuts in my app and they work fine. In the Shortcuts app I can search for my specific app shortcuts and use them. However, if I try to use Open App my app doesn't show up. In looking through the long list of apps that do show up, only some of them have implemented shortcuts, soI can't figure out what makes an app show up, and how to make my app show up.
Post not yet marked as solved
I moved an existing app to Xcode 14 Beta and I get this error:
MyApp[33596:267791] [CK] Invalid value of "(null)" for entitlement "com.apple.application-identifier" or "com.apple.developer.associated-application-identifier" on process "MyApp(33596)". We expect TEAMID.BUNDLEID, and insist that TEAMID is exactly 10 characters long, consisting of [0-9][A-Z]. This is a permanent issue, and access to CloudKit will be denied until this is resolved
I also found that if I use Xcode 14 Beta, create a new project, and simply add these lines of code I get the same error.
import CloudKit
init() {
_ = CKContainer.default()
}
Is this a bug in Xcode 14 Beta? Is there something I need to do to get this working? Has anybody gotten CloutKit to work with Xcode 14 Beta?
Post not yet marked as solved
I have a macOS app that has access to all of the users iCloud files. This means that the app can see any file that the user can see using the Files app in iOS. How can I get access to the same files programmatically from within iOS? I know how to get access to the files in the container for that iOS app, but I don’t see how to get access to all the users iCloud files like the Files app. I‘m sure it can be done because there are lots of file manager apps that access all the users iCoud files.
Post not yet marked as solved
I have an app that uses CloudKit and I have a notification sent if I create a “Notification” record with “Username” set to the signed in user. This works, but a user could have 2 devices, say an iPhone and an iPad, and be signed in to both devices with the same iCloud account, but be using different app accounts. For example:
iPhone - signed into iCloud as “User”, signed into app as “UserPersonal”
iPad - signed into iCloud as “User”, signed into app as “UserBusiness”
The problem is that CloudKit is tied to the iCloud account so in the above example both the iPhone and iPad will get notifications meant for both “UserPersonal” and “UserBusiness”. In this example I want “UserPersonal” notifications to just go to the iPhone and “UserBusiness” to go to just the iPad.
I see that Apple has added the ability to filter notifications with a Notification Service Extension Filtering Entitlement:
https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_usernotifications_filtering
I already use a notification service extension so I could use this to filter the notifications going to the same iCloud account and check if it is for the user who is signed into my app account. But, you have to apply to Apple for this entitlement and it says:
“This entitlement is intended for certain types of apps — such as messaging apps or location sharing apps — that use notification service extensions to receive push notifications without delivering notifications to the user.”
This is not really my use case.
Is there any way I can have a CloudKit notification just go to either app user “UserPersonal” or “UserBusiness” even though they are signed into the same iCloud account? Or, should I just try applying for the Notification Service Extension Filtering Entitlement?
Has anybody gotten AWS CodeCommit to work with Xcode 7?
Post not yet marked as solved
I believe that sections in a SwiftUI Form used to extend to the left and right edges, but now the sections are in a card like format and don't extend to the edges. Did Form change recently? Is there someway I can force Form to extend to the edges like it used to?
PS - I have before and after photos but no matter how hard I tried to add a link to show them it kept telling me I had to remove the links in order to post.
Post not yet marked as solved
I have an iOS app and I need to be able to pick a file on my iCloud Drive, modify the file, and save the modified file with a new extension. I've tried lots of things but I still can't write the new file. Here is my latest code:documentPickerViewController = DocumentPickerViewController(documentTypes: ["public.item"], in: .open) func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
let fileURL = urls[0]
do {
// Read the file
_ = fileURL.startAccessingSecurityScopedResource()
let fileData = try Data(contentsOf: fileURL, options: .uncached)
fileURL.stopAccessingSecurityScopedResource()
// write the file
let fileCopyURL = fileURL.appendingPathExtension("copy")
_ = fileCopyURL.startAccessingSecurityScopedResource()
try fileData.write(to: fileCopyURL)
fileCopyURL.stopAccessingSecurityScopedResource()
}
catch {
print(error.localizedDescription)
}
}When I pick a file on my iCloud Drive I get the following error:You don’t have permission to save the file “TestFile.txt.copy” in the folder “Test Files”.How can a save a modifed file?