Posts

Post not yet marked as solved
2 Replies
1.8k Views
A user is having problems with my app and I've traced his log files to discover that the user never receives a background fetch opportunity. Every setting seems to be OK, including not being in lo power mode, but nothing ever happens. Users phone is iOS12. The app works fine on my iOS 13 phone and in Simulator for iOS 12.Is there a way to determine if your app is truly registered for background fetches?On a related note, it'd be nice to know the availability of all of these, as dictated by the user's choices in Settings: • iCloud key,value store, NSUbiquitousKeyValueStore.default • Notifications • Background app refresh • Location servicesI can check the Notifications: let center = UNUserNotificationCenter.current() center.getNotificationSettings { settings in guard (settings.authorizationStatus == .authorized) else { self.logSB.error("Authorization status is NOT authorized") return } self.logSB.debug("Authorization status IS authorized") if settings.alertSetting == .enabled { // Schedule an alert-only notification. self.logSB.debug("Authorization alert is enabled") } else { // Schedule a notification with a badge and sound. self.logSB.error("Authorization alert is NOT enabled") } }
Posted
by waynehend.
Last updated
.
Post not yet marked as solved
2 Replies
727 Views
Some users are telling me they "never" or rarely get alerts sent by my app while in the background. I have no such problem on my phone - I get alerts frequently. I've checked every setting we can find related to background app refresh, and to notifications, but all seems in order.My app (AirCompare) does background fetches, processes a small amount of web data, and then sends an alert. This all works fine for me and most users. In the case of the affected user, my app logging shows that alerts were requested, but the user never saw them.Here's an example alert, one relaed to the weather:requestIdentifier = "Tickle Weather" content.title = "... Weather update ..." content.subtitle = "" content.body = "my alert text" content.sound = nil logSB.info("Tickle Weather alert sent at \(currentDate)") let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 0.2, repeats: false) let request = UNNotificationRequest(identifier:requestIdentifier, content: content, trigger: trigger) UNUserNotificationCenter.current().add(request) { (error) in if (error != nil){ self.logSB.error("ERROR sending a notification at \(currentDate)") } // close error conditional } // close userNotificationThe user's logs show that web data were fetched and processed and that the alerts are sent with no error logged. But the user sees nothing.What are we missing?[update] I forgot to mention: When the user crosses a geofence set within my app, that notification comes through. Occaionally one of the previously missing alerts will fire at the same time, even a day late.
Posted
by waynehend.
Last updated
.
Post marked as solved
3 Replies
861 Views
My app uses a text field where the user enters a number. Upon an entry, the app checks to make sure that the user has entered a number and not gibberish, then stores the numerical entry as a double.let stored = NumberFormatter().number(from: textField.text! as String)!.doubleValueThen calculations are made and the gui updated. For updating the text field, I convert a stored double back to text:numberInput.text = String.localizedStringWithFormat("%.\3f %@", stored, "")It all works fine, for entries under 1000.Problem: When a comma is inserted by the localizer, as in "1,000", and the user does not clear the entire entry or enters a comma manually - for instance edits the old entry to show "1,001" - that is no longer recognized as a number. Of course entering 1001 is fine. I cannot just strip out the comma because it can have different meanings in different locations. I want to show the comma in the textfield to propoerly format the number display.Ideas?
Posted
by waynehend.
Last updated
.
Post not yet marked as solved
5 Replies
2.2k Views
I'm working on an engineering app that uses a bunch of java code I succefully converted using J2OBJC. Amazing! I can call the functions defined in that java code from my Swift code and it works nicely most of the time.But that java code throws an "OutOfRangeException" whenever the user input paramaters fall out of some range. The error ends up in my AppDelegate and crashes my app there.Is there a way to catch this "exception" gracefully without crashing?I've tried the following but it doesn't work, as Xcode warns:do { 'catch' block is unreachable because no errors are thrown in 'do' block let myVar = JavaProject().someFunction(with: Temp) } catch { }*** Terminating app due to uncaught exception 'OutOfRangeException', reason: 'JavaProject.OutOfRangeException'
Posted
by waynehend.
Last updated
.
Post marked as solved
8 Replies
790 Views
A "normal" for..in loop on an array handles the elements in the order you would expect. But not this one.Go ahead and try this in a playground. Every time it runs, I get a different ordering of the keys and never get back 1,2,3,4,5 as entered. If I make another loop around the loop shown (as commented out), it'll give the same key order for each iteration. But a different key order appears when the whole thing is rerun.Confused.import UIKit let dataTable: [String: [Double]] = [ "1Cat": [99.95, 0, 0.05, 0, 0, 0, 0.04], "2Dog": [1, 1, 0, 98, 0, 0, 0.2], "3Mouse": [49.0, 43.2, 3.9, 0, 0.2, 3.7, 0.05], "4Gerbil": [40.3, 55.4, 3.0, 0, 0.4, 0.9, 0.05], "5Fish": [7.7, 90.8, 1.2, 0, 0.1, 0.2, 0.05]] for i in dataTable { print(i) } // for j in 1...4 { // for i in dataTable { // print(i) // } // print("\n") // }
Posted
by waynehend.
Last updated
.
Post not yet marked as solved
15 Replies
8.1k Views
I'm familiar only with Swift. I have a running Swift app that I want to add other code to, from projects I've found online. One project was in C and with just a few hoops to jump, I got that part working. Yay me.Now I'm trying to add some C++ code and I'm hitting roadblocks.First question: Is my current Objective C Bridging Header the only one I need, or do I need another bridging header?Second question.The problem I'm having is with this code in my bridging header:#include "IF97.h" // The project I want to use #include <cmath> #include <vector> #include <algorithm> #include <iostream> #include <iomanip> #include <stdexcept> #include <stdio.h>All but the first and final lines produce "file not found" errors.
Posted
by waynehend.
Last updated
.
Post not yet marked as solved
4 Replies
5.8k Views
I've learned that ...performFetchWithCompletionHandler...is Deprecated in iOS 13.I'm looking for simple example code for retro-fitting my code for background URL sessions to be compatible with iOS 13.My app uses Background Fetch to grab repeating updates of web data whenever the app is in the background. It works pretty well. The main issue is that the time allocation by iOS is unpredictable. Anyway, now I want to ensure my app is ready for iOS 13. I've already addressed Dark Mode.The example code provided at WWDC 19 for performing background tasks...developer.apple.com/documentation/backgroundtasks/refreshing_and_maintaining_your_app_using_background_tasks...is useful but I'm finding it overly complex (Mock servers, Persistent Containers, etc.). Adapting this example to my app is daunting.I've found another writeup up. I haven't worked through it yet but it looks promising.dzone.com/articles/how-to-update-app-content-with-background-tasks-usIf anyone here knows of other good examples of background URL fetches, I'd appreciate some help.
Posted
by waynehend.
Last updated
.
Post not yet marked as solved
3 Replies
875 Views
Not sure where this should be posted. If you prefer it be somewhere else, just let me know.With the update to iOS 12.4, a user and I are noticing that my app is behaving a bit zombie-like when it's brought forward from the background. The app does background fetches and makes a few calculations while in the background, so it's necessary to refresh the GUI whenever the user returns to the app.The previous behavior, code below, performs a GUI refresh whenever the app was brought forward. This seemed fairly snappy and gave the user the freshest data. Now, the GUI is showing old data and feels dead when the app is brought forward. By "feels dead", I mean that nothing appears to be happening. Normally, the HomeKit homemanager is immediately called and the user can see the progress of that. And fresh web data might be called for, and arrive a few seconds later. None of this is happening.I should say it's not happening all the time. It does often happen properly, and only occasionally goes zombie on me.My background fetches trigger notifications and these are arriving as expected, so I don't think the problem is the lack of new data, it's an unresponsive GUI.Any ideas what's going on here, what might have changed?This is the code that's in my "Main" home screen class describing the view controller that is usually frontmost when the app enters or leaves the background. @objc func didEnterForeground() { //This executes EVERY time the app starts OR is brought forward. Central().calcThermSetting() // Forces a calculation based on the latest data self.logSB.info("didEnterForeground Ready for duty") // Mankes an entry into my Swifty ****** logging // weatherSourceLabel.isHidden = false self.setIndicator() // Sets the UI elements based on stored values of the Homekit indicators updateGUIWeather() updateGUIRate() updateWebData() updateGUIThermostat() }
Posted
by waynehend.
Last updated
.
Post not yet marked as solved
18 Replies
3.4k Views
This is really weird. My app involves a number of unit-of-measure choices made by the user for expressing pressure, temperature and so on. I save these user preferences in UserDefaults and for the most part it all works great. Except for one specific case, when "°F" comes back as "\U00b0F".The only way I know to see this anomaly is to store the choice of "°F" in an array stored in UserDefaults...var oldUnit = Central().getKey("tempUnit", defaultValue: "°F") // The user-entered, preferred temperature unit oldUnits[0] = oldUnit // Puts the stored unit preference into an array with other units choices defaults.set(oldUnits, forKey: "oldUnits") // Saves the array to UserDefaults...and then write the userdefaults to a text file to examine the contents:let filemgr = FileManager.default let dir: URL = filemgr.urls(for: .documentDirectory, in: .userDomainMask).last! as URL let url = dir.appendingPathComponent("defaultsFile.txt") if filemgr.fileExists(atPath: url.path) { // Try to get rid of an existing file do { try! filemgr.removeItem(at: url as URL) } catch { } } else { } var result = " " logSB.verbose("Writing the userDefaults to the iCloud defaults file...") for (key, value) in defaults.dictionaryRepresentation() { keyStore.set(value, forKey: key) do { try "\(key), \(value)".appendLineToURL(fileURL: url as URL) // Creates a new file if one is not pres// logSB.info("Writing \(value) for \(key) to file (not Keystore)") } catch { logSB.error("Could not write to local file") } } do { result = try String(contentsOf: url as URL, encoding: String.Encoding.utf8) // } catch { logSB.error("Could not read the defaults file after writing it") }Any key-value pair set to °F remains that way thorugh this process, but the °F placed into the array and then stored, shows up as \U00b0F.My app has a rare problem where it crashes at startup after a reinstall. I have no idea if this is the cause of that but it sure is suspicious.Any ideas?
Posted
by waynehend.
Last updated
.
Post not yet marked as solved
1 Replies
2.5k Views
I'm trying to understand a few issues around the timing of how data are backed up to iCloud and then recovered.My app uses iCloud backup of my NSUserDefaults and it works fine. For instance changes on one device (iPhone) soon appear on another (appleTV). If the user trashes my app for some reason, they can get back in business with all their own settings and preferences by simply trashing the app and re-installing it from the App Store. Cool.But here's where I'm confused. As soon as the user reinstalls and starts running the app again, I can see in the log file that iCloud is pushing every stored key-value pair to my app one at time, generating a notification with each pair. I didn't anticipate that many notifications when I wrote my code below, but it usually works fine anyway.I've seen some odd behavior though and I'm wondering about the timing of all this. The new ***** app opens with some assumed defaults that are used if there is no stored value available. Those assumed values end up in the display. As the key-value pairs arrive from iCloud, which I understand might be several minutes later, these defaults get reset in the background and there is then a discrepancy between the display and the desired values. I never really anticipated defaults being altered by anyone other than the user, in the app interface.I think what I need is a way to delay launching of the app until the iCloud stored values, if they exist, have all arrived.Does the synching of iCloud stored values (NSUbiquitousKeyValueStore) get synched when the app is installed, or only when the app first runs?How long are the iCloud data stored after an app is deleted? Forever? An hour? Users usually trash the app (due to a lockup or such) and reinstall within a few minutes, but what if they were to wait a day? Screwed?Here's the related code in my AppDelegate that makes it happen.NotificationCenter.default.addObserver(self, selector: #selector(settingsChange), name: NSUbiquitousKeyValueStore.didChangeExternallyNotification, object: NSUbiquitousKeyValueStore.default) @objc func settingsChange() { var keyStore = NSUbiquitousKeyValueStore.default keyStore.synchronize() let defaults: UserDefaults = UserDefaults.standard for (key, value) in keyStore.dictionaryRepresentation { defaults.set(value, forKey: key) } } func applicationWillResignActive(_ application: UIApplication) var keyStore = NSUbiquitousKeyValueStore.default for (key, value) in UserDefaults.standard.dictionaryRepresentation() { keyStore.set(value, forKey: key) do { try "\(key), \(value)".appendLineToURL(fileURL: url as URL) // Creates a new file if one is not present // logSB.info("Writing \(value) for \(key) to file (not Keystore)") } catch { logSB.error("Could not write to local file") } } do { result = try String(contentsOf: url as URL, encoding: String.Encoding.utf8) // The next line logs the entire preferences file logSB.warning("userDefaults saved to disk") // logSB.warning("There it is: \n\(results)") } catch { logSB.error("Could not read the defaults file after writing it") } logSB.verbose("Synchronizing the iCloud defaults file...") keyStore.synchronize()
Posted
by waynehend.
Last updated
.
Post not yet marked as solved
4 Replies
2.3k Views
I recently updated my app and uploaded it. This USED to change the version (build) that users could see and download. But my latest build is just sitting there while the older one remains the one shown in the store.I know it's a stupid question but there must be some easy way to force the store to use the latest build. I've clicked every link I could find in AppStoreConnect but cannot seem to find the solution.Somewhat related question: When I first created my app I gave it an arbitrary version number of "0.3". I'd like to now bump that up to "1.0". How do I do that? When I'm at AppStoreConnect:App=>Store=>App Information=>"Version or Platform", clicking on the "+" shows iOS greyed out. It won't allow me to create a new version.
Posted
by waynehend.
Last updated
.