Post

Replies

Boosts

Views

Activity

Unarchiving an object with custom classes
I have a custom class named CodeReadModel, which contains another custom class named CodeDataModel. The former contains the latter as an array like the following. class CodeReadModel: NSObject, NSSecureCoding { class var supportsSecureCoding: Bool { true } let identifier: String let codeDataModels: [CodeDataModel] init(identifier: String, codeDataModels: [CodeDataModel]) { self.identifier = identifier self.codeDataModels = codeDataModels } required init(coder decoder: NSCoder) { self.identifier = decoder.decodeObject(forKey: "identifier") as! String self.codeDataModels = decoder.decodeObject(forKey: "codeDataModels") as! [CodeDataModel] } func encode(with coder: NSCoder) { coder.encode(identifier, forKey: "identifier") coder.encode(codeDataModels, forKey: "codeDataModels") } } And I want to unarchive an object with the following. func importCodeReaderSnippetNext(fileURL: URL) { do { NSKeyedUnarchiver.setClass(CodeReadModel.self, forClassName: "CodeReadModel") NSKeyedUnarchiver.setClass(CodeDataModel.self, forClassName: "CodeDataModel") let data = try! Data(contentsOf: fileURL) if let codeReadModel = try NSKeyedUnarchiver.unarchivedObject(ofClass: CodeReadModel.self, from: data) { } } catch { print("Error: \(error.localizedDescription)") } } And I will get an error because codeReadModel contains another custom class, which cannot be decoded. How can I resolve this problem? Muchas thankos.
7
0
869
Jul ’24
WidgetKit with Data from CoreData
I have a SwiftUI app. It fetches records through CoreData. And I want to show some records on a widget. I understand that I need to use AppGroup to share data between an app and its associated widget. import Foundation import CoreData import CloudKit class DataManager { static let instance = DataManager() let container: NSPersistentContainer let context: NSManagedObjectContext init() { container = NSPersistentCloudKitContainer(name: "DataMama") container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: group identifier)!.appendingPathComponent("Trash.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)") } } } // ViewModel // import Foundation import CoreData import WidgetKit class ViewModel: ObservableObject { let manager = DataManager() @Published var records: [Little] = [] init() { fetchRecords() } func fetchRecords() { let request = NSFetchRequest<Little>(entityName: "Little") do { records = try manager.context.fetch(request) records.sort { lhs, rhs in lhs.trashDate! < rhs.trashDate! } } catch { print("Fetch error for DataManager: \(error.localizedDescription)") } WidgetCenter.shared.reloadAllTimelines() } } So I have a view model that fetches data for the app as shown above. Now, my question is how should my widget get data from CoreData? Should the widget get data from CoreData through DataManager? I have read some questions here and also read some articles around the world. This article ( https://dev.classmethod.jp/articles/widget-coredate-introduction/ ) suggests that you let the Widget struct access CoreData through DataManager. If that's a correct fashion, how should the getTimeline function in the TimelineProvider struct get data? This question also suggests the same. Thank you for your reading my question.
7
0
256
2w
NWPathMonitor Failing
I need to check the network connection with NWPathMonitor. import Foundation import Network class NetworkViewModel: ObservableObject { let monitor = NWPathMonitor() let queue = DispatchQueue(label: "NetworkViewModel") @Published var isConnected = false var connectionDescription: String { if isConnected { return "You are connected." } else { return "You are NOT connected." } } init() { monitor.pathUpdateHandler = { path in DispatchQueue.main.async { self.isConnected = path.status == .satisfied } } monitor.start(queue: queue) } } import SwiftUI struct ContentView: View { @StateObject private var networkViewModel = NetworkViewModel() var body: some View { VStack { } .onAppear { if networkViewModel.isConnected { print("You are connected.") } else { print("You are NOT connected.") } } } } So there is nothing special, not at all. Yet, if I test it with a totally new Xcode project for iOS, it fails and return !isConnected. I've tested it with a macOS application. And it fails. I've tested it with an actual device. It fails. I've tested it with an old project. It still does work. I have no mere idea why new Xcode projects all fail to detect the WiFi connection. This is a total nightmare. Does anybody have a clue? thanks.
7
0
237
May ’25
Too Complex To Check Code in Reasonable Time?
Again, I have a vertical stack of horizontal stacks of buttons as follows. import SwiftUI struct ContentView: View { &#9;&#9;@State private var eventPresented = Bool() &#9;&#9;@State private var selectedEventIndex = Int() &#9;&#9;@State private var monthSelection = Int() &#9;&#9; &#9;&#9;var body: some View { &#9;&#9;&#9;&#9;VStack { &#9;&#9;&#9;&#9;&#9;&#9;VStack(spacing: 0.0) { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;HStack(spacing: 0.0) { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;ForEach((0...6), id: \.self) { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;index in &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;Button(buttonTitles[index] ?? "") { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;eventPresented = true &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;selectedEventIndex = index + 1 - self.weekIndex &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.foregroundColor(titleColors[index]) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.overlay(Text(eventNumbers[index] ?? "").font(.footnote).foregroundColor(.blue).offset(x: -16, y: -16)) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.buttonStyle(BorderlessButtonStyle()) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.frame(width: 48, height: 48, alignment: .center) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.background(RoundedRectangle(cornerRadius: 2) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.fill(fillColors[index]) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.shadow(color: shadowColors[index], radius: 2, x: 0, y: 0) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.sheet(isPresented: $eventPresented) { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;EventView(eventVisible: self.$eventPresented, dayFromParent: self.$selectedEventIndex, monthFromParent: self.$monthSelection) &#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;} &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;... &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;... &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;HStack(alignment: .top, spacing: 0.0) { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;ForEach((35...36), id: \.self) { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;index in &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;Button(buttonTitles[index] ?? "") { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;eventPresented = true &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;selectedEventIndex = index + 1 - self.weekIndex &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.foregroundColor(titleColors[index]) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.overlay(Text(eventNumbers[index] ?? "").font(.footnote).foregroundColor(.blue).offset(x: -16, y: -16)) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.buttonStyle(BorderlessButtonStyle()) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.frame(width: 48, height: 48, alignment: .center) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.background(RoundedRectangle(cornerRadius: 2) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.fill(fillColors[index]) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.shadow(color: shadowColors[index], radius: 2, x: 0, y: 0) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.sheet(isPresented: $eventPresented) { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;EventView(eventVisible: self.$eventPresented, dayFromParent: self.$selectedEventIndex, monthFromParent: self.$monthSelection) &#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;} &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.frame(width: 336.0, height: 48.0, alignment: .leading) &#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;} &#9;&#9;} } And I want to send a few variables to EventView when the user clicks on a button. struct EventView: View { &#9;&#9;@Binding var eventVisible: Bool &#9;&#9;@Binding var dayFromParent: Int &#9;&#9;@Binding var monthFromParent: Int &#9;&#9;var body: some View { &#9;&#9;&#9;&#9;VStack { &#9;&#9;&#9;&#9;&#9;&#9;Text("Window sheet.") &#9;&#9;&#9;&#9;&#9;&#9;Button("OK") { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;self.eventVisible = false &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;print("month from parent: \(monthFromParent)") &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;print("day from parent: \(dayFromParent)") &#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;.frame(width: 240, height: 180) &#9;&#9;} } If I just want to send two variables to it, EventView(eventVisible: self.$eventPresented, dayFromParent: self.$selectedEventIndex) the compiler didn't complain. For the third variable, it says SwiftUI the compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions I know what it means. Some say it could resolve the issue by making the data types of variables clearer. Others say you could use a function to return a variable for a somewhat complex algebra equation. But what can I do in my case? Does anybody have any suggestions? Thank you
6
0
805
Jan ’21
Using Combine-Future to Fetch Server Data
I could do it with completionHandler, but I'm trying to get server data with Combine. The following is what I have. // UIViewController // import UIKit import Combine class ViewController: UIViewController { // MARK: - Variables private var cancellableSet: Set<AnyCancellable> = [] // MARK: - Life cycle override func viewDidLoad() { super.viewDidLoad() let urlStr = "https://api.github.com/repos/ReactiveX/RxSwift/events" let viewModel = ViewModel(urlStr: urlStr, waitTime: 2.0) viewModel.fetchData(urlText: viewModel.urlStr, timeInterval: viewModel.waitTime) .sink { completion in print("complete") } receiveValue: { dataSet in print("count: \(dataSet)") } .store(in: &cancellableSet) print("Yeah...") } } struct DataModel: Hashable, Decodable { let id: String let type: String } // ViewModel // import UIKit import Combine class ViewModel: NSObject { var cancellables = [AnyCancellable]() var urlStr: String var waitTime: Double init(urlStr: String, waitTime: Double) { self.urlStr = urlStr self.waitTime = waitTime } func fetchData(urlText: String, timeInterval: Double) -> Future<[DataModel], Error> { return Future<[DataModel], Error> { [weak self] promise in guard let strongSelf = self else { return } if let url = URL(string: urlText) { var request = URLRequest(url: url) request.timeoutInterval = timeInterval let sessionConfiguration = URLSessionConfiguration.default let publisher = URLSession(configuration: sessionConfiguration).dataTaskPublisher(for: request) publisher.sink { completion in print("complete") } receiveValue: { (data: Data, response: URLResponse) in do { let dataModels = try JSONDecoder().decode([DataModel].self, from: data) promise(.success(dataModels)) } catch { print("Error while parsing: \(error)") promise(.failure("Failure" as! Error)) } } .store(in: &strongSelf.cancellables) } else { promise(.failure("Failure" as! Error)) } } } } If I run it, I don't get an error. The app doesn't crash, either. The view controller doesn't deliver anything. What am I doing wrong? Muchos thankos.
6
0
1.8k
Dec ’21
Binding<String>, set, get?
I have three sets of Text and TextField. And I need to filter each TextField entry. I have gotten a function to filter the TextField entry from this website (https://zenn.dev/yorifuji/articles/swiftui-textfield-filter). Finally, I have the following lines of code. import SwiftUI struct ContentView: View { @State var username = "" @State var password = "" @State var tenantID = "" var body: some View { VStack { makeForm(label: "Username: ", placeHolder: "123456", text: $username) makeForm(label: "Password: ", placeHolder: "abcdefg", text: $password) makeForm(label: "Shop ID: ", placeHolder: "123456", text: $tenantID) }.padding(.horizontal, 40.0) } @ViewBuilder private func makeForm(label: String, placeHolder: String, text: Binding<String>) -> some View { HStack { let newText = Binding<String>( get: { text.wrappedValue }, set: { filter(value: $0) } ) Text(label) TextField(placeHolder, text: newText) } } func filter(value: String) -> String { let validCodes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" let sets = CharacterSet(charactersIn: validCodes) return String(value.unicodeScalars.filter(sets.contains).map(Character.init)) } } Well, I don't know how to use the Binding with get and set, which I believe is what I need. Yet, I get a warning at the following line. set: { filter(value: $0) } What I need to do is set the filtered value to each TextField. What am I doing wrong? Thanks.
6
0
1.3k
May ’22
Showing Multiple Instances of View and Showing Results from Them
I have the following lines of code to show multiple instances of View (MyTextView) import SwiftUI struct ContentView: View { @State var myTextViews = [MyTextView]() var body: some View { VStack { Button { } label: { Text("Show me your current text strings") }.padding(.vertical, 10.0) VStack { ForEach(0 ..< myTextViews.count, id: \.self) { _ in MyTextView() } } Button { myTextViews.append(MyTextView()) } label: { Text("Add me!") }.padding(.vertical, 10.0) } } } struct MyTextView: View { @State var text = "" var body: some View { ZStack { TextField("Enter some text", text: $text) }.padding(.horizontal, 50.0) } } According to the screenshot, I have three instances, each of which contains TextField. After I tap the top button (Show me your current...), I want to show the result from each TextField. How can I do that? Thanks.
5
0
1.2k
Apr ’22
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 an NSViewController as a Sheet
I have a SwiftUI desktop application. And I need to open a window sheet from a storyboard with a click of a button, which works. But I have a problem. The opening window sheet is very big. Its size is 1,400 x 300 pixels. (I don't know the exact height.) I don't know where this size comes from. But I need to make it smaller. If I try to do it with the view controller, it doesn't work. How can I control the opening window sheet size? // SwiftUI View // import SwiftUI struct ContentView: View { &#9;&#9;@State private var sheetPresented = false &#9;&#9;@State private var selectionIndex = 3 &#9;&#9; &#9;&#9;var body: some View { &#9;&#9;&#9;&#9;ZStack { &#9;&#9;&#9;&#9;&#9;&#9;VStack { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;Button(action: { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;sheetPresented = true &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;}) { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;Text("Show me a sheet") &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;.sheet(isPresented: $sheetPresented) { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;SheetViewControllerRepresentation(message: String(selectionIndex)) &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;}.frame(minWidth: 360, idealWidth: 360, maxWidth: 360, minHeight: 240, idealHeight: 240, maxHeight: 240, alignment: .center) &#9;&#9;} } // View controller // import Cocoa import SwiftUI class SheetViewController: NSViewController { &#9;&#9;// MARK: - &#9;&#9;var message = String() &#9;&#9;&#9;&#9; &#9;&#9;// MARK: - IBOutlet &#9;&#9;@IBOutlet weak var messageLabel: NSTextField! &#9;&#9;// MARK: - IBAction&#9;&#9; &#9;&#9;@IBAction func closeClicked(_ sender: NSButton) { &#9;&#9;&#9;&#9;/* closing window */ &#9;&#9;&#9;&#9;self.view.window?.setIsVisible(false) &#9;&#9;&#9;&#9;self.view.window?.close() &#9;&#9;} &#9;&#9;// MARK: - Life cycle &#9;&#9;override func viewDidLoad() { &#9;&#9;&#9;&#9;super.viewDidLoad() &#9;&#9;&#9;&#9;// Do view setup here. &#9;&#9;} &#9;&#9; &#9;&#9;override func viewWillAppear() { &#9;&#9;&#9;&#9;super.viewWillAppear() &#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;messageLabel.stringValue = message &#9;&#9;} &#9;&#9; &#9;&#9;override func viewDidAppear() { &#9;&#9;&#9;&#9;super.viewDidAppear() &#9;&#9;&#9;&#9; &#9;&#9;&#9;&#9;view.setFrameSize(CGSize(width: 320, height: 220)) &#9;&#9;} } struct SheetViewControllerRepresentation: NSViewControllerRepresentable { &#9;&#9;var message = String() &#9;&#9; &#9;&#9;func makeNSViewController(context: NSViewControllerRepresentableContext<SheetViewControllerRepresentation>) -> SheetViewController { &#9;&#9;&#9;&#9;let mainStoryboard = NSStoryboard(name: "Main", bundle: nil) &#9;&#9;&#9;&#9;let sheetViewController = mainStoryboard.instantiateController(withIdentifier: "SheetView") as! SheetViewController &#9;&#9;&#9;&#9;sheetViewController.message = self.message &#9;&#9;&#9;&#9;return sheetViewController &#9;&#9;} &#9;&#9; &#9;&#9;func updateNSViewController(_ nsViewController: SheetViewController, context: NSViewControllerRepresentableContext<SheetViewControllerRepresentation>) { &#9;&#9;} } Thank you.
4
0
1.1k
Dec ’20
List Single Selection
I have some lines of code below where I can make multiple selections. import SwiftUI struct ContentView: View { @State private var selectedUsers: Set<String> = [] @State var users = ["Susan", "Kate", "Natalie", "Kimberly", "Taylor", "Sarah", "Nancy", "Katherine", "Nicole", "Linda", "Jane", "Mary", "Olivia", "Barbara"] var body: some View { VStack { List(selection: $selectedUsers) { ForEach(users, id: \.self) { user in Text(user) } } .environment(\.editMode, .constant(.active)) } } } So the blue selection symbol appears as shown in the screenshot above. That's good. But that's not what I'm after. I just want to select one row at a time. import SwiftUI struct ContentView: View { @State var selectedUser: String? @State var users = ["Susan", "Kate", "Natalie", "Kimberly", "Taylor", "Sarah", "Nancy", "Katherine", "Nicole", "Linda", "Jane", "Mary", "Olivia", "Barbara"] var body: some View { VStack { List(selection: $selectedUser) { ForEach(users, id: \.self) { user in Text(user) } } .environment(\.editMode, .constant(.active)) } } } In the lines of code above, I only let myself select one row at a time. And I don't get the blue selection symbol. I wonder why? I find two or three websites where they have similar lines of code and where they select one row at a time. And they have the blue selection symbol. Why don't I get it? Mucho thankos for reading.
4
0
1.3k
Jul ’23
Heavy Duty Work With Async Await
I am perplexed as to how to use async await. In the following example, I don't use GCD or performSelector(inBackground:with:). The view controller is NSViewController, but it doesn't make any difference if it's NSViewController or UIViewController. import Cocoa class ViewController: NSViewController { func startWriteImages() { Task{ let bool = await startWriteImagesNext() if bool { print("I'm done!") } } } func startWriteImagesNext() async -&gt; Bool { // pictures is a path to a folder in the sandbox folder // appDelegate.defaultFileManager is a variable pointing to FileManager.default in AppDelegate let pictURL = URL(fileURLWithPath: pictures) if let filePaths = try? self.appDelegate.defaultFileManager.contentsOfDirectory(atPath: pictURL.path) { for file in filePaths { let fileURL = pictURL.appending(component: file) if self.appDelegate.defaultFileManager.fileExists(atPath: fileURL.path) { let newURL = self.folderURL.appending(component: file) do { try self.appDelegate.defaultFileManager.copyItem(at: fileURL, to: newURL) } catch { print("Ugghhh...") } } } return true } return false } func startWriteImagesNext2() async -&gt; Bool { let pictURL = URL(fileURLWithPath: pictures) if let filePaths = try? self.appDelegate.defaultFileManager.contentsOfDirectory(atPath: pictURL.path) { DispatchQueue.global().async() { for file in filePaths { let fileURL = pictURL.appending(component: file) if self.appDelegate.defaultFileManager.fileExists(atPath: fileURL.path) { let newURL = self.folderURL.appending(component: file) do { try self.appDelegate.defaultFileManager.copyItem(at: fileURL, to: newURL) } catch { print("Ugghhh...") } } } } return true } return false } } In the code above, I'm saving each file in the folder to user-selected folder (self.folderURL). And the application will execute the print guy only when work is done. Since it's heavy-duty work, I want to use CCD or performSelector(inBackground:with:). If I use the former (startWriteImagesNext2), the application will execute the print guy right at the beginning. I suppose I cannot use GCD with async. So how can I perform heavy-duty work? Muchos thankos.
4
0
1.3k
Feb ’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
Opening FileDocument with URL → should only be called in the main thread
Its document says openDocument can open a document at a specific URL. So I've saved a model as a JSON object with its URL and a bookmark as Data. With its security-scoped bookmark data resolved, I am able to open a document except that the app will crash right after opening a document. Console says should only be called in the main thread struct ContentView: View { @EnvironmentObject var bookmarkViewModel: BookmarkViewModel var body: some View { VStack { } .onAppear { loadBookmarks() } } extension ContentView { func loadBookmarks() { print("1 \(Thread.current)") // NSMainThread Task { for bookmarkItem in bookmarkViewModel.bookmarkItems { // resolving a security-scoped bookmark print("2 \(Thread.current)") // NSMainThread if let _ = resolveBookmark(bookmarkData: bookmarkItem.bookmarkData) { print("3 \(Thread.current)") // NSMainThread do { print("4 \(Thread.current)") // NSMainThread try await openDocument(at: bookmarkItem.bookmarkURL) print("5 \(Thread.current)") // NSMainThread } catch { print("\(error.localizedDescription)") } } } } } } Well, the application is on the main thread. I've checked every line before and after opening a document with its URL. Call what on the main thread? This is confusing. Thanks. class BookmarkViewModel: ObservableObject { @Published var bookmarkItems: [BookmarkItem] = [] var defaultFileManager: FileManager { return FileManager.default } var documentURL: URL? { ... } init() { fetchBookmarkItems() } func fetchBookmarkItems() { bookmarkItems.removeAll() if let documentURL { let bookmarkFolderURL = documentURL.appending(path: "MyApp").appending(path: "Bookmarks") do { let contents = try defaultFileManager.contentsOfDirectory(atPath: bookmarkFolderURL.path) for content in contents { ... let fileURL = bookmarkFolderURL.appending(path: content) let data = try Data(contentsOf: fileURL) let bookmarkItem = try JSONDecoder().decode(BookmarkItem.self, from: data) bookmarkItems.append(bookmarkItem) } } catch { print("Error fetching folder content: \(error.localizedDescription)") } } } } struct BookmarkItem: Codable, Hashable { let bookmarkURL: URL let date: Date let bookmarkData: Data let open: Bool }
4
0
110
May ’25
Projecting a Cube with a Number in ARKit
I'm a novice in RealityKit and ARKit. I'm using ARKit in SwiftUI to show a cube with a number as shown below. import SwiftUI import RealityKit import ARKit struct ContentView : View { var body: some View { return ARViewContainer() } } #Preview { ContentView() } struct ARViewContainer: UIViewRepresentable { typealias UIViewType = ARView func makeUIView(context: UIViewRepresentableContext<ARViewContainer>) -> ARView { let arView = ARView(frame: .zero, cameraMode: .ar, automaticallyConfigureSession: true) arView.enableTapGesture() return arView } func updateUIView(_ uiView: ARView, context: UIViewRepresentableContext<ARViewContainer>) { } } extension ARView { func enableTapGesture() { let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(recognizer:))) self.addGestureRecognizer(tapGestureRecognizer) } @objc func handleTap(recognizer: UITapGestureRecognizer) { let tapLocation = recognizer.location(in: self) // print("Tap location: \(tapLocation)") guard let rayResult = self.ray(through: tapLocation) else { return } let results = self.raycast(from: tapLocation, allowing: .estimatedPlane, alignment: .any) if let firstResult = results.first { let position = simd_make_float3(firstResult.worldTransform.columns.3) placeObject(at: position) } } func placeObject(at position: SIMD3<Float>) { let mesh = MeshResource.generateBox(size: 0.3) let material = SimpleMaterial(color: UIColor.systemRed, roughness: 0.3, isMetallic: true) let modelEntity = ModelEntity(mesh: mesh, materials: [material]) var unlitMaterial = UnlitMaterial() if let textureResource = generateTextResource(text: "1", textColor: UIColor.white) { unlitMaterial.color = .init(tint: .white, texture: .init(textureResource)) modelEntity.model?.materials = [unlitMaterial] let id = UUID().uuidString modelEntity.name = id modelEntity.transform.scale = [0.3, 0.1, 0.3] modelEntity.generateCollisionShapes(recursive: true) let anchorEntity = AnchorEntity(world: position) anchorEntity.addChild(modelEntity) self.scene.addAnchor(anchorEntity) } } func generateTextResource(text: String, textColor: UIColor) -> TextureResource? { if let image = text.image(withAttributes: [NSAttributedString.Key.foregroundColor: textColor], size: CGSize(width: 18, height: 18)), let cgImage = image.cgImage { let textureResource = try? TextureResource(image: cgImage, options: TextureResource.CreateOptions.init(semantic: nil)) return textureResource } return nil } } I tap the floor and get a cube with '1' as shown below. The background color of the cube is black, I guess. Where does this color come from and how can I change it into, say, red? Thanks.
4
0
144
Jul ’25