Post

Replies

Boosts

Views

Activity

Reply to Open app review crashlog .txt file in Xcode 13
Do you know why was the format changed to this new pair of JSON dictionaries, when it seems like you pretty much need to convert it back to the more readable table-style format in order to debug with it? When I read the article Interpreting the JSON format of a crash report, it links to Adding identifiable symbol names to a crash report, and that article requires the crash log to be in the old table-style format in order to extract the info needed to run the atos command, which seems to be the only way I could find to determine which function call and line number in my source code are being referenced.
Jul ’25
Reply to Network Framework Ad Hoc Connection via Ethernet
That article is really helpful., thank you for that. I see why you say the terms become meaningless if not used precisely. Hopefully I'm asking this right: What do you call the hardwired version of Wifi Direct (or Apple peer-to-peer Wi-Fi)? I know that 2 non-cellular iPads can find each other and communicate with Network Framework via Wifi Direct (Apple peer-to-peer Wi-Fi?) even without a wifi network available. Can they do this through a cable connected to each other? If it's technically possible, I assume I would need to set requiredInterfaceType to wiredEthernet like you mentioned. After that, could the cable be a USB-C to USB-C as shown in the 1st attached pic? Or would it need to be an Ethernet cable as shown in the 2nd (contrived) attached pic?
Jun ’25
Reply to Jetsam memory crash during Network framework usage
I tried this as an alternative: let priSecDataFilePacket = PriSecDataFilePacket(fileName: filenamePart, startPointer: fileReqPacket.startPointer, endPointer: fileReqPacket.endPointer, chunkNum: fileReqPacket.chunkNum, totalChunkCount: fileReqPacket.totalChunkCount) let jsonEncoder = JSONEncoder() let jsonData = try jsonEncoder.encode(priSecDataFilePacket) let jsonSize = jsonData.count let jsonSizeAsString = String(jsonSize) let padded = String(repeating: "0", count: max(0, 10 - jsonSizeAsString.count)) + jsonSizeAsString guard let jsonSizeAsStringAsData = padded.data(using: .utf8) else { return } let totalSize = jsonSizeAsStringAsData.count + jsonData.count + fileBlob.count var dataAmalgam = Data(capacity: totalSize) dataAmalgam.append(jsonSizeAsStringAsData) dataAmalgam.append(jsonData) dataAmalgam.append(fileBlob) sendJson(encodedJsonToSend: dataAmalgam, passedInPriSecMsgType: .priToSecDataFile) but this spikes the memory during the send, like the memory is being held onto longer. The chunking way (using 20MB chunks that are json-encoded into the struct) do indeed make a larger data blob like you said, but that doesn't spike the memory. I also tried PropertyListEncoder instead of JSONEncoder (which I only just learned about tonight), but it has the same issue with spiking the memory. It's almost like Network framework is optimized somehow for a binary blob that is JSONEncoded? (Or maybe this is all a lucky side effect that the JSONEncoding is slower to perform and gives the device time to release the memory before performing the next send? Grabbing at straws here.)
Topic: Programming Languages SubTopic: Swift Tags:
Mar ’25
Reply to Jetsam memory crash during Network framework usage
Thanks for the info. So it sounds like chunking is the way to go. Regarding the JSON-encoding, is there an alternate way to send a struct that could be decoded on the other end? Since the struct has the other pieces of data that are needed for describing the binary blob coming over. I have a couple other fields like a unique ID in the struct. I was thinking that one way would be to encode the struct without the binary blob, then determine the size in bytes of the struct, then append the json-encoded struct together with the file blob, then lastly append at the beginning of this new blob a fixed-size (like 20 bytes say) indicating the size of the struct. Then on the receiving side, peel off the first 20 bytes, which tells how many bytes are needed for the struct, then peel off the bytes for the struct, so that can be decoded, and the remaining bytes are the file blob.
Topic: Programming Languages SubTopic: Swift Tags:
Mar ’25
Reply to iOS deep linking with Xcode UI testing
Just posting this here in case it helps someone in the future. The code here came in handy for us: http://emndeniz.medium.com/ios-ui-testing-with-deep-links-7c33e9f9b7f1 Here's the relevant code. After starting a UI test in your app, then you start up Safari and open a deep link, which sends the data back to your app, and since the UI test is running for your app, you can now receive the incoming data in onOpenURL. import XCTest final class UITestHelpers { // Singleton instance static let shared = UITestHelpers() private init() {} // Safari app by its identifier private let safari: XCUIApplication = XCUIApplication(bundleIdentifier: "com.apple.mobilesafari") /// Opens safari with given url /// - Parameter url: URL of the deeplink. func openWithSafari(app: XCUIApplication, url: String) { if safari.state != .notRunning { // Safari can get in to bugs depending on too many tests. // Better to kill at at the beginning. safari.terminate() _ = safari.wait(for: .notRunning, timeout: 5) } safari.launch() // Ensure that safari is running _ = safari.wait(for: .runningForeground, timeout: 30) // Access the search bar of the safari // Note: 'Address' needs to be localized if the simulator language is not english let searchBar = safari.descendants(matching: .any).matching(identifier: "Address").firstMatch searchBar.tap() // Enter the URL safari.typeText(url) // Simulate "Return" key tap safari.typeText("\n") // Tap "Open" on confirmation dialog // Note: 'Open' needs to be localized if the simulator language is not english safari.buttons["Open"].tap() // Wait for the app to start _ = app.wait(for: .runningForeground, timeout: 5) } func waitFor(element: XCUIElement, failIfNotExist: Bool = true, timeOut: TimeInterval = 15.0) { if !element.waitForExistence(timeout: timeOut) { if failIfNotExist { XCTFail("Could not find \(element.description) within \(timeOut) seconds") } } } }
Feb ’25
Reply to iOS autodelete Keychain items after uninstall?
Still the case with iOS 17.5 as of June 2024. The keychain is definitely preserved even after app uninstall/reinstall. Quinn's suggestion about implementing some kind of entanglement (or even stembermichal's suggestion of a Bool flag in UserDefaults) appears necessary. Basically you have to implement your own test to determine if the keychain item is a holdover from a previous install.
Topic: Privacy & Security SubTopic: General Tags:
Jun ’24
Reply to SwiftUI and vars outside the SwiftUI world
@Polyphonic I guess my perception of the @EnvironmentObject (or @Environment in iOS 17) as the place where the app's data should be persisted is not quite right. It does seem telling that in Apple's article (https://developer.apple.com/documentation/swiftui/migrating-from-the-observable-object-protocol-to-the-observable-macro) about migrating to the Observation frameworks, the @Environment is only used in structs and not in classes. In your example of the pets app, is this the basic data flow: Data starts in long-term disk storage (either SQLite/Core Data or UserDefaults). On app startup, any data needed during app running is copied into the AppDataModel class. When a view opens, any data needed for display is copied into the view's XYZViewModel class, which only exists while XYZ view exists. If any changes are made to data during that time, that changes are migrated back to the AppDataModel class (and from there to SQLite/Core Data or UserDefaults). It makes me wonder if you really need the view model class, when you could just use@State vars for that view. I have read that ViewModel classes make for easier unit tests, which we do use in our app, and which makes sense I suppose since you can instantiate the class independent of the view for testing.
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Dec ’23
Reply to SwiftUI and vars outside the SwiftUI world
@Polyphonic This is great stuff Polyphonic, thank you! Data Model vs View Model makes a lot of sense in particular. Do you think, conceptually, this could be seen as the "SwiftUI world" (aka what is handled by the View Model), and the "non-SwiftUI world" (aka the Data Model)? To me it seemed like that causes 2 sources of truth, like we have now...but maybe that is normal? As in, the View Model only manages the data as long as the view (the UI world) is alive, but once it disappears and is done, then its data must be transferred over to the Data Model? If that's the case, it still makes me wonder how a plain vanilla class like DoNetworkStuff has access to that data. I see what you're saying that starting the app with an AppViewModel as an .environmentObject is the way to persist the whole app's data in a single, non-replicated class, but it still seems like SwiftUI isn't really designed for passing that data to plain classes. To quote this StackOverflow comment, https://stackoverflow.com/a/65370757/1359088, A possible approach is to make it shared (and don't use @EnvironmentObject anywhere outside SwiftUI view - it is not designed for that) I found it interesting that he/she said the @EnvironmentObject isn't designed for being used outside the view. His/her answer is the same as your suggested solution, which is to create a shared instance of the ObservableObject, which serves both worlds: In the SwiftUI world, it uses its @Published vars to publish updates to views that need to display the appViewModel's values as they change; In the non-SwiftUI world, it makes itself available via the appViewModel.shared instance, which is where DoNetworkStuff should go to fetch the devId. Why is it that plain classes like DoNetworkStuff can't see an environmentObject? Why wasn't that made a feature? Why must you "bridge the gap" between the SwiftUI ObservableObject and this plain class by making the shared instance? Or, maybe you could make all classes like DoNetworkStuff "opt-in" to the SwiftUI world by importing SwiftUI and making them conform to the ObservableObject protocol--in which case they WOULD be able to see the environmentObject? Do you think that's a better solution, is to make all classes operate within the SwiftUI world, or is it better to leave them as plain classes and bring the data over to them via the shared instance?
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Dec ’23
Reply to SwiftUI Navigation Bar appears behind Status Bar
I don't remember the exact fix, but based on my comments listed here, this seemed to be the fix: var body: some View { // You must have the TabView and the NavigationView at the top of the hierarchy, or you'll have an // issue of the navigation bar's breadcrumb and buttons such as "+" appearing behind the status bar ( // ie, then clock and date). I had a workaround hack where I would toggle the status bar on and off to // cause the navigation bar to "walkdown" to its correct location, keeping the hierarchy this way // eliminates it altogether. TabView(selection: $tabSelection) { NavigationView { GeometryReader { geomRdr in ZStack { VStack(spacing: 0) {
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Dec ’23
Reply to Network.Framework vs URLSession in Background Task (BGTask)
Thank you so much for that info! That helped a ton. What steered me wrong was that the NWConnection would never stay connected once the app gets backgrounded, and even when I tried using it during the BGTask, it wasn't working. However, when I would start a new NWConnection with the NWListener, it did work, proving that what you said about the network being fully available during the BGTask, as long as requiresNetworkConnectivity was set to true like you said. Is it a better strategy, then, to consider the NWConnection as short-lived, rather than trying to keep it alive? That is, should I use the NWConnection to connect, do the necessary business, then close it, and start a new one the next night? These tasks will be occurring once each night. I'm also curious what you meant about the URLSession being special--did that mean it's given extra permissions or capabilities of some kind?
Nov ’23
Reply to Network.Framework vs URLSession in Background Task (BGTask)
Hi Quinn! The task will definitely be running from a BGTask at night, which means the app will be suspended (and therefore also backgrounded). Am I correct to assume that URLSession is the only way to communicate to the "outside world", so to speak? Because at that point any PeerConnections established with the Network framework will probably not be usable? We're trying to determine if the Network framework is a viable way for the app to fetch data using a BGTask, or if we will need to set up a web service for the app to communicate with. From my quick experiments, it seems like a suspended app running a BGTask can only use a URLSession at that point. It's interesting that you mentioned that URLSession is special--is that because it's given networking allowances that other frameworks (like Network) don't have?
Nov ’23