Post

Replies

Boosts

Views

Activity

CoreData Data Sharing with AppGroup
I have the following lines of code to access data through CoreData. import Foundation import CoreData import CloudKit class CoreDataManager { static let instance = CoreDataManager() let container: NSPersistentCloudKitContainer let context: NSManagedObjectContext init() { container = NSPersistentCloudKitContainer(name: "ABC") container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { print(error.userInfo) } }) context = container.viewContext context.automaticallyMergesChangesFromParent = true context.mergePolicy = NSMergePolicy(merge: .mergeByPropertyObjectTrumpMergePolicyType) } func save() { do { try container.viewContext.save() print("Saved successfully") } catch { print("Error in saving data: \(error.localizedDescription)") } } } I have confirmed that I can share data between iPhone and iPad. Now, I need to use AppGroup as well. I have changed my code as follows. import Foundation import CoreData import CloudKit class CoreDataManager { static let shared = CoreDataManager() let container: NSPersistentContainer let context: NSManagedObjectContext init() { container = NSPersistentCloudKitContainer(name: "ABC") container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "some group name")!.appendingPathComponent("CoreDataMama.sqlite"))] container.loadPersistentStores(completionHandler: { (description, error) in if let error = error as NSError? { print("Unresolved error \(error), \(error.userInfo)") } }) context = container.viewContext context.automaticallyMergesChangesFromParent = true context.mergePolicy = NSMergePolicy(merge: .mergeByPropertyObjectTrumpMergePolicyType) } func save() { do { try container.viewContext.save() print("Saved successfully") } catch { print("Error in saving data: \(error.localizedDescription)") } } } Other files being unaltered, my sample apps aren't sharing data. What am I doing wrong? Just FYI, I'm using actual devices. Thank you for your reading this topic.
1
0
106
May ’25
onReceive(_:perform:) on Frontmost Window Only?
I have a simple document-based application for macOS. struct ContentView: View { @Binding var document: TextDocument var body: some View { .onReceive(NotificationCenter.default.publisher(for: .notificationTextWillAppendSomeTextt), perform: { _ in }) VStack { TextEditor(text: $document.text) } } } extension Notification.Name { static let notificationTextWillAppendSomeTextt = Notification.Name("TextWillAppendSomeText") } Suppose that my application currently has three tabs. If I call a menu command through post(name:object:) this menu command call will affect all three of them. This stackoverflow topic talks about it, too. So how could I tell which window should get a call and others don't? Thanks.
3
0
91
May ’25
Opening a New Document from File URL?
I have a sample document-based macOS app. I understand that you can open a new window or a new tab with some text. import SwiftUI struct ContentView: View { @Binding var document: TexDocument @Environment(\.newDocument) var newDocument var body: some View { VStack(spacing: 0) { topView } } private var topView: some View { Button { newDocument(TexDocument(text: "A whole new world!")) } label: { Text("Open new window") .frame(width: 200) } } } Suppose that I have a path to a text file whose security-scoped bookmark can be resolved with a click of a button. I wonder if you can open a new window or a new tab with the corresponding content?. I have done that in Cocoa. I hope I can do it in SwiftUI as well. Thanks.
1
0
93
May ’25
Different Build Schemes -> Error: -Onone Swift optimization level to use previews
I have a sample SwiftUI iOS app. As shown in the screenshot below, my project has three configurations: Debug, MyDebug, Release. If I select the Debug or MyDebug scheme, I get a preview. But if I select the Release scheme, I get an error that says the following. ”***.app” needs -Onone Swift optimization level to use previews (current setting is -O) , where *** is the app name. It probably has nothing to do with the Preview error, but the Info.plist has a dictionary such that the key name is devMode, and the value is $(DEVMODE). And I have a user-defined setting as shown below. My ContentView has the following. import SwiftUI struct ContentView: View { @State private var state: String = "" var body: some View { VStack { Text("Hello, world!: \(state)") } .onAppear { if let devMode = Bundle.main.object(forInfoDictionaryKey: "devMode") as? String { print("Development mode: \(devMode)") state = devMode } if let path = Bundle.main.path(forResource: "Info", ofType: "plist") { if let dict = NSDictionary(contentsOfFile: path) { print("**** \(dict)") } } #if DEBUG print("Debug") #elseif MYDEBUG print("MyDebug") #else print("Que?") #endif } } } #Preview { ContentView() } So my question is how I get the preview for all three build schemes? Muchos thankos.
5
0
348
Apr ’25
Opening a New Tab with Text in a Document-Based App
I have a sample document-based application for macOS. According to this article (https://jujodi.medium.com/adding-a-new-tab-keyboard-shortcut-to-a-swiftui-macos-application-56b5f389d2e6), you can create a new tab programmatically. It works. Now, my question is whether you can open a tab with some data. Is that possible under the SwiftUI framework? I could do it in Cocoa. Hopefully, we can do it in SwiftUI as well. Muchos thankos. import SwiftUI @main struct SomeApp: App { var body: some Scene { DocumentGroup(newDocument: SomeDocument()) { file in ContentView(document: file.$document) } } } import SwiftUI struct ContentView: View { @Binding var document: SomeDocument var body: some View { VStack { TextEditor(text: $document.text) Button { createNewTab() } label: { Text("New tab") .frame(width: 64) } } } } extension ContentView { private func createNewTab() { if let currentWindow = NSApp.keyWindow, let windowController = currentWindow.windowController { windowController.newWindowForTab(nil) if let newWindow = NSApp.keyWindow, currentWindow != newWindow { currentWindow.addTabbedWindow(newWindow, ordered: .above) } } } }
2
0
90
Apr ’25
Clearing Change Count in FileDocument?
I'm playing with a simple document-based application with TextEditor for macOS. In Cocoa, NSViewController can call updateChangeCount(_:) to clear document changes in NSDocument. I wonder SwiftUI's View has access to the same function? Hopefully, I would like to manually set the change count to zero if the user clears text in TextEditor. I bet SwiftUI doesn't have it. Thanks. import SwiftUI struct ContentView: View { @Binding var document: SampleDocumentApp var body: some View { VStack { TextEditor(text: $document.text) .onChange(of: document.text) { _, _ in guard !document.text.isEmpty else { return } // clear change count // } } .frame(width: 360, height: 240) } }
2
0
55
Apr ’25
Not Showing FileOpen with Document-
I have developed several document-based (NSDocument) applications for macOS is Cocoa. Now, I'm playing with a document app project in SwiftUI. If I launch the application out of box, a file-select panel will open just as you see in TextEdit. (Please see the picture below) How do we prevent it from appearing? I would rather show a blank window, which in fact appears if I just press Command + N. Thanks.
2
0
93
Apr ’25
Release Build Configuration as Release Fails Preview
I have a simple SwiftUI project with two basic build configurations (Debug, Release) as shown below. I now choose Build > Scheme > Edit Scheme under Product and select Release as the current build configuration as shown below. And the Preview canvas exhibit errors. If I click on the Diagnostics button, it says under PREVIEW UPDATE ERROR OptimizationLevelError: not building -Onone ”BuildSchemeCrazyDaughter.app” needs -Onone Swift optimization level to use previews (current setting is -O) What does that mean and why don't I get the preview for the Release build configuration? Thanks.
1
0
180
Mar ’25
Writing to Printer with Core Bluetooth
I have a very cheap Bluetooth-connected printer. And I want to print out a word or two via Core Bluetooth. It's an iOS app with the SwiftUI framework. The following is what I have for an ObservableObject class. import Foundation import CoreBluetooth class BluetoothManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeripheralDelegate { @Published var connectedDevices: [CBPeripheral] = [] @Published var powerOn = false @Published var peripheralConnected = false private var centralManager: CBCentralManager! private var peripheralName = "LX-D02" private var connectedPeripheral: CBPeripheral? private var writeCharacteristic: CBCharacteristic? private let serviceUUID = CBUUID(string:"5833FF01-9B8B-5191-6142-22A4536EF123") private let characteristicUUID = CBUUID(string: "FFE1") override init() { super.init() self.centralManager = CBCentralManager(delegate: self, queue: nil) } func startScanning() { if centralManager.state == .poweredOn { centralManager.scanForPeripherals(withServices: nil, options: nil) } } func centralManagerDidUpdateState(_ central: CBCentralManager) { if central.state == .poweredOn { powerOn = true print("Bluetooth is powered on") } else { print("Bluetooth is not available") } } func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) { if !connectedDevices.contains(peripheral) { if let localName = advertisementData["kCBAdvDataLocalName"] as? String { if localName == peripheralName { connectedDevices.append(peripheral) centralManager.connect(peripheral, options: nil) centralManager.stopScan() peripheralConnected = true print("Connected: \(peripheral.identifier.uuidString)") } } } } func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) { connectedPeripheral = peripheral peripheral.delegate = self let services = [serviceUUID] peripheral.discoverServices(services) //discoverServices(peripheral: peripheral) } func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: (any Error)?) { guard let error = error else { print("Failed connection unobserved") return } print("Error: \(error.localizedDescription)") } func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) { if let error = error { print("Failing to discover servies: \(error.localizedDescription)") return } discoverCharacteristics(peripheral: peripheral) } /* Return all available services */ private func discoverServices(peripheral: CBPeripheral) { peripheral.discoverServices(nil) } private func discoverCharacteristics(peripheral: CBPeripheral) { guard let services = peripheral.services else { return } for service in services { peripheral.discoverCharacteristics(nil, for: service) } } func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) { guard let characteristics = service.characteristics else { return } for characteristic in characteristics { let characteristicUUID = characteristic.uuid print("Discovered characteristic: \(characteristicUUID)") peripheral.setNotifyValue(true, for: characteristic) if characteristic.properties.contains(.writeWithoutResponse) { writeCharacteristic = characteristic print("You can write!!!") // Never read... } if characteristic.properties.contains(.write) { print("You can write?") writeCharacteristic = characteristic // Being read... } } func writeToPrinter() { guard let peripheral = connectedPeripheral else { print("Ughhh...") return } if let characteristic = writeCharacteristic { if let data = "Hello".data(using: .utf8, allowLossyConversion: true) { peripheral.writeValue(data, for: characteristic, type: .withoutResponse) peripheral.writeValue(data, for: characteristic, type: .withResponse) // -> Message sent successfully } } } func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) { if let error = error { print("Writing error: \(error.localizedDescription)") return } print("Message sent successfully") } } My app has no trouble connecting to the bluetooth-connected printer. Initially, I called discoverServices(peripheral:) to get all services And I get a service identifier (5833FF01-9B8B-5191-6142-22A4536EF123) for my printer. peripheral(_:didDiscoverCharacteristicsFor:error:) doesn't return a thing for .writeWithoutResponse but does return a characteristic for .write. Eventually, if I call writeToPrinter(), peripheral.writeValue(data, for: characteristic, type: .withoutResponse) returns WARNING: Characteristic <CBCharacteristic: 0x3019040c0, UUID = 5833FF02-9B8B-5191-6142-22A4536EF123, properties = 0x8, value = (null), notifying = NO> does not specify the "Write Without Response" property - ignoring response-less write If I call peripheral.writeValue(data, for: characteristic, type: .withResponse) , there is no error. But I get no output from the printer. What am I doing wrong? Thanks.
1
0
466
Jan ’25
Limiting the Number of Bool (True) Values
I have the following lines of code where I show a bunch of checkboxes, each of which can toggle between on and off with a tap. import SwiftUI struct ContentView: View { @State private var viewModel = ContentViewModel() var body: some View { VStack(alignment: .leading) { List { ForEach(viewModel.models, id: \.id) { model in CheckButtonView(id: model.id, text: model.name, isOn: model.isOn) { id, bool in updateDate(id: id, bool: bool) } } } } } func updateDate(id: String, bool: Bool) { for i in 0..<viewModel.models.count { let oldModel = viewModel.models[i] if oldModel.id == id { let newModel = Content(id: oldModel.id, name: oldModel.name, isOn: bool) viewModel.models.remove(at: i) viewModel.models.insert(newModel, at: i) break } } var count = 0 for i in 0..<viewModel.models.count { let model = viewModel.models[i] if model.isOn { count += 1 } } } } struct CheckButtonView: View { let id: String let text: String @State var isOn: Bool var callBack: (String, Bool) -> Void var body: some View { HStack { Button { isOn.toggle() callBack(id, isOn) } label: { Image(systemName: isOn ? "checkmark.square.fill" : "square") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 18) .tint(!isOn ? .black : .blue) } Text(text) .font(.subheadline) Spacer() } .frame(maxWidth: .infinity) } } struct Content { let id: String let name: String let isOn: Bool } class ContentViewModel: ObservableObject { @Published var models = [Content]() @Published var canChange = true init() { models = [ Content(id: UUID().uuidString, name: "Jim", isOn: false), Content(id: UUID().uuidString, name: "Jenny", isOn: false), Content(id: UUID().uuidString, name: "Nancy", isOn: false), Content(id: UUID().uuidString, name: "Natalie", isOn: false) ] } } According to the picture above, I have two checkboxes that are turned on. Now, what I want to do is let the user turn on as many as two checkboxes only. Can someone think of a good way of doing that? Thanks.
2
0
375
Nov ’24
Showing SwiftUI Below NSStatusItem When Button is Clicked on Over SwiftUI View
I see a lot of tutorials that show how to open a SwiftUI View when a NSStatusItem is clicked on. That's not what I want. I need to show a SwiftUI View when I click on a button over SwiftUI View. So far the following is what I have. import SwiftUI @main struct MyStatusApp_App: App { @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var body: some Scene { WindowGroup { ContentView() } } } #if os(macOS) class AppDelegate: NSObject, NSApplicationDelegate { var statusItem: NSStatusItem! private var popover: NSPopover? func applicationDidFinishLaunching(_ notification: Notification) { hideTitleBar() NSApp.setActivationPolicy(.accessory) statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) if let button = statusItem.button { if let image = NSImage(named: "statusImage") { button.image = image } } } #endif // ContentView // import SwiftUI struct ContentView: View { @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var body: some View { VStack { Button("Click me!") { let popOver = NSPopover() popOver.contentViewController = NSHostingController(rootView: NotificationView()) appDelegate.statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) if let statusBarbutton = appDelegate.statusItem.button { popOver.show(relativeTo: statusBarbutton.bounds, of: statusBarbutton, preferredEdge: .minY) } } } .frame(width: 200, height: 100) } } If I run the application and click on the button (orange arrow) over ContentView, a guy from NotificationView will appear (green rectangle). That's good. But it appears not below the status item (red arrow). It's positioned at an odd location. It's way below the status item guy. What am I doing wrong? Muchos thankos. I guess site's add image function is broken. It doesn't show my screenshot. ![]("https://developer.apple.com/forums/content/attachment/7e19bf2e-439d-4ed0-a03c-740b77e94e24" "title=Screenshot.jpg;width=364;height=400")
Topic: UI Frameworks SubTopic: SwiftUI Tags:
1
0
719
Aug ’24
All Item Row Positions After List onMove(perform:)
Using List to list an array of an object isn't a problem. For example, I have simple lines of code below to list an array of some guy. struct ContentView: View { @State private var selectedFieldItem: FieldItem? private var fieldListView: some View { List(selection: $selectedFieldItem) { ForEach(fieldItems.indices, id: \.self) { index in Button { ... } label: { let fieldItem = fieldItems[index] HStack(spacing: 10) { Text("\(fieldItem.name)") } .frame(maxWidth: .infinity, alignment: .leading) } .buttonStyle(.borderless) } .onMove(perform: fieldlocate) } .listStyle(.plain) } private func fieldlocate(from source: IndexSet, to destination: Int) { fieldItems.move(fromOffsets: source, toOffset: destination) } } As you see in the picture below, I can move a row up and down. A problem that I now have with List is that I cannot know how those rows are rearranged after one of them is moved up or down. In Cocoa, you can tell the positions of all rows after one moves with tableView(_:acceptDrop:row:dropOperation:) I think I have done the same in UIKit. Can we tell the current row numbers of List items in SwiftUI? Like Item 0 moves from Row 0 to Row 2 item 1 moves from Row 1 to Row 0 item 2 moves from Row 2 to Row 1 after one drags Item 0 from the top to the bottom? Muchos thankos.
Topic: UI Frameworks SubTopic: SwiftUI
1
0
398
Aug ’24
The Mystery of an Array of Strings and Escaped Characters
I have a very simple set of lines of code. It doesn't matter whether you run it under UIKit or SwiftUI. In SwiftUI, I have the following. import SwiftUI struct ContentView: View { var body: some View { VStack { Button("Click on me") { let tabLine = "1\tAnthony James\t139.9" var item = "" let tabs = tabLine.components(separatedBy: "\t") for tab in tabs { item += "'\(tab)'" } print("\(item)") } } } } So I have tab-separated values. And I want to separate them and quote each value either with an apostrophe or a double quotation mark. In the case above, I get the following print. '1''Anthony James''139.9' That's exactly what I want. Now, I have an array of three of those guys like the following. import SwiftUI struct ContentView: View { var body: some View { VStack { Button("Click on me") { let tabLine0 = "1\tAnthony James\t139.9" let tabLine1 = "2\tKim Harbaugh\t181.4" let tabLine2 = "3\tAnthony James\t212.4" let tabTextLines = [tabLine0, tabLine1, tabLine2] var strings = [String]() for tabLine in tabTextLines { var item = "" let tabs = tabLine.components(separatedBy: "\t") for tab in tabs { item += "'\(tab)'" } strings.append(item) } print("\(strings)") } } .frame(width: 360, height: 240) } } And I get the following print. This is a nightmare situation. Each value is quoted with an escaped apostrophe. I can't even remove the escapees with replacingOccurrences(of:with:). How does that happen when you have an array of strings? If I try quoting the values with a unicode character, things are the same. Is there a workaround? Muchos thankos.
4
0
532
Aug ’24
Button.background(Color) under the Light Appearance
I'm trying to set the background color of a button with label like the following for a macOS application. I haven't run it for iOS. VStack(spacing: 20) { HStack(spacing: 32) { Button { showGuide.toggle() } label: { Text("Hello") .font(.title3) .frame(width: 190, height: 36) } .foregroundStyle(.primary) .background(.yellow) .clipShape(.capsule) .shadow(color: .red, radius: 8) Button { } label: { Text("Good morning") .font(.title3) .frame(width: 190, height: 36) } .foregroundStyle(.primary) .background(.pink) .clipShape(.capsule) .shadow(color: .red, radius: 8) } } .frame(maxWidth: .infinity, alignment: .center) Interestingly, those two buttons have a white background color under the light appearance as shown below. And it will get the designated background color under the dark appearance as shown below. So why don't I get the buttons colored under the light appearance? I can't figure out why it happens. Does anybody know why? Thanks.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
1
0
548
Aug ’24
Send a Closure from NSViewRepresentable (or UIViewRepresentable) to ContentView?
I'm using NSTableView with NSViewRepresentable in my SwiftUI ContentView. I'm letting the user right-click on a table row such that the application will recognize the row number, which is achieved. The following is what I have so far. struct ContentView: View { @State private var rowSelection = -1 VStack { TableView(tableData: someData, selectedRow: $rowSelection) } } struct TableView: NSViewRepresentable { @Binding var tableData: [Dictionary<String, String>] @Binding var selectedRow: Int func makeNSView(context: Context) -> NSScrollView { let scrollView = NSScrollView(frame: .zero) let tableView = NSTableView() tableView.delegate = context.coordinator tableView.dataSource = context.coordinator let contextMenu = NSMenu() let copyRowMenuItem = NSMenuItem(title: "Copy Row", action: #selector(Coordinator.tableRowAction(_:)), keyEquivalent: "") contextMenu.addItem(copyRowMenuItem) copyRowMenuItem.target = context.coordinator tableView.menu = contextMenu scrollView.documentView = tableView scrollView.hasVerticalScroller = true scrollView.hasHorizontalScroller = true scrollView.autohidesScrollers = true return scrollView } func updateNSView(_ nsView: NSScrollView, context: Context) { } func makeCoordinator() -> Coordinator { return Coordinator(tableData: $tableData, tableInfo: $tableInfo, selectedRow: $selectedRow, rowSelected: $rowSelected) } class Coordinator: NSObject, NSTableViewDelegate, NSTableViewDataSource { @Binding var tableData: [Dictionary<String, String>] @Binding var selectedRow: Int init(tableData: Binding<[Dictionary<String, String>]>, tableInfo: Binding<[PragmaModel]>, selectedRow: Binding<Int>, rowSelected: Binding<Bool>) { self._tableData = tableData self._rowSelected = rowSelected } func numberOfRows(in tableView: NSTableView) -> Int { return tableData.count } func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? { for i in 0..<tableInfo.count { let col = NSString(format: "%i", i) as String let identifier = NSString(format: "Column%i", i) as String if ((tableColumn?.identifier)!.rawValue == identifier) { let data = tableData[row][col] return data } } return nil } func tableViewSelectionDidChange(_ notification: Notification) { let tv = notification.object as! NSTableView if tv.selectedRow >= 0 { selectedRow = tv.selectedRow } } @objc func tableRowAction(_ sender: Any) { // closure // } } } The contextual menu works. Yet, the application needs to know when a row is clicked on. So I want to send a closure back to ContentView. How can I do that, por favor? Muchos thankos.
1
0
505
Aug ’24