Post

Replies

Boosts

Views

Activity

System requirements for Xcode 14
I'm a bit confused about the minimum macOS version required to run Xcode 14. I don't know what the minimum macOS version to run it. In the meantime, it seems that macOS 13 beta requires a Mac computer with the Apple silicon. As for Xcode 14 beta, its details say "Xcode 14 beta includes everything you need to create amazing apps for all Apple platforms. It includes SDKs for iOS 16, iPadOS 16, tvOS 16, watchOS 9, and macOS 13." What does that mean as far as macOS 13 is concerned? Do we need a Mac with the Apple silicon to run Xcode 14? Thanks.
1
0
8.1k
Jun ’22
Files Selected with UIDocumentPickerViewController Ending Up in File Provider Storage [SwiftUI]
I often use security-scoped bookmarks when I develop a desktop application in Cocoa. This time, I need to use them in an iOS app, using SwiftUI framework. I don't quite remember the history, but I use UIDocumentPickerViewController through UIViewControllerRepresentable to let the user select a file. And I have a model where I save file name, file path, its bookmark (Data) with NSKeyedArchiver.. And everything goes well when I run the app in a simulator. Yet, FileManager says each file in the model does not exist. One of the path is something like the following. /private/var/mobile/Containers/Shared/AppGroup/749F05F0-12BC-40AC-B5C4-72571145C624/File Provider Storage/Test/somefile.txt Since it doesn't exist, I cannot even resolve it. How can I resolve the bookmark if a file ends up at the File Provider Storage folder? Do I need a special capability that I don't know about or something? Thanks.
1
0
643
Jul ’22
Observing a Call from ObservableObject without onChange
I have a simple case as follows. class Monster: ObservableObject { static let shared = Monster() @Published var selectionChanged = false } struct ContentView: View { @ObservedObject var monster = Monster.shared @State private var isOn = false var body: some View { VStack { Button { monster.selectionChanged.toggle() } label: { Text("Tap me") } .padding(.vertical, 60.0) SecondView() } } } struct SecondView: View { @StateObject var monster = Monster.shared var body: some View { VStack { Text("Hello") }.onChange(of: monster.selectionChanged) { _ in print("GGGG") } } } So SecondView receives a call from Monster with through onChange.. Is there a simpler approach where SecondView receives a call without it? Thanks.
1
0
1.2k
Aug ’22
Not Allowing Row Selection in List
In UIKit, it's just the matter of setting table view's allowsSelection to false if you don't want to allow selection. If each row has a button, it can still be clicked on. Can we do that in SwiftUI? I have the following simple SwiftUI project. import SwiftUI struct ContentView: View { @State private var fruits = ["Apple", "Banana", "Mango", "Watermelon", "Pineapple", "Strawberry", "Orange"] @State private var isEditable = true var body: some View { List { ForEach(fruits, id: \.self) { fruit in HStack { Text(fruit) .onDrag { return NSItemProvider() } Spacer() Button { print("Hello") } label: { Text("Tap me") } } } .onMove(perform: move) } .onTapGesture(perform: { return }) .listStyle(.plain) } func move(from source: IndexSet, to destination: Int) { fruits.move(fromOffsets: source, toOffset: destination) withAnimation { isEditable = false } } } The tap gesture prevents row interaction. So I won't even be able to tap the button. How can I disable row selection while allowing interaction inside the list row? List { } .onAppear { UITableView.appearance().allowsSelection = false UITableViewCell.appearance().selectionStyle = .none } The lines of code above don't work, either. Thanks.
1
0
2.2k
Aug ’22
Deleting a Row in the List with Data from Realm
I have created a very simple sample project just to make my point using RealmSwift.. // ContentView.swift // import SwiftUI import RealmSwift struct ContentView: View { @StateObject var viewModel = ViewModel() var body: some View { NavigationView { VStack { Spacer() NavigationLink("Listing all meals") { ListView() .environmentObject(viewModel) } Spacer() } } } } // ListView.swift // import SwiftUI import RealmSwift struct ListView: View { @EnvironmentObject var viewModel: ViewModel @State var meals = [MealDB]() var body: some View { List { ForEach(meals) { meal in HStack { Text("\(meal.title)") .padding(.leading, 6.0) Spacer() Button { viewModel.model.delete(id: meal.id) } label: { Text("Delete") } .padding(.trailing, 6.0) .buttonStyle(.borderless) } .onDrag { return NSItemProvider() } } .onMove(perform: move(from:to:)) } .onAppear { updateData() } } func updateData() { meals.removeAll() // data from Realm database for mealItem in viewModel.mealItems {// <<<<<<<<<< meals.append(mealItem) } meals.sort { (($0).place < (($1).place)) } } } // ViewModel.swift // import Foundation import RealmSwift class ViewModel: ObservableObject { @Published var model = MealStore() var mealItems: Results<MealDB> { model.items } } final class MealStore: ObservableObject { var config: Realm.Configuration init() { config = Realm.Configuration() } var realm: Realm { return try! Realm(configuration: config) } var items: Results<MealDB> { realm.objects(MealDB.self) } } // MealDB.swift // import Foundation import RealmSwift class MealDB: Object, Identifiable { @objc dynamic var id = "" @objc dynamic var title = "" @objc dynamic var order = 0 @objc dynamic var place = 0 override class func primaryKey() -> String? { "id" } } ListView has a list of meals. Each row comes with a button that lets me delete the corresponding row. And the app will crash inside the updateData function. I have found out that the issue is the way how SwiftUI works and hangs on to the old set of data even after I tap the delete button. So a solution is to 'freeze up' the dataset. And the app won't crash when I tap the delete button. for mealItem in viewModel.mealItems.freeze() { ... } Now, my question is... Are there reasons for not freezing up the dataset? If there is no downside, how come MongoDB just doesn't tell us to do it when we use access a dataset in Realm? Thanks.
1
0
783
Sep ’22
Reading a PSSliderSpecifier value in Settings Bundle
I didn't know that Settings Bundle exists till two days ago. Anyway, I've tested it with a simple example. As shown in the screenshot below, I have one group, one text field, one slider and two toggle buttons. I am able to read the values from all of them except the slider. I wonder if it's a bug? I'm using Xcode 14.2. In the following code, the app won't go inside the if clause for the PSSliderSpecifier key. import UIKit class ViewController: UIViewController { // MARK: - Life cyle override func viewDidLoad() { super.viewDidLoad() let defaultValues = [String: AnyObject]() UserDefaults.standard.register(defaults: defaultValues) } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) /* settings */ fetchSettingBundleData() } @objc func fetchSettingBundleData() { let userDefaults = UserDefaults.standard if let settingsURL = Bundle.main.url(forResource: "Root", withExtension: "plist", subdirectory: "Settings.bundle"), let settings = NSDictionary(contentsOf: settingsURL), let preferences = settings["PreferenceSpecifiers"] as? [NSDictionary] { var defaultsToRegister = [String: Any]() for preferenceSpecification in preferences { if let key = preferenceSpecification["Type"] as? String, let value = preferenceSpecification["Title"] { defaultsToRegister[key] = value } } userDefaults.register(defaults: defaultsToRegister) } if let groupName = userDefaults.string(forKey: "PSGroupSpecifier") { print("Group name: \(groupName)") } if let _ = userDefaults.string(forKey: "PSTextFieldSpecifier") { if let text = userDefaults.string(forKey: "name_preference") { print("Textfield \(text)") } } if let _ = userDefaults.string(forKey: "PSToggleSwitchSpecifier") { if let value = userDefaults.string(forKey: "enabled_preference1") { print("Toggle \(value)") // 0 or 1 } } if let _ = userDefaults.string(forKey: "PSToggleSwitchSpecifier") { if let value = userDefaults.string(forKey: "enabled_preference2") { print("Toggle2 \(value)") // 0 or 1 } } if let _ = userDefaults.string(forKey: "PSSliderSpecifier") { print("heck....") // No show if let value = userDefaults.string(forKey: "slider_preference") { print("Slider \(value)") } } } }
1
0
827
Jan ’23
Not Showing App Name in the Status Bar
I'm using the custom URL scheme to open my app through Safari. When the app appears, the status bar shows 'Safari' at the top-left corner. Is there a way of stopping the app from showing Safari's name? I don't want the user to tap the name and go back to Safari. There is nothing special in my SceneDelegate. So I wonder if it's probably the matter of settings in the Settings app? Thanks.
1
0
472
Apr ’23
Removing Apps from App Switcher?
I have a simple app that implements a custom URL scheme. When I enter the scheme for my app in Safari, the app will launch itself. So far, so good... Now, when I initiate the app switcher, I have my app and the web browser (Safari). Is there a way of not showing them in the app switcher? Or can I at least stop the web browser from appearing in the app switcher? Is it even possible for me to terminate Safari programmatically from my app, provided that that is not going to violate the app store guidelines? Thanks.
1
0
891
Apr ’23
DisclosureGroup with Swipe Actions and Contextual Menu
I have created a simple case to make my point as follows. import SwiftUI struct ContentView: View { var body: some View { ZStack { Color.yellow.ignoresSafeArea() VStack(alignment: .leading) { ForEach(Fruit.allCases, id: \.self) { fruit in DisclosureGroup(fruit.rawValue) { VStack { Text("1") Text("2") Text("3") } } .contextMenu { Button("Hello", action: { }) } } }.padding(.horizontal, 20) } } } enum Fruit: String, CaseIterable { case apple = "Apple" case grape = "Grape" case lemon = "Lemon" case orange = "Orange" case peach = "Peach" case pineapple = "Pineapple" case watermelon = "Watermelon" } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } What I want to do is show the contextual menu when the user long-presses a fruit name, which works. Yet, if I long-press a child inside the disclosure view, I also get the contextual menu, which is unintentional. Is there a simple way by which I can stop the contextual menu to appear if long-press a child inside the disclosure view? Muchos thankos
1
0
1.1k
Aug ’23
Making a Call to a Distant Struct
Let me say that I have three structs that are sequentially connected. ContentView -> FirstView -> SecondView And I want to make a call from SecondView to ContentView with a button tap. So I have the following lines of code. import SwiftUI struct ContentView: View { @State var goToFirst = false var body: some View { NavigationStack { VStack { NavigationLink { FirstView(callBack: { sayHello() }, goToSecond: $goToFirst) } label: { Text("Go to First") } } } .navigationDestination(isPresented: $goToFirst) { } } func sayHello() { print("Hello!") } } struct FirstView: View { @State var callBack: (() -> Void)? @Binding var goToSecond: Bool var body: some View { VStack { Button("Go to Second") { goToSecond.toggle() } } .navigationDestination(isPresented: $goToSecond) { SecondView(callBack: callBack) } } } struct SecondView: View { @State var callBack: (() -> Void)? var body: some View { VStack { Button("Tap me to make a call to ContentView") { callBack?() } } } } If I tap the button in SecondView, my ContentView will receive a call and call the sayHello function. Since ContentView and SecondView are not directly connected with each other, they have to through FirstView in this case. I wonder if there's a better or easier approach in having SecondView make a call to ContentView? In UIKit and Cocoa, you can make a delegate call to a distant class even when two classes are not directly connected with other. Using the notification is another option. In SwiftUI, I suppose you don't use either of them. Muchos thankos.
1
0
669
Sep ’23
Undo/Redo with DragGesture
I have a sample macOS app that I'm working on. I can run the exactly same lines of code below for iOS. For now, I'm running code for macOS since I can just press Command + z to undo the last action. Anyway, I have two Text View objects. Since TextView has the DragGesture gesture, I am able to freely move either of them. And I want to undo and redo their positions. So the following is what I have. import SwiftUI struct ContentView: View { @State var textViews: [TextView] = [TextView(text: "George"), TextView(text: "Susan")] var body: some View { VStack { ForEach(textViews, id: \.id) { textView in textView } } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } struct TextView: View { @Environment(\.undoManager) var undoManager @StateObject private var undoModel = UndoViewModel() @State private var dragOffset: CGSize = .zero @State private var position: CGSize = .zero let id = UUID() let text: String init(text: String) { self.text = text } var body: some View { ZStack { Text(text) .fixedSize() .padding(.vertical, 10) .offset(x: dragOffset.width + position.width, y: dragOffset.height + position.height) .gesture( DragGesture() .onChanged { self.dragOffset = $0.translation } .onEnded( { (value) in self.position.width += value.translation.width self.position.height += value.translation.height self.dragOffset = .zero undoModel.registerUndo(CGSize(width: position.width, height: position.height), in: undoManager) }) ) } } } class UndoViewModel: ObservableObject { @Published var point = CGSize.zero func registerUndo(_ newValue: CGSize, in undoManager: UndoManager?) { let oldValue = point undoManager?.registerUndo(withTarget: self) { [weak undoManager] target in target.point = oldValue // registers an undo operation to revert to old text target.registerUndo(oldValue, in: undoManager) // this makes redo possible } undoManager?.setActionName("Move") point = newValue // update the actual value } } Well, if I press Command + z after moving one of them, it won't return to the last position. What am I doing wrong? Muchos thankos.
1
0
661
Sep ’23
List with ForEach Enumeration
When I enumerate an array of objects with ForEach, I often wonder how I use the array. For example, I have the following lines of code. import SwiftUI struct ContentView: View { @State var checkItems: [CheckItem] = [ .init("Susan"), .init("Meagan"), .init("Daniel") ] var body: some View { List() { ForEach(0..<checkItems.count, id: \.self) { index in HStack { Image(systemName: !checkItems[index].selected ? "circle" : "checkmark.circle.fill") .resizable() .scaledToFit() .frame(height: 24) .foregroundColor(!checkItems[index].selected ? .gray : .blue) .onTapGesture { checkItems[index].selected.toggle() } Text(checkItems[index].name) } } } } } struct CheckItem: Identifiable, Hashable { var id = UUID() var selected: Bool var name: String init(_ name: String) { self.selected = false self.name = name } } The code works as shown in the following image. In the following lines of code, I'm enumerating the same array in a slightly different fashion. struct ContentView: View { @State var checkItems: [CheckItem] = [ .init("Susan"), .init("Meagan"), .init("Daniel") ] var body: some View { List() { ForEach(checkItems, id: \.id) { item in HStack { Image(systemName: !item.selected ? "circle" : "checkmark.circle.fill") .resizable() .scaledToFit() .frame(height: 24) .foregroundColor(!item.selected ? .gray : .blue) .onTapGesture { //item.selected.toggle() // Cannot use mutating member on immutable value: 'item' is a 'let' constant } Text(item.name) } } } } } And I get an error in the line inside the onTapGesture guy. I wonder why the first section of code works and why second section doesn't? Muchos thankos.
1
0
733
Sep ’23
How to Detect the Retina Display for macOS in SwiftUI
In Cocoa, you can find out whether or not you have a Retina screen with the backingScaleFactor property like the following. func getWinFactor() -> CGFloat? { if let view = self.view.window { let factor = view.backingScaleFactor return factor } else { return nil } } How could we detect whether or not the application is dealing with a Retina screen in SwiftUI? I thought the displayScale Environment property is the chosen one. But my 27-inch iMac with a Retina display will return the scale as 1.0. import SwiftUI struct ContentView: View { @Environment(\.displayScale) var displayScale var body: some View { VStack { ... } .onAppear { print("display scale: \(displayScale)") // Returning 1.0 } } } Do I miss something with this environment guy? Muchos thankos.
1
1
1.1k
Oct ’23
URLSession ViewModel with Loading State
I have a test app that is supposed to list a bunch of iTunes music records. I have existing lines of code that successfully load data. Now, I'm adding a loading state to them. As a result, I have the following lines code. import SwiftUI struct iTunesView: View { @StateObject var viewModel = iTunesViewModel() var body: some View { switch viewModel.state { case .idle: EmptyView() case .loading: ProgressView() case .loaded(let results): List { ForEach(results, id: \.self) { result in Text("\(result.trackId)") Text(result.trackName) .lineLimit(0) } } case .failed(let error): Text(error.localizedDescription) } } } @MainActor class iTunesViewModel: ObservableObject { enum LoadingState { case idle case loading case loaded([iTunesResult]) case failed(Error) } @Published var state: LoadingState = .idle init() { state = .loading Task { await fetchMusic() } } func fetchMusic() async { guard let url = URL(string: "https://itunes.apple.com/search?term=classical+music&entity=song") else { state = .failed(URLError(.badURL)) return } do { let urlRequest = URLRequest(url: url, timeoutInterval: 1.0) let (data, _) = try await URLSession.shared.data(for: urlRequest) let music = try JSONDecoder().decode(iTunesResponse.self, from: data) self.state = .loaded(music.results) print("\(music.results)") } catch { state = .failed(error) } } } struct iTunesResponse: Codable { let resultCount: Int let results: [iTunesResult] } struct iTunesResult: Codable, Hashable { var trackId: Int var trackName: String var collectionName: String } enum iTunesError: Error { case badURL case decoding case invalidHTTPResponse case badData(statusCode: Int) case badRequest(statusCode: Int) case redirection(statusCode: Int) case server(statusCode: Int) case error(String) } For some reason, the app just shows a spinner although it reaches the print line in the fetchMusci function and print the string data. I wonder what I'm doing wrong? With the code lines above, an app is fully functional except it will show the progress guy, you know? I've made changes after reading this Stack overflow topic. Thanks.
1
0
561
Nov ’23
Callback from onTapGesture Through Framework
I've found a simple example at YouTube (https://www.youtube.com/watch?v=ddp1jwkDwr8) as to create a framework. The following example does NOT use a framework. import SwiftUI struct ContentView: View { @State private var selectedColor: Color = .clear var body: some View { VStack { ColorSelectorView(selectedColor: $selectedColor) { color in print("**** \(color)") } } } } import SwiftUI struct ColorSelectorView: View { @Binding var selectedColor: Color @State var callBack: ((Color) -> Void)? let colors: [Color] = [.blue, .green, .orange, .yellow, .red, .purple] var body: some View { HStack { ForEach(colors, id: \.self) { color in Image(systemName: selectedColor == color ? "record.circle.fill" : "circle.fill") .foregroundColor(color) .onTapGesture { selectedColor = color callBack?(color) } } } } } #Preview { ColorSelectorView(selectedColor: .constant(.red)) } If I select a color, ContentView will receive a call back as to which color has been selected. So far, so good... Now, I want to make the ColorSelectorView part a framework. ContentView doesn't change. The following is the framework part. import SwiftUI public struct ColorSelectorView: View { @Binding var selectedColor: Color @State var callBack: ((Color) -> Void)? let colors: [Color] = [.blue, .green, .orange, .yellow, .red, .purple] public init(selectedColor: Binding<Color>, callBack: ((Color) -> Void)? = nil) { self._selectedColor = selectedColor self.callBack = callBack } public var body: some View { HStack { ForEach(colors, id: \.self) { color in Image(systemName: selectedColor == color ? "record.circle.fill" : "circle.fill") .foregroundColor(color) .onTapGesture { selectedColor = color callBack?(color) } } } } } struct ColorSelectorView_Previews: PreviewProvider { static var previews: some View { ColorSelectorView(selectedColor: .constant(.red)) } } Running ContentView with a framework, it doesn't receive a call back. What am I doing wrong? Muchos thankos.
1
0
771
Nov ’23