Post

Replies

Boosts

Views

Activity

SwiftUI - What is Identifiable?
I have the following simple lines of code. import SwiftUI struct ContentView: View { var users = ["Susan", "Kate", "Natalie", "Kimberly", "Taylor", "Sarah", "Nancy", "Katherine", "Nicole", "Linda", "Jane", "Mary", "Olivia", "Barbara"] var body: some View { List { ForEach(users, id: \.self) { user in Text(user) } } } } So I'm just listing names. What I want to ask is what is id and what .self means. If I look up the doc under ForEach, it says the following. Either the collection’s elements must conform to Identifiable or you need to provide an id parameter to the ForEachinitializer. Does the compiler automatically generate a unique string like UUID for each element in the array or something? Can I somehow print the raw value of each id? Muchos thankos.
1
0
3.4k
Sep ’21
Updating @State Variable Depending ForEach Row Selection
import SwiftUI struct ContentView: View { @State var numbers = [2021, 9, 30] var body: some View { //let firstLocalYear = 2021 let firstLocalMonth = 9 let firstLocalDay = 24 let firstLastDay = 30 NavigationView { List { Section(header: Text("Current month")) { ForEach(firstLocalDay ..< firstLastDay) { i in HStack { Text("\(firstLocalMonth)-\(i + 1)") Spacer() NavigationLink( destination: TimeView(numbers: $numbers), label: { Text("") }) } } } } } } } struct TimeView: View { @Binding var numbers: [Int] var body: some View { HStack { Text(String(numbers[0])) Text(String(numbers[1])) Text(String(numbers[2])) } } } I have the lines of code above to list some rows of text. For now, numbers is a state variable that is pre-determined. This state variable is passed on to TimeView. Actually, I want to change this array depending on which row the user selects like numbers = [firstLocalYear, firstLocalMonth, i] where i comes from the ForEach thing. How can I change this array? Muchos thankos.
1
0
436
Sep ’21
Why Do We Need to Specify Schedule?
Hola, I have the following simple lines of code. import UIKit import Combine class ViewController: UIViewController { // MARK: - Variables var cancellable: AnyCancellable? @Published var labelValue: String? // MARK: - IBOutlet @IBOutlet weak var textLabel: UILabel! // MARK: - IBAction @IBAction func actionTapped(_ sender: UIButton) { labelValue = "Jim is missing" } // MARK: - Life cycle override func viewDidLoad() { super.viewDidLoad() cancellable = $labelValue .receive(on: DispatchQueue.main) .assign(to: \.text, on: textLabel) } } I just wonder what is the point of specifying the main thread with .receive? If I comment out the receive line, the app will still run without a problem. Muchos thankos
1
0
632
Oct ’21
Observing UIButton Tap with Combine?
Let me say that I have an IBOutlet object like @IBOutlet weak var deleteButton: UIButton! RxCocoa can make this button tap observable like deleteButton.rx.tap It doesn't look like Combine lets us observe a button tap. Am I right? I find one approach found at the following URL. https://www.avanderlee.com/swift/custom-combine-publisher/ And Combine has no native approach? And you still have to use the IBAction?
1
0
2.7k
Oct ’21
Observing Changes in Multiple @Published Variables at the Same Time?
I have the following lines of code to subscribe text changes over two text fields. import UIKit import Combine class ViewController: UIViewController { var cancellables = Set<AnyCancellable>() @Published var userText: String = "" @Published var passText: String = "" // MARK: - IBOutlet @IBOutlet var usernameTextField: UITextField! @IBOutlet var passwordTextField: UITextField! // MARK: - Life cycle override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: usernameTextField) .sink(receiveValue: { (result) in if let myField = result.object as? UITextField { if let text = myField.text { self.userText = text } } }) .store(in: &cancellables) NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: passwordTextField) .sink(receiveValue: { (result) in if let myField = result.object as? UITextField { if let text = myField.text { self.passText = text } } }) .store(in: &cancellables) $userText .sink(receiveValue: { text in print(text) }) .store(in: &cancellables) } } In the last several lines, I am printing the text change for userText. Does Combine allow me to observe two variables (userText, passText) at the same time so that I can plug them into a function? If yes, how? Muchos Thankos.
1
0
1.9k
Nov ’21
Hiding Application Name over Toolbar?
I have a toolbar (NSToolbar) through a window controller (NSWindowController). I don't know which Xcode version does it, but the toolbar shows the name of the application next to the three window buttons. Can we hide the name? Old desktop applications that I developed several years ago don't show the name. I hope I can hide it. Muchos thankos.
1
0
729
Dec ’21
Horizontal List with NavigationView and NavigationLink
I have a list with five rows as follows. import SwiftUI struct ContentView: View { @State var horizonModels = [MenuModel]() var body: some View { ZStack { Color.green NavigationView { List { ForEach(horizonModels, id: \.self) { model in if model.id == 0 { NavigationLink( destination: MenuView0(), label: { Text("\(model.name)") }) } else { NavigationLink( destination: MenuView1(), label: { Text("\(model.name)") }) } } } } } .ignoresSafeArea() .onAppear(perform: { horizonModels = [ MenuModel.init(id: 0, name: "Shopping"), MenuModel.init(id: 1, name: "Gift cards"), MenuModel.init(id: 2, name: "Video"), MenuModel.init(id: 3, name: "Music"), MenuModel.init(id: 4, name: "Account") ] }) } } struct MenuModel: Hashable, Identifiable { let id: Int let name: String } struct MenuView0: View { var body: some View { Text("Menu 0") } } struct MenuView1: View { var body: some View { Text("Menu 1") } } And I get something like the following screenshot. Well, I actually want to create a horizontal list like the screenshot below. I could do it except that I am not able to use NavigationView and NavigationLink instead of ScrollView and HStack. So how can I make a horizontally-scrollable list with NavigationView and NavigationLink? Muchos thankos.
1
0
1.1k
Dec ’21
Showing Alert or Sheet after Some Delay?
In the following lines of code, I tap a button and an alert message will appear. I wonder if I can change the code such that the alert message will appear after some time, say, 5 seconds? During this period of delay, I want to determine whether or not the app should show an alert message. import SwiftUI import Combine struct ContentView: View { @State var cancellables = Set<AnyCancellable>() @State var disabled: Bool = false @State private var showingAlert = false let timeInterval: Double = 5.0 var body: some View { VStack { Spacer() Button("Tap me") { showingAlert = true disabled = true // some Combine work // } .font(.system(size: 24.0)) .disabled(disabled) .alert("GGGG", isPresented: $showingAlert) { /* showing alert after timeInterval */ } } } } I could do it in UIKit, but I'm not sure if that's possible in SwiftUI. Muchos thankos.
1
0
2.4k
Jan ’22
Syntax-highlighting a String with Multiple Keys
I need to highlight a string with certain keys. The base string may contain one or more occurrences of a key. Test 1: I use code based on this web site . import SwiftUI struct HighlightView: View { let baseText : String = "President's nearly $2 trillion proposed healthcare, climate, and social spending plan has been floundering for over a month since Mr. Williams came out against the bill in late December. That left the party with little to show after six months of negotiations with the conservative Democratic holdout.\n\nHe later left the door cracked open to future negotiations on a separate plan. Mr. Williams has spoken favorably about some chunks of the bill, including a program to establish universal pre-K and climate spending measures.\n\nMr. Williams wields outsized influence over the Democratic Party's agenda since the Senate is split 50-50 between both parties. Senate Democrats can't pass the package without his support, leaving them with no option but to eventually tailor a separate bill that addresses his concerns about its possible impact on the national debt and inflation.\n\nMr. Williams, meanwhile, appears to be focusing most of his time and energy leading a bipartisan group of senators working on election reform proposals including modernizing and updating the Electoral Count Act of 1887." let keys = ["Democratic", "Williams", "about"] var body: some View { ZStack { Text(baseText) { str in for i in 0..<keys.count { let key = keys[i] if let range = str.range(of: key) { str[range].foregroundColor = .pink } } }.foregroundColor(Color.gray).font(.system(size: 18.0)) } } } extension Text { init(_ string: String, configure: ((inout AttributedString) -> Void)) { var attributedString = AttributedString(string) /// create an `AttributedString` configure(&attributedString) /// configure using the closure self.init(attributedString) /// initialize a `Text` } } The following screenshot shows the result. It handles multiple keys. But it highlights one occurrence for each key. Test 2: I use code based on some web site, which I'm not permitted to show according to this system. import SwiftUI struct HighlightView2: View { let baseText : String = "President's nearly $2 trillion proposed healthcare, climate, and social spending plan has been floundering for over a month since Mr. Williams came out against the bill in late December. That left the party with little to show after six months of negotiations with the conservative Democratic holdout.\n\nHe later left the door cracked open to future negotiations on a separate plan. Mr. Williams has spoken favorably about some chunks of the bill, including a program to establish universal pre-K and climate spending measures.\n\nMr. Williams wields outsized influence over the Democratic Party's agenda since the Senate is split 50-50 between both parties. Senate Democrats can't pass the package without his support, leaving them with no option but to eventually tailor a separate bill that addresses his concerns about its possible impact on the national debt and inflation.\n\nMr. Williams, meanwhile, appears to be focusing most of his time and energy leading a bipartisan group of senators working on election reform proposals including modernizing and updating the Electoral Count Act of 1887." let keys = ["Democratic", "Williams", "about"] var body: some View { ZStack { ForEach(keys, id: \.self) { key in highlightedText(baseText: baseText, match: key, highlightColor: Color.orange) .foregroundColor(Color.gray).font(.system(size: 19.0)) } } } func highlightedText(baseText: String, match: String, highlightColor: Color) -> Text { guard !baseText.isEmpty && !match.isEmpty else { return Text(baseText) } var result: Text! let components = baseText.components(separatedBy: match) for i in components.indices { result = (result == nil ? Text(components[i]) : result + Text(components[i])) if i != components.count - 1 { result = result + Text(match).foregroundColor(highlightColor) } } return result ?? Text(baseText) } } This one handles multiple occurrences. But I can only use one key at a time. The following screenshot shows the result. Do you have a better idea in highlighting a string with multiple keys? Muchos thankos for reading.
1
0
505
Feb ’22
How to Update a UILabel Object with MainActor
I guess I was in coma, and I didn't learn of MainActor till today. So I have the following lines of code to test MainActor. import UIKit class ViewController: UIViewController { // MARK: - IBOutlet @IBOutlet weak var label: UILabel! // MARK: - IBAction @IBAction func buttonTapped(_ sender: UIButton) { Task { do { let bool = try await asyncWaitMakeLabelChanges() if bool { print("I'm done!") } } catch { print("\(error.localizedDescription)") } } } func asyncWaitMakeLabelChanges() async throws -> Bool { for i in 0..<5 { let text = String(i) label.text = text // UILabel.text must be used from main thread only print(text) sleep(1) } return true } } As I expect, I get the purple main thread checker error at the line where I update the label. That's good. And I've changed the code as follows. import UIKit class ViewController: UIViewController { // MARK: - IBOutlet @IBOutlet weak var label: UILabel! // MARK: - IBAction @IBAction func buttonTapped(_ sender: UIButton) { Task { do { let bool = try await asyncWaitMakeLabelChanges() if bool { print("I'm done!") } } catch { print("\(error.localizedDescription)") } } } func asyncWaitMakeLabelChanges() async throws -> Bool { for i in 0..<5 { let text = String(i) Task { @MainActor in label.text = text } print(text) sleep(1) } return true } } Okay. The app won't crash. But the label won't get updated every second. It will finally display the number (4) when the count reaches 4. So my question is why not? I could change my code as follows to update my label every second. func asyncWaitMakeLabelChanges() async throws -> Bool { for i in 0..<5 { let text = String(i) DispatchQueue.main.async() { [weak self] in self?.label.text = text } print(text) sleep(1) } return true } So why would I want to use MainActor?
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
1.3k
Feb ’22
'animation' was deprecated in iOS 15.0
Hmm... I don't quite get it. How can I get rid of the deprecation warning in the following case? import SwiftUI struct ContentView: View { @State var isAnimating = false var body: some View { Circle() .fill(Color.pink) .frame(width: 150, height: 150) .scaleEffect(isAnimating ? 0.5 : 1.0) .animation(Animation.easeIn(duration: 1.0).repeatForever()) .onAppear { self.isAnimating = true } } } The following could work except that I have to tap the circle once. import SwiftUI struct ContentView: View { @State var isAnimating = true var body: some View { Circle() .fill(Color.pink) .frame(width: 150, height: 150) .scaleEffect(isAnimating ? 1 : 0.5) .animation(Animation.easeIn(duration: 3.0).repeatForever(), value: isAnimating) .onTapGesture { isAnimating.toggle() } .onAppear { isAnimating = false isAnimating.toggle() } } } Muchos thankos.
1
0
3.5k
Feb ’22
Passing a Variable Between Two Unrelated Views Without Binding
My ContentView has one View (RightView) inside. Tapping the button over RightView, the app will pass a boolean value to ContentView. struct ContentView: View { @ObservedObject var monster: MonsterObservable var body: some View { GeometryReader { geo in ZStack { HStack(spacing: 0.0) { RightView(showMe: $monster.showDialog) .frame(width: geo.size.width, height: geo.size.height) } ShowDialogView(isShowing: $monster.showDialog) { } .frame(width: 500, height: 600, alignment: .center) .cornerRadius(10.0) } } } } struct RightView: View { @Binding var showMe: Bool var body: some View { ZStack { Color.red Button { showMe = true } label: { Text("Tap me") .font(.largeTitle) } } } } class MonsterObservable: ObservableObject { @Published var showDialog = false } struct ShowDialogView<Content: View>: View { @Binding var isShowing: Bool @ViewBuilder let content: () -> Content var body: some View { Group { if isShowing { ZStack { Color.brown VStack { Spacer() Button { isShowing = false } label: { Text("Close me") .font(.largeTitle) }.padding([.top, .bottom], 100.0) } } } } } } So the code above works. If I tap the button over RightView, a small dialog (ShowDialogView) will appear. Currently, ContentView and RightView are bound. That's not exactly what I need. How can I pass a boolean value from RightView to ContentView without Binding where ContentView is the following? struct ContentView: View { @ObservedObject var monster: MonsterObservable var body: some View { GeometryReader { geo in ZStack { HStack(spacing: 0.0) { RightView() .frame(width: geo.size.width, height: geo.size.height) } ShowDialogView(isShowing: $monster.showDialog) { } .frame(width: 500, height: 600, alignment: .center) .cornerRadius(10.0) } } } }
1
0
599
Mar ’22
Showing a Constructor Dialog View with an ObservedObject Object
I'm trying to show a dialog over ContentView. The dialog view, ShowDialogView, has an ObservedObject object with name and properties. class User: ObservableObject { @Published var name = "" @Published var age: Int = 0 } struct ShowDialogView: View { @Binding var isPresented: Bool @ObservedObject var user: User /* @State var name = "" */ init(isPresented: Binding<Bool>, user: User) { self._isPresented = isPresented self.user = user.searchWord //_name = State(initialValue: "Kimberly") } var body: some View { VStack { ... ... }.onAppear { print("\(user.name)") } } } struct ContentView: View { @State var user = User() @State var showMe = true var body: some View { VStack { ... ... ShowDialogView(isPresented: showMe, user: user) } } } The dialog view will open with no problem. The problem that I have is that the user object doesn't deliver anything beyond default values. If I somehow set the name property to "Kimberly" before the dialog appears, the app will end up showing no value (""). Even if I try setting an initial value to the name property in the constructor, the app will still show an empty value. What am I doing wrong? I'm sorry I cannot give you a lot of details in the code above. Thank you.
1
0
434
Apr ’22
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
642
Jul ’22