Posts

Post marked as solved
2 Replies
1.5k Views
Recently, I have trouble with my Xcode Cloud builds, where they seemingly complete, but the very final step does not happen. I am building from the same codebase for both macOS and iOS (I have two “Archive” steps in my workflow, one for iOS and one for macOS). The iOS one usually completes fast without problems. The macOS log ending looks like this, and remains stuck forever, with the macOS build in the “spinning progress” state and never completing. Is there something I can do on my end to make this work better? I would not want to go back to manual builds, Xcode Cloud is convenient and was working well for a while, but this is really annoying lately.
Posted
by Jaanus.
Last updated
.
Post not yet marked as solved
7 Replies
3.0k Views
I understand that in iOS 15 and macOS Monterey, I can easily access the log system to get log entries for my app like this: let store = try OSLogStore(scope: .currentProcessIdentifier) I can then query store for the log entries. However, as it says right in the name, the store is only for current process, i.e current run of my app. When I try to get entries, I only get entries from the current run, even if I specify an earlier time like this: guard let positionDate = Calendar.current.date(byAdding: .day, value: -7, to: Date()) else { return } let position = store.position(date: positionDate) let predicate = NSPredicate(format: "subsystem == 'com.exampl.emyAppSubsystem'") let entries = try store.getEntries(with: [], at: position, matching: predicate) for entry in entries { print("Entry: \(entry.date) \(entry.composedMessage)") } Is there any way to access log entries for earlier runs of my app, e.g from days or weeks ago? Either on macOS or iOS?
Posted
by Jaanus.
Last updated
.
Post marked as solved
8 Replies
2.9k Views
I’m slightly confused about how are CloudKit containers supposed to handle app transfers. I’m seeing some strange too-permissive security behavior, and I am not sure whether this is a feature or a bug 🙂Here’s the setup:I had an app with bundleID com.example.something, talking to a CloudKit container also called com.example.something, all under the same developer account A. All was well.I then transferred the app from developer account A to developer account B. The bundle ID or anything else about the app did not change, just the ownership. Must now also sign new builds of the app with credentials for account B, as expected. HOWEVER: the CK container also did not change at all, and remained under development account A.What I am seeing now: the app signed by developer account B can still access the CK container under developer account A. No bundle IDs or CK ID-s changed, so I can sort of understand this, but at the same time, it seems strange.There is no security risk to my data, as this app only uses "read" operation of the public database. I didn’t try any other operations or private databases.Is this a bug and could it stop working? Or is this a feature which will remain working? This tells me that under certain conditions, any app can read the CK container of any other app from any developer account, if they know the correct CK container ID to talk to. Is this expected? (Or maybe it only keeps working because they were previously under the same developer account, and the system knows to keep this connection? And if I were try to randomly read any other app’s container, it would fail?) Any docs or guidance from Apple?
Posted
by Jaanus.
Last updated
.
Post not yet marked as solved
12 Replies
4.7k Views
Is it possible to drive NavigationSplitView navigation with a view in sidebar (left column) that is not a List? All examples that I have seen from this year only contain List in sidebar. I ask this because I would like to have a more complex layout in sidebar (or first view on iOS) that contains a mix of elements, some of them non-interactive and not targeting navigation. Here’s what I would like to do: import SwiftUI struct Thing: Identifiable, Hashable {     let id: UUID     let name: String } struct ContentView: View {     let things: [Thing]     @State private var selectedThingId: UUID?          var body: some View {         NavigationSplitView {             ScrollView(.vertical) {                 VStack {                     ForEach(things) { thing in                         Button("Thing: \(thing.name) \( selectedThingId == thing.id ? "selected" : "" )") {                             selectedThingId = thing.id                         }                     } SomeOtherViewHere() Button("Navigate to something else") { selectedThingId = someSpecificId }                 }             }         } detail: {             // ZStack is workaround for known SDK bug             ZStack {                 if let selectedThingId {                     Text("There is a thing ID: \(selectedThingId)")                 } else {                     Text("There is no thing.")                 }             }         }     } } This actually works as expected on iPadOS and macOS, but not iOS (iPhone). Tapping changes the selection as I see in the button label, but does not push anything to navigation stack, I remain stuck at home screen. Also filed as FB10332749.
Posted
by Jaanus.
Last updated
.
Post not yet marked as solved
11 Replies
3.9k Views
I am having trouble with my existing CloudKit app on iOS 15 beta simulator. Tried with Xcode 13 beta 1 on both Big Sur and Monterey. When I try to set up CloudKit record zones, I get the error: <CKError 0x600000ad34e0: "Partial Failure" (2/1011); "Failed to modify some record zones"; partial errors: { Zone1:__defaultOwner__ = <CKError 0x600000aab990: "Internal Error" (1/5000); "Failed to sync user keys"> Zone2:__defaultOwner__ = <CKError 0x600000aac180: "Internal Error" (1/5000); "Failed to sync user keys"> }> And when I try to retrieve some records: <CKError 0x600000aa6670: "Partial Failure" (2/1011); "Failed to fetch some query results"; partial errors: { 17E15463-28D9-4A8F-9C00-13864C0B1922:(Zone1:__defaultOwner__) = <CKError 0x600000a74120: "Internal Error" (1/5001); "Record <CKRecordID: 0x7fea11997820; recordName=17E15463-28D9-4A8F-9C00-13864C0B1922, zoneID=Zone1:__defaultOwner__> has items that require encryption but no zone protection data was found: <CKError 0x7fea105c6b40: "Internal Error" (5000/com.apple.protectedcloudstorage:97); "Failed to sync user keys">"> 4CADA078-7040-4633-9321-C1FF6C5BF80C:(Zone1:__defaultOwner__) = <CKError 0x600000a6c570: "Internal Error" (1/5001); "Record <CKRecordID: 0x7fea1198d250; recordName=4CADA078-7040-4633-9321-C1FF6C5BF80C, zoneID=Zone1:__defaultOwner__> has items that require encryption but no zone protection data was found: <CKError 0x7fea105c6b40: "Internal Error" (5000/com.apple.protectedcloudstorage:97); "Failed to sync user keys">"> E1558266-C19A-4A46-BC1A-B11303DA87FC:(Zone1:__defaultOwner__) = <CKError 0x600000a60210: "Internal Error" (1/5001); "Record <CKRecordID: 0x7fea132dfb80; recordName=E1558266-C19A-4A46-BC1A-B11303DA87FC, zoneID=Zone1:__defaultOwner__> has items that require encryption but no zone protection data was found: <CKError 0x7fea13263e60: "Internal Error" (5000/com.apple.protectedcloudstorage:97); "Failed to sync user keys">"> }> <CKError 0x600000af8d50: "Partial Failure" (2/1011); "Failed to fetch some query results"; partial errors: { BE1508B0-20C1-483A-B536-FFA1949E758A:(Zone1:_9b181defada871111c80080a15254790) = <CKError 0x600000aec7b0: "Internal Error" (1/5001); "Record <CKRecordID: 0x7fea1198cf00; recordName=BE1508B0-20C1-483A-B536-FFA1949E758A, zoneID=Zone1:_9b181defada871111c80080a15254790> has items that require encryption but no share protection data was found: <CKError 0x7fea105980b0: "Internal Error" (5004/5004); "Couldn't create share PCS data for share <CKRecordID: 0x7fea119910d0; recordName=Share-7347C086-8BA5-47C6-96AD-1DD12B1AAC8D, zoneID=Zone1:_9b181defada871111c80080a15254790>">"> F1D604B6-A4BC-4F2E-A23E-5B50A2D7C82D:(Zone1:_9b181defada871111c80080a15254790) = <CKError 0x600000a740f0: "Internal Error" (1/5001); "Record <CKRecordID: 0x7fea11985170; recordName=F1D604B6-A4BC-4F2E-A23E-5B50A2D7C82D, zoneID=Zone1:_9b181defada871111c80080a15254790> has items that require encryption but no share protection data was found: <CKError 0x7fea107bfb10: "Internal Error" (5004/5004); "Couldn't create share PCS data for share <CKRecordID: 0x7fea10416370; recordName=Share-C990C533-D709-4B7D-B916-418336386366, zoneID=Zone1:_9b181defada871111c80080a15254790>">"> }> I wonder if anyone else has experienced the same? Or if I can do something on my end to fix it? I’ve filed FB9144546 about this.
Posted
by Jaanus.
Last updated
.
Post marked as solved
1 Replies
915 Views
A few questions about advanced use of cktool for record creation and filtering. Is it possible to filter by record name? I.e query for a record with a specific recordName? Is there any way to specify record parent and reference fields when creating a record? All the examples of JSON fields so far that I have seen are of simple value types. Is there any way to filter/query by reference-type field?
Posted
by Jaanus.
Last updated
.
Post marked as solved
5 Replies
2.9k Views
Consider this view: import SwiftUI struct ContentView: View { &#9;&#9;@State var selection: ListObject? &#9;&#9;var objects: [ListObject] &#9;&#9;var body: some View { &#9;&#9;&#9;&#9;NavigationView { &#9;&#9;&#9;&#9;&#9;&#9;List { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;ForEach(objects) { object in &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;NavigationLink( &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;destination: &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;ListObjectView(object: object), tag: object, selection: $selection, &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;label: { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;Text(object.text) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;}) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;&#9;}.listStyle(SidebarListStyle()) &#9;&#9;&#9;&#9;&#9;&#9;.toolbar { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;ToolbarItem { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;Button("Push item") { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;selection = objects.first &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;&#9;Text("Empty view, pick something.").padding() &#9;&#9;&#9;&#9;}.onAppear { &#9;&#9;&#9;&#9;&#9;&#9;DispatchQueue.main.asyncAfter(deadline: .now() + 2) { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;selection = objects.first &#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;} &#9;&#9;} } This is a simple list, where I can programmatically control the selection, and push another view into the navigation stack. I demonstrate two ways of doing this here, both with a timer and then with a button. Everything works as expected. Now, when I change the @State variable to @Binding, and pass it in from outside, this suddenly stops working. No matter what I do, I can no longer programmatically change the selection. What’s more, the list UI itself stops working: when I tap on a list item, nothing happens, and no detail view appears. Why do @State and @Binding behave differently here? Why does navigation link selection work with one, but not the other?
Posted
by Jaanus.
Last updated
.
Post marked as solved
21 Replies
4.8k Views
I am working on a macOS app that involves remote notifications. In my app delegate appDidFinishLaunching, I simply call NSApplication.shared.registerForRemoteNotifications() I then get one of two callbacks in the app delegate, either didRegisterForRemoteNotificationsWithDeviceToken or didFailToRegisterForRemoteNotificationsWithError. This has worked fine forever in previous versions. In Big Sur, this does not seem to work at all. I call the registerForRemoteNotifications, but I never get either callback called. My hypothesis was that this is because of the new app lifecycle (which is where I originally tried this out). I built a small test app with AppKit app delegate lifecycle. It is equally broken there. What gives? Why cannot I register for remote notifications in Big Sur?
Posted
by Jaanus.
Last updated
.
Post not yet marked as solved
1 Replies
1.1k Views
Consider this macOS app code implemented with app delegate lifecycle: App delegate: func applicationDidFinishLaunching(_ aNotification: Notification) {         let contentView = ContentView()         window = NSWindow(             contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),             styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],             backing: .buffered, defer: false)         window.toolbar = NSToolbar(identifier: "toolbar")         window.title = "hello title"         window.subtitle = "hello subtitle"         window.isReleasedWhenClosed = false         window.center()         window.setFrameAutosaveName("Main Window")         window.contentView = NSHostingView(rootView: contentView)         window.makeKeyAndOrderFront(nil)     } SwiftUI: struct ContentView: View {     var body: some View {         NavigationView {             List {                 NavigationLink(                     destination: ItemView(),                     label: {                         Label("Something", systemImage: "folder.circle")                     })                 NavigationLink(                     destination: ItemView(),                     label: {                         Label("Another", systemImage: "pencil.tip.crop.circle")                     })             }.listStyle(SidebarListStyle())         }         .frame(maxWidth: .infinity, maxHeight: .infinity)         .toolbar {             ToolbarItem {                 Button(action: {                     print("Button clicked")                 }, label: {                     Label("Hello", systemImage: "pencil.circle")                 })             }         }     } } struct ItemView: View {     var body: some View {         Text("Hello, World!")             .frame(maxWidth: .infinity, maxHeight: .infinity)             .toolbar {                 ToolbarItem {                     Button(action: {                         print("Item button")                     }, label: {                         Label("Itemtool", systemImage: "lock.doc")                     })                 }             }     } } What this does: correctly sets up the window and toolbar look. Toolbar has no buttons though. What I would like to do: get the toolbar items added from SwiftUI added to the toolbar. Everything works as expected when I have the window managed by the SwiftUI app lifecycle. However, I need to stick with the app delegate lifecycle for unrelated reasons. Is this possible? How do I add toolbar buttons from SwiftUI to the toolbar of window that is created by app delegate?
Posted
by Jaanus.
Last updated
.
Post marked as solved
2 Replies
4.7k Views
Consider this code that presents a sheet on macOS: struct ContentView: View {     @State var showSheet = false     var body: some View {         VStack {             Text("Hello, world!").padding()             Button("Show sheet") {                 showSheet = true             }         }         .sheet(isPresented: $showSheet) {             SheetView()         }     } } struct SheetView: View {     @State var greenBiggerBox = false     var body: some View {         VStack {             Toggle("Show bigger box", isOn: $greenBiggerBox)             if greenBiggerBox {                 Rectangle().frame(width: 640, height: 480).foregroundColor(.green)             } else {                 Rectangle().frame(width: 320, height: 240).foregroundColor(.red)             }         }.padding()     } } The problem: initially, the sheet is presented, sized correctly to its contents (good). However, when something happens inside the sheet that resizes the content (like the toggle in the sheet), the sheet window is not resized, yielding a sheet size that is either too large or too small. How do I make the sheet resize correctly and automatically if its the size of its content changes?
Posted
by Jaanus.
Last updated
.
Post not yet marked as solved
2 Replies
1k Views
In the iOS 13 world, I had code like this: class SceneDelegate: UIResponder, UIWindowSceneDelegate { &#9;&#9;func windowScene(_ windowScene: UIWindowScene, userDidAcceptCloudKitShareWith cloudKitShareMetadata: CKShare.Metadata) { &#9;&#9;&#9;&#9;// do stuff with the metadata, eventually call CKAcceptSharesOperation &#9;&#9;} } I am migrating my app to the new SwiftUI app lifecycle, and can’t figure out where to put this method. It used to live in AppDelegate pre-iOS13, and I tried going back to that, but the AppDelegate version never gets called. There doesn’t seem to be a SceneDelegateAdaptor akin to UIApplicationDelegateAdaptor available, which would provide a bridge to the old code. So, I’m lost. How do I accept CloudKit shares with SwiftUI app lifecycle? 🙈
Posted
by Jaanus.
Last updated
.
Post marked as solved
8 Replies
8.4k Views
I would like to have a SwiftUI view that shows many lines of text, with the following requirements:Works on both macOS and iOS.Shows a large number of strings (each string is backed by a separate model object).I can do arbitrary styling to the multiline text.Each string of text can be of arbitrary length, possibly spanning multiple lines and paragraphs.The maximum width of each string of text is fixed to the width of the container. Height is variable according to the actual length of text.There is no scrolling for each individual text, only the whole list.Links in the text must be tappable/clickable.Text is read-only, does not have to be editable.Feels like the most appropriate solution would be to have a List view, with the individual rows wrapping native UITextView/NSTextView.Here’s what I have so far. It implements most of the requirements EXCEPT having the correct height for the rows.import SwiftUI let number = 20 struct ListWithNativeTexts: View { var body: some View { List(texts(count: number), id: \.self) { text in NativeTextView(string: text) } } } struct ListWithNativeTexts_Previews: PreviewProvider { static var previews: some View { ListWithNativeTexts() } } func texts(count: Int) -&gt; [String] { return (1...count).map { (1...$0).reduce("Hello https://example.com:", { $0 + " " + String($1) }) } } #if os(iOS) typealias NativeFont = UIFont typealias NativeColor = UIColor struct NativeTextView: UIViewRepresentable { var string: String func makeUIView(context: Context) -&gt; UITextView { let textView = UITextView() textView.isEditable = false textView.isScrollEnabled = false textView.dataDetectorTypes = .link textView.textContainerInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) textView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) textView.textContainer.lineFragmentPadding = 0 let attributed = attributedString(for: string) textView.attributedText = attributed return textView } func updateUIView(_ textView: UITextView, context: Context) { } } #else typealias NativeFont = NSFont typealias NativeColor = NSColor struct NativeTextView: NSViewRepresentable { var string: String func makeNSView(context: Context) -&gt; NSTextView { let textView = NSTextView() textView.isEditable = false textView.isAutomaticLinkDetectionEnabled = true textView.isAutomaticDataDetectionEnabled = true textView.textContainer?.lineFragmentPadding = 0 textView.backgroundColor = NSColor.clear textView.textStorage?.append(attributedString(for: string)) textView.isEditable = true textView.checkTextInDocument(nil) // make links clickable textView.isEditable = false return textView } func updateNSView(_ textView: NSTextView, context: Context) { } } #endif func attributedString(for string: String) -&gt; NSAttributedString { let attributedString = NSMutableAttributedString(string: string) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = 4 let range = NSMakeRange(0, (string as NSString).length) attributedString.addAttribute(.font, value: NativeFont.systemFont(ofSize: 24, weight: .regular), range: range) attributedString.addAttribute(.foregroundColor, value: NativeColor.red, range: range) attributedString.addAttribute(.backgroundColor, value: NativeColor.yellow, range: range) attributedString.addAttribute(.paragraphStyle, value: paragraphStyle, range: range) return attributedString }This mostly does what I need, except wrapping the text to multiple lines and scaling the height of each list row. Each list row remains at its default height.How do I get this solution to wrap the text to multiple lines and size the text views with correct heights?One approach that I have tried, but not shown here, is to give the height “from outside in” - to specify the height on the list row itself with frame. I can calculate the height of an NSAttributedString when I know the width, which I can obtain with geoReader. This almost works, but is buggy, and does not feel right, so I’m not showing it here.
Posted
by Jaanus.
Last updated
.
Post not yet marked as solved
2 Replies
1.1k Views
Using Xcode 12 beta 2 on Big Sur beta. Having a view like this: import SwiftUI struct ContentView: View {     @SceneStorage("selectedItem") var selection: String?     var body: some View {         NavigationView {             List(selection: $selection) { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;… list contents             }.listStyle(SidebarListStyle())         }     } } When I try to compile and build this on macOS, I get this fatal error: Fatal error: @SceneStorage is only for use with SwiftUI App Lifecycle.: file SwiftUI, line 0 I am definitely using the SwiftUI App Lifecycle because this is a fresh new project created with Multiplatform app template. Why do I get this error? Can I fix it somehow?
Posted
by Jaanus.
Last updated
.
Post marked as solved
11 Replies
15k Views
Just getting started with SwiftUI. Exciting stuff.I understand that List would be one of the main building blocks that I can use in place of UI/NSTableView. One thing I haven’t seen yet: how to get and set the scroll position? Specifically, my list would consist of “read” and “unread” items. When the user first enters the list, everything is unread, so the list can start at the top. As new items scroll into view, they become “read”. When the user now leaves the list, and later returns, the list should scroll to the first “unread” item. So I am not so much interested in the pixel-level scroll offset, but rather, how do I scroll the viewport into the right location so that the user would see the desired info. The API could be something like “scroll the list such that model object X is visible in the middle” (with or without animation).The read/unread state is easily expressible as a model object property. I’m having trouble with how to bind it to the list scrolling in this new declarative world of ours.
Posted
by Jaanus.
Last updated
.
Post marked as solved
1 Replies
2.3k Views
I am using a fairly standard setup of NSTableView + CoreData + NSFetchedResultsController, with the relevant view controller being NSFetchedResultsControllerDelegate to receive the changes. Here are the relevant bits of code from the view controller:func controller(_ controller: NSFetchedResultsController, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?){ print("Change type \(type) for indexPath \(String(describing: indexPath)), newIndexPath \(String( switch type { case .insert: if let newIndexPath = newIndexPath { tableView.insertRows(at: [newIndexPath.item], withAnimation: .effectFade) } case .delete: if let indexPath = indexPath { tableView.removeRows(at: [indexPath.item], withAnimation: .effectFade) } case .update: if let indexPath = indexPath { let row = indexPath.item for column in 0.. tableView.reloadData(forRowIndexes: IndexSet(integer: row), columnIndexes: IndexSet(integer: column)) } } case .move: if let indexPath = indexPath, let newIndexPath = newIndexPath { tableView.removeRows(at: [indexPath.item], withAnimation: .effectFade) tableView.insertRows(at: [newIndexPath.item], withAnimation: .effectFade) } @unknown default: fatalError("Unknown fetched results controller change result type") } } func controllerWillChangeContent(_ controller: NSFetchedResultsController) { print("tableViewBeginUpdates") tableView.beginUpdates() } func controllerDidChangeContent(_ controller: NSFetchedResultsController) { tableView.endUpdates() print("tableViewEndUpdates") }I understand that I should be able to batch all the updates this way, even if multiple rows are deleted. However, this causes a crash with multiple deletes in a row.Here is the log output from a session, with the table initially having five rows, and all of them being deleted:tableViewBeginUpdates Change type NSFetchedResultsChangeType for indexPath Optional([0, 4]), newIndexPath nil Change type NSFetchedResultsChangeType for indexPath Optional([0, 3]), newIndexPath nil Change type NSFetchedResultsChangeType for indexPath Optional([0, 1]), newIndexPath nil Change type NSFetchedResultsChangeType for indexPath Optional([0, 0]), newIndexPath nil Change type NSFetchedResultsChangeType for indexPath Optional([0, 2]), newIndexPath nilThe last row causes a crash:2019-05-03 22:33:13.361102+0300 MyApp[2104:168334] [error] error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. NSTableView error inserting/removing/moving row 2 (numberOfRows: 1). with userInfo (null)The first four deletes happen to be reported in the "right" order (rows with bigger indexes [row numbers] being deleted first). The last one arrives “out of order” and the other rows are seemingly already gone from NSTableView by this time.Have I misunderstood how to work with the fetched results controller delegate? I thought that the beginupdates/endupdates calls make sure that the “table view model” does not change between them? What should I do to eliminate the crash?
Posted
by Jaanus.
Last updated
.