Post

Replies

Boosts

Views

Activity

Reply to How do I get recommended iOS app preview resolution?
OK, I knew I was missing something stupid: I should not be using iPhone 13 Pro for the video, but an iPhone 13 Pro Max. That gives the correct resolution. Bonus tip: Make use of iMovie's built-in support for generating app previews (yes, I know this should be obvious, but just in case). This did allow me to record my video on my iPhone 13 Pro and still save it in the correct resolution.
Jan ’22
Reply to Cannot bind to local UDP socket - address already in use
Thanks. I am not sure what to do with this tread since the problem was not a code problem but a port being reserved by XQuartz. Thanks for the advice on netstat. I will use it in the future but it seems it would not have picked up the problem either since the port was not open, it was just being reserved. I cannot confirm since I've uninstalled XQuartz to resolve my issue (did not have the option to move other port). I am marking this as the answer purely to close the thread, and in case anyone ever gets to it. Let me know if you disagree.
Topic: App & System Services SubTopic: General Tags:
Feb ’22
Reply to Does UITextField in UIViewRepresentable have a solution?
I found something that fixed my problem but I'm not sure it is the right way of doing things. Setting the horizontal content compression resistance priority to defaultLow made it scroll correctly. The makeUIView function below shows the full solution. func makeUIView(context: Context) -> UIViewType { // Setup text view: // ---------------- let textView = UITextField() textView.delegate = context.coordinator textView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) // Creae a dummy view for the inputView (keyboard) so that the default // keyboard is not shown: let dummyView = UIView(frame: CGRect.zero) textView.inputView = dummyView return textView }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Apr ’22
Reply to Why does custom Binding not update UI
I cannot change the code because It is in a 3rd party library for which I do not have the code. The other alternative would be to write a wrapper for the 3rd party class but that felt less elegant that the custom Binding. Seeing that the Binding works, I was wondering what it was missing and why it is not working. Is @Published adding some other functionality that could be simulated somehow.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Oct ’22
Reply to Why does custom Binding not update UI
Thanks. That is a step in the right direction and could work. Sorry for the piecewise info but I did not think it was relevant given the original question (I thought I just missed a notification in my Binding). There is a slight catch: This leaves me with two sources of truth. The bool value in the class may be changed by something other than the UI. I have a callback for when this happens, so I could notify/publish when it does. In the case of your example, I could use Binding instead of State so that the value could be changed externally as well, but that brings me back to an original concept that just felt clumsy. I could also add an Update button to my UI to refresh the values that may have changed externally, but again, it would be preferable to have just one source of truth.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Oct ’22
Reply to How to use network sockets with async/await?
I currently have a BSD socket where I use CFSocketCreate() with a receive callback. I've looked at NWConnection and have no problem switching to it if it makes more sense. My hardware will always use the same connection (same Source IP:Port to same Destination IP:Port). It will only change (source IP) for different hardware. From what I could gather, my problem for adopting async/await still has to do with signalling. I looked a bit at combine after posting (as it mentions networking) but have a feeling I was going down the wrong path. Ultimately, I need a await receive() somehow where it may block if it has not received anything yet and will not block if it has already received (and queued) data.
Topic: Programming Languages SubTopic: Swift Tags:
Nov ’22
Reply to How to use network sockets with async/await?
Thanks, I did not consider the continuation solutions as my head was stuck on signalling. [As side, would be interesting to know how the continuations work under the hood as I have not come across that before]. Could you elaborate on the cancellation? Where would your example be cancelled (I assume before the continuation is called??). Would you be guaranteed that the continuation is not called? If so, then handling any context should be solvable. I am not clear where withTaskCancellationHandler(operation:onCancel:) comes in to the picture (where to prime it).
Topic: Programming Languages SubTopic: Swift Tags:
Nov ’22
Reply to How to use network sockets with async/await?
Sorry, the question about async networking is now becoming a question about task cancellation. Feel free to throw me to new thread (pun intended). The bulk of the Swift concurrency runtime is in the Swift open source. I've got the swift repo and do look at it but not to that depth. Maybe one-day when I have lots of time :) I strongly recommend that you watch WWDC 2021 Session 10134 Explore structured concurrency in Swift. I did this, and learned a lot but not what I expected. I fully understand while a Task needs to complete and be able to be cancelled. What I fail to see, is how to opt-in. To try and explain, below is a simple example that works (assuming ostrich algorithm). Should the withCheckedContinuation be replaced with withTaskCancellationHandler? [1] Even if it is, how would I cancel a connection that is waiting for data to be received? Maybe I am starting to understand just enough to realise that something needs to change in the networking layer? [1] I found very little on withTaskCancellationHandler in documentation and online which may explain why it is not clear to me. import Foundation import Network class Udp { private var listner: NWListener private var receiveCallback: ((Data, NWEndpoint) -> Void)? func receive() async -> (Data, NWEndpoint) { await withCheckedContinuation { continuation in asyncReceive { data, endpoint in continuation.resume(returning: (data, endpoint)) } } } private func asyncReceive(callback: @escaping (Data, NWEndpoint) -> Void) { receiveCallback = callback } init(localPort: UInt16) throws { listner = try NWListener(using: .udp, on: NWEndpoint.Port(rawValue: localPort)!) listner.newConnectionHandler = { connection in connection.start(queue: .global()) self.receive(from: connection) } listner.start(queue: .global()) } func receive(from connection: NWConnection) { connection.receiveMessage { content, context, isComplete, error in if let rxData = content { if let receiveCallback = self.receiveCallback { receiveCallback(rxData, connection.endpoint) } } // Receive again: self.receive(from: connection) } } } print("This app listens for UDP on port 7000.") print("Use:") print(" nc -u 127.0.0.1 7000") print("to start sending data to me. I'll let you know when I've received it.") let udp = try! Udp(localPort: 7000) let (data, sender) = await udp.receive() print("Received data from \(sender)")
Topic: Programming Languages SubTopic: Swift Tags:
Nov ’22
Reply to Why does SwiftUI sidebar not update when ObservedObject changes?
The problem is that person is never observed. The Text view in the list will not be notified when the person's name changes because it is not observed. To fix the problem, create another view that observes the class (ObservableObject). That entire view is invalidated when the @Published field in the @ObservedObject changes. The code below fixes the problem and the sidebar is correctly updated in real time as the name is edited. class Person: NSObject, ObservableObject { @Published public var name: String init(name: String) { self.name = name } } class Database { public var people: [Person] init() { people = [Person(name: "Susan"), Person(name: "John"), Person(name: "Jack"), Person(name: "Mary")] } } @main struct BindingTestApp: App { @State private var database = Database() var body: some Scene { WindowGroup { ContentView(people: $database.people) } } } struct PersonView: View { @ObservedObject var person: Person var body: some View { Text(person.name) } } struct ContentView: View { struct SidebarView: View { @Binding var people: [Person] @Binding var selectedPerson: Person? var body: some View { List(people, id: \.self, selection: $selectedPerson) { person in PersonView(person: person) }.listStyle(SidebarListStyle()) } } struct PersonView: View { @ObservedObject public var person: Person var body: some View { TextField("Name", text: $person.name) } } @Binding var people: [Person] @State private var selectedPerson: Person? var body: some View { NavigationView { SidebarView(people: $people, selectedPerson: $selectedPerson) if let selectedPerson = selectedPerson { PersonView(person: selectedPerson) } else { Text("Please select or create a person.") } } } } struct ContentView_Previews: PreviewProvider { @State static private var database = Database() static var previews: some View { ContentView(people: $database.people) } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Nov ’22
Reply to How to preserve state in reference types in swiftUI
I quickly played with UserDefaults but as expected it gets saved in Preferences .plist file. I did see keys with names like "AppWindow-X" [1]. If I could get the number of a window in a scene that would uniquely identify it, then I could use that to store the settings specific for the window but I found no way of getting a window reference. For interest sake, I also tried to find where the @SceneStorage data is stored to see if it gave any clues but I could not find it. Any suggestions will be appreciated. [1] Where X is the window number.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Nov ’22
Reply to Where is userDefaults saved for SwiftUI Sandbox app?
The preferences file that backs UserDefaults is ~/Library/ ... Thanks. That is what I've been looking at. The part that confuses me is that I can remove the container, empty my bin, run my app again, and then the file contains data that I did not write with the last run of my app. It contains values that was written by earlier versions of the app. So it seems like it is refreshing the container from some cache that I've not been able to find. Am I seeing ghosts, or do I misunderstand how it should be working? WARNING The location and format of this file is subject to change. ... but do not encode such knowledge in your product. Understood. That was my intention - to get a better understanding of what is saved, and to check that it is saved correctly. I was working with arrays of dictionaries where each dictionary had a UUID so making errors in code and debugging without looking at the underlying data was very tricky. For more info about that tool, see the defaults man page. I've used the defaults tools. I could see for example that when I removed the container that defaults would show that it no longer sees the data. But just like opening the .plist file in GUI, defaults showed the same stale data returning when I run my app again. Hmmmm, that’s not good. Please get in touch with me via email Thanks, will do.
Topic: App & System Services SubTopic: General Tags:
Dec ’22
Reply to Where is userDefaults saved for SwiftUI Sandbox app?
Aaah great, case closed. At least the world makes sense again. I've marked your first reply as correct, as it answered my question but this extra bit of information clears up some confusion that made me think it is not stored there. The full answer may have been that it is stored in ~/Library/Containers but also cached. This may only be useful for development purposes.
Topic: App & System Services SubTopic: General Tags:
Dec ’22
Reply to How to preserve state in reference types in swiftUI
Thanks to apple support for helping me out with this one. The correct answer is in the WWDC22 The SwiftUI cookbook for navigation video, right at the end. For completeness, the following fixes the example given in the original question: import SwiftUI import Combine @main struct SceneStorageTest: App { var body: some Scene { WindowGroup("Port Statistics", id: "statsView") { ContentView() } } } class StreamStats: ObservableObject, Encodable { @Published public var port: Int = 60000 public var jsonData: Data? { get { try? JSONEncoder().encode(self) } set { guard let data = newValue, let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return } port = json["port"] as! Int } } enum CodingKeys: String, CodingKey { case port } init() { startListening() } public func startListening() { print("Gathering stats for port \(port)") } var objectWillChangeSequence: AsyncPublisher<Publishers.Buffer<ObservableObjectPublisher>> { objectWillChange .buffer(size: 1, prefetch: .byRequest, whenFull: .dropOldest) .values } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(port, forKey: .port) } } struct ContentView: View { @StateObject var streamStats = StreamStats() @SceneStorage("streamStatsData") var streamStatsData: Data? @Environment(\.openWindow) private var openWindow var body: some View { VStack { TextField("port", value: $streamStats.port, format: .number) Button("Open") { streamStats.startListening() } Divider() Button("New Port Statistics Window") { openWindow(id: "statsView") } } .padding() .task { if let data = streamStatsData { print("Loading data.") streamStats.jsonData = data } for await _ in streamStats.objectWillChangeSequence { streamStatsData = streamStats.jsonData } } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Dec ’22
Reply to How do I get recommended iOS app preview resolution?
OK, I knew I was missing something stupid: I should not be using iPhone 13 Pro for the video, but an iPhone 13 Pro Max. That gives the correct resolution. Bonus tip: Make use of iMovie's built-in support for generating app previews (yes, I know this should be obvious, but just in case). This did allow me to record my video on my iPhone 13 Pro and still save it in the correct resolution.
Replies
Boosts
Views
Activity
Jan ’22
Reply to Cannot bind to local UDP socket - address already in use
Thanks. I am not sure what to do with this tread since the problem was not a code problem but a port being reserved by XQuartz. Thanks for the advice on netstat. I will use it in the future but it seems it would not have picked up the problem either since the port was not open, it was just being reserved. I cannot confirm since I've uninstalled XQuartz to resolve my issue (did not have the option to move other port). I am marking this as the answer purely to close the thread, and in case anyone ever gets to it. Let me know if you disagree.
Topic: App & System Services SubTopic: General Tags:
Replies
Boosts
Views
Activity
Feb ’22
Reply to Does UITextField in UIViewRepresentable have a solution?
I found something that fixed my problem but I'm not sure it is the right way of doing things. Setting the horizontal content compression resistance priority to defaultLow made it scroll correctly. The makeUIView function below shows the full solution. func makeUIView(context: Context) -> UIViewType { // Setup text view: // ---------------- let textView = UITextField() textView.delegate = context.coordinator textView.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) // Creae a dummy view for the inputView (keyboard) so that the default // keyboard is not shown: let dummyView = UIView(frame: CGRect.zero) textView.inputView = dummyView return textView }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Apr ’22
Reply to Why does custom Binding not update UI
I cannot change the code because It is in a 3rd party library for which I do not have the code. The other alternative would be to write a wrapper for the 3rd party class but that felt less elegant that the custom Binding. Seeing that the Binding works, I was wondering what it was missing and why it is not working. Is @Published adding some other functionality that could be simulated somehow.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Oct ’22
Reply to Why does custom Binding not update UI
Thanks. That is a step in the right direction and could work. Sorry for the piecewise info but I did not think it was relevant given the original question (I thought I just missed a notification in my Binding). There is a slight catch: This leaves me with two sources of truth. The bool value in the class may be changed by something other than the UI. I have a callback for when this happens, so I could notify/publish when it does. In the case of your example, I could use Binding instead of State so that the value could be changed externally as well, but that brings me back to an original concept that just felt clumsy. I could also add an Update button to my UI to refresh the values that may have changed externally, but again, it would be preferable to have just one source of truth.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Oct ’22
Reply to How to use network sockets with async/await?
I currently have a BSD socket where I use CFSocketCreate() with a receive callback. I've looked at NWConnection and have no problem switching to it if it makes more sense. My hardware will always use the same connection (same Source IP:Port to same Destination IP:Port). It will only change (source IP) for different hardware. From what I could gather, my problem for adopting async/await still has to do with signalling. I looked a bit at combine after posting (as it mentions networking) but have a feeling I was going down the wrong path. Ultimately, I need a await receive() somehow where it may block if it has not received anything yet and will not block if it has already received (and queued) data.
Topic: Programming Languages SubTopic: Swift Tags:
Replies
Boosts
Views
Activity
Nov ’22
Reply to How to use network sockets with async/await?
Thanks, I did not consider the continuation solutions as my head was stuck on signalling. [As side, would be interesting to know how the continuations work under the hood as I have not come across that before]. Could you elaborate on the cancellation? Where would your example be cancelled (I assume before the continuation is called??). Would you be guaranteed that the continuation is not called? If so, then handling any context should be solvable. I am not clear where withTaskCancellationHandler(operation:onCancel:) comes in to the picture (where to prime it).
Topic: Programming Languages SubTopic: Swift Tags:
Replies
Boosts
Views
Activity
Nov ’22
Reply to How to use network sockets with async/await?
Sorry, the question about async networking is now becoming a question about task cancellation. Feel free to throw me to new thread (pun intended). The bulk of the Swift concurrency runtime is in the Swift open source. I've got the swift repo and do look at it but not to that depth. Maybe one-day when I have lots of time :) I strongly recommend that you watch WWDC 2021 Session 10134 Explore structured concurrency in Swift. I did this, and learned a lot but not what I expected. I fully understand while a Task needs to complete and be able to be cancelled. What I fail to see, is how to opt-in. To try and explain, below is a simple example that works (assuming ostrich algorithm). Should the withCheckedContinuation be replaced with withTaskCancellationHandler? [1] Even if it is, how would I cancel a connection that is waiting for data to be received? Maybe I am starting to understand just enough to realise that something needs to change in the networking layer? [1] I found very little on withTaskCancellationHandler in documentation and online which may explain why it is not clear to me. import Foundation import Network class Udp { private var listner: NWListener private var receiveCallback: ((Data, NWEndpoint) -> Void)? func receive() async -> (Data, NWEndpoint) { await withCheckedContinuation { continuation in asyncReceive { data, endpoint in continuation.resume(returning: (data, endpoint)) } } } private func asyncReceive(callback: @escaping (Data, NWEndpoint) -> Void) { receiveCallback = callback } init(localPort: UInt16) throws { listner = try NWListener(using: .udp, on: NWEndpoint.Port(rawValue: localPort)!) listner.newConnectionHandler = { connection in connection.start(queue: .global()) self.receive(from: connection) } listner.start(queue: .global()) } func receive(from connection: NWConnection) { connection.receiveMessage { content, context, isComplete, error in if let rxData = content { if let receiveCallback = self.receiveCallback { receiveCallback(rxData, connection.endpoint) } } // Receive again: self.receive(from: connection) } } } print("This app listens for UDP on port 7000.") print("Use:") print(" nc -u 127.0.0.1 7000") print("to start sending data to me. I'll let you know when I've received it.") let udp = try! Udp(localPort: 7000) let (data, sender) = await udp.receive() print("Received data from \(sender)")
Topic: Programming Languages SubTopic: Swift Tags:
Replies
Boosts
Views
Activity
Nov ’22
Reply to How to access parent in List View with children?
Thanks, I never considered using the ID as reference.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Nov ’22
Reply to Why does SwiftUI sidebar not update when ObservedObject changes?
The problem is that person is never observed. The Text view in the list will not be notified when the person's name changes because it is not observed. To fix the problem, create another view that observes the class (ObservableObject). That entire view is invalidated when the @Published field in the @ObservedObject changes. The code below fixes the problem and the sidebar is correctly updated in real time as the name is edited. class Person: NSObject, ObservableObject { @Published public var name: String init(name: String) { self.name = name } } class Database { public var people: [Person] init() { people = [Person(name: "Susan"), Person(name: "John"), Person(name: "Jack"), Person(name: "Mary")] } } @main struct BindingTestApp: App { @State private var database = Database() var body: some Scene { WindowGroup { ContentView(people: $database.people) } } } struct PersonView: View { @ObservedObject var person: Person var body: some View { Text(person.name) } } struct ContentView: View { struct SidebarView: View { @Binding var people: [Person] @Binding var selectedPerson: Person? var body: some View { List(people, id: \.self, selection: $selectedPerson) { person in PersonView(person: person) }.listStyle(SidebarListStyle()) } } struct PersonView: View { @ObservedObject public var person: Person var body: some View { TextField("Name", text: $person.name) } } @Binding var people: [Person] @State private var selectedPerson: Person? var body: some View { NavigationView { SidebarView(people: $people, selectedPerson: $selectedPerson) if let selectedPerson = selectedPerson { PersonView(person: selectedPerson) } else { Text("Please select or create a person.") } } } } struct ContentView_Previews: PreviewProvider { @State static private var database = Database() static var previews: some View { ContentView(people: $database.people) } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Nov ’22
Reply to How to preserve state in reference types in swiftUI
I quickly played with UserDefaults but as expected it gets saved in Preferences .plist file. I did see keys with names like "AppWindow-X" [1]. If I could get the number of a window in a scene that would uniquely identify it, then I could use that to store the settings specific for the window but I found no way of getting a window reference. For interest sake, I also tried to find where the @SceneStorage data is stored to see if it gave any clues but I could not find it. Any suggestions will be appreciated. [1] Where X is the window number.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Nov ’22
Reply to Where is userDefaults saved for SwiftUI Sandbox app?
Yes, this is currently for a macOS app where I can see the plist files in finder (or terminal). Ultimately, I am trying to answer How to preserve state in reference types in swiftUI asked in a different post (and with a TSI that has gone unanswered for two weeks) but I am going down deeper and deeper in to a rabbit hole.
Topic: App & System Services SubTopic: General Tags:
Replies
Boosts
Views
Activity
Dec ’22
Reply to Where is userDefaults saved for SwiftUI Sandbox app?
The preferences file that backs UserDefaults is ~/Library/ ... Thanks. That is what I've been looking at. The part that confuses me is that I can remove the container, empty my bin, run my app again, and then the file contains data that I did not write with the last run of my app. It contains values that was written by earlier versions of the app. So it seems like it is refreshing the container from some cache that I've not been able to find. Am I seeing ghosts, or do I misunderstand how it should be working? WARNING The location and format of this file is subject to change. ... but do not encode such knowledge in your product. Understood. That was my intention - to get a better understanding of what is saved, and to check that it is saved correctly. I was working with arrays of dictionaries where each dictionary had a UUID so making errors in code and debugging without looking at the underlying data was very tricky. For more info about that tool, see the defaults man page. I've used the defaults tools. I could see for example that when I removed the container that defaults would show that it no longer sees the data. But just like opening the .plist file in GUI, defaults showed the same stale data returning when I run my app again. Hmmmm, that’s not good. Please get in touch with me via email Thanks, will do.
Topic: App & System Services SubTopic: General Tags:
Replies
Boosts
Views
Activity
Dec ’22
Reply to Where is userDefaults saved for SwiftUI Sandbox app?
Aaah great, case closed. At least the world makes sense again. I've marked your first reply as correct, as it answered my question but this extra bit of information clears up some confusion that made me think it is not stored there. The full answer may have been that it is stored in ~/Library/Containers but also cached. This may only be useful for development purposes.
Topic: App & System Services SubTopic: General Tags:
Replies
Boosts
Views
Activity
Dec ’22
Reply to How to preserve state in reference types in swiftUI
Thanks to apple support for helping me out with this one. The correct answer is in the WWDC22 The SwiftUI cookbook for navigation video, right at the end. For completeness, the following fixes the example given in the original question: import SwiftUI import Combine @main struct SceneStorageTest: App { var body: some Scene { WindowGroup("Port Statistics", id: "statsView") { ContentView() } } } class StreamStats: ObservableObject, Encodable { @Published public var port: Int = 60000 public var jsonData: Data? { get { try? JSONEncoder().encode(self) } set { guard let data = newValue, let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] else { return } port = json["port"] as! Int } } enum CodingKeys: String, CodingKey { case port } init() { startListening() } public func startListening() { print("Gathering stats for port \(port)") } var objectWillChangeSequence: AsyncPublisher<Publishers.Buffer<ObservableObjectPublisher>> { objectWillChange .buffer(size: 1, prefetch: .byRequest, whenFull: .dropOldest) .values } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(port, forKey: .port) } } struct ContentView: View { @StateObject var streamStats = StreamStats() @SceneStorage("streamStatsData") var streamStatsData: Data? @Environment(\.openWindow) private var openWindow var body: some View { VStack { TextField("port", value: $streamStats.port, format: .number) Button("Open") { streamStats.startListening() } Divider() Button("New Port Statistics Window") { openWindow(id: "statsView") } } .padding() .task { if let data = streamStatsData { print("Loading data.") streamStats.jsonData = data } for await _ in streamStats.objectWillChangeSequence { streamStatsData = streamStats.jsonData } } } }
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Dec ’22