Crash when unwrapping optional - ios

I have several clients that are complaining of a crash in my app. I have never been able to reproduce it. Crashlitics has detected the crash :
func addDevice(unconfiguredDevice: UnconfiguredDevice) {
if let macSegment = unconfiguredDevice.macSegmentFromSSID { <<-CRASH
print("unconfigured mac: \( macSegment )")
if let setupDevice = self.unconfiguredDevices.value.first(where: { Device in Device.macEnd == unconfiguredDevice.macSegmentFromSSID! }) {
setupDevice.unconfiguredDevice = unconfiguredDevice
} else {
self.unconfiguredDevices.value.append(SetupDevice(unconfiguredDevice: unconfiguredDevice))
}
}
}
The crash type is EXC_BREAKPOINT. I have seen on several other threads around here that this kind of crash might be related to optional unwrapping, and indeed that macSegment method there returns an optional. But I don't understand what the problem might be. (BTW this method is for detecting devices that are configurable via WAC).
Any ideas/tips/suggestions ?

The crash occurs because macSegmentFromSSID was nil when you tried to unwrap it.
try like
if let setupDevice = self.unconfiguredDevices.value.first(where: { Device in Device.macEnd == macSegment}) {
setupDevice.unconfiguredDevice = unconfiguredDevice
}

Related

Can two same closures on the main thread, from the same function call, crash an iOS program written in Swift?

My users experienced crashes when I sent them an update on TestFlight. After examining the eight crash reports they submitted, I've noticed a commonality - there are two of the same closures sitting on top of thread 0. Could this have caused the crash? What do you think is the cause, if not?
Please see image for crash report of thread 0. All other threads generally look the same in the report.
Note - when the users opened their app subsequent times after the initial opening, they did not experience further crashes.
Thank you in advance for your thoughts.
Update from comments, 9/29/22 -
Here's the closure code as requested by Damien and Tadreik:
When the app is opened, this line runs during initialization, which sets up the variables the connection view controller needs. Thus the empty closure.
if !twilioIDs.isEmpty {
ProfileModelManager.shared.getUsersForConnectionView(withTwilioIDs: twilioIDs) { _ in }
}
And the code below is invoked when the connection view is tapped on from the menu tab the second time:
if !twilioIDs.isEmpty {
ProfileModelManager.shared.getUsersForConnectionView(withTwilioIDs: twilioIDs) { result in
guard let success = result else { return }
if success {
self.handleSuccessOfGettingConnectionCards()
}
else {
self.handleFailureOfGettingConnectionCards()
}
}
}
Here is the code for handleSuccessOfGettingConnectionCards -
refreshControl.endRefreshing()
hideNoConnectionsLabel()
createChatViewControllersForChannels()
connectionsTableView.alpha = 1
errorConnectingLabel.alpha = 0
connectionsTableView.reloadData()
showActivitySpinner(false)
navigationController?.navigationBar.isHidden = true
Here is the code for handleFailureOfGettingConnectionCards -
showErrorConnectingMessage()
refreshControl.endRefreshing()
connectionsTableView.alpha = 0
hideNoConnectionsLabel()
showActivitySpinner(false)
Thanks in advance again for any intuition or experience you may share.
The crash log for thread 0
The code inside the closure ProfileModelManager.shared.getUsersForConnectionView(withTwilioIDs: twilioIDs) { result in captures a reference to self, your problem might be that at the time of execution, self is pointing to a null reference (has been deallocated), which can cause a crash. Try to set a weak reference to self like that and see if the crash still occurs :
if !twilioIDs.isEmpty {
ProfileModelManager.shared.getUsersForConnectionView(withTwilioIDs: twilioIDs) { [weak self] result in
guard let success = result else { return }
if success {
self?.handleSuccessOfGettingConnectionCards()
}
else {
self?.handleFailureOfGettingConnectionCards()
}
}
}
If you want you could also handle the nil case of the weak self as any other optional.

How can I debug a "BUG IN CLIENT OF LIBPLATFORM: Trying to recursively lock an os_unfair_lock" crash?

I am writing a simple WKWebView extension that executes some Javascript and return the result as a Future.
func runJSFuture(_ js: String) -> Future<Any?, Error> {
Future<Any?, Error> { promise in
self.evaluateJavaScript(js) { (result: Any?, error: Error?) in
if let errorUnwrapped = error {
promise(.failure(errorUnwrapped))
return
}
promise(.success(result))
}
}
}
However, sometimes(consistently at a particular JS, but not all the time, so I figured it's not a problem with the JS itself) I get a crash as follows. I've been debugging and researching for a while and I've checked for implicitly unwrapped vars, force unwrapping. I'm stll unable to find the cause. There is not much useful information on the stack trace as well.
EDIT :
I've did some poking around converting the future to a PassthroughSubject and I have found where exactly the code in my question crashes. It'd comfort me if one could explain why/ how the crash happens and what I can do to avoid it or if this is a Combine bug.
func runJSFuture(_ js: String) -> AnyPublisher<Any?, Error> {
let pts = PassthroughSubject<Any?, Error>()
self.evaluateJavaScript(js) { (result, error) in
if let errorUnwrapped = error {
pts.send(completion: .failure(errorUnwrapped))
return
}
pts.send(result)
//pts.send(completion: .finished) // crashes here
}
return pts.eraseToAnyPublisher()
}
If I comment the line that crashes, the code works fine, but if I understand correctly, the pipeline would be open indefinitely? Any help would be extremely appreciated.

Implementing Swift 5.1 collection diffing in internal type

I'm building an iOS app that displays ranged iBeacons in a TableViewController.
To improve performances and test the new Swift 5.1 diffing feature I wrote the following code:
private func updateBeacons(_ rangedBeacons: [CLBeacon]) {
guard beacons != rangedBeacons else { return }
let difference = rangedBeacons.difference(from: beacons)
// Also tried:
// let difference = rangedBeacons.difference(from: beacons, by: { $0.uuid == $1.uuid })
// ...
}
When this code is reached a fatalError is thrown:
Fatal error: unsupported: file
/BuildRoot/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-1100.2.259.70/swift/stdlib/public/core/ArrayBuffer.swift,
line 231
How can I perform collection diffing on CLBeacons?
The referenced code can be found here:
https://github.com/apple/swift/blob/master/stdlib/public/core/ArrayBuffer.swift#L226-L232
I was hitting this issue as well, but in my case I was getting one of the arrays from a Core Data NSFetchedResultsController. I suspect it's related to the fact that the original array comes from Objective-C.
I was able to fix this by wrapping the arrays in a new Array:
private func updateBeacons(_ rangedBeacons: [CLBeacon]) {
guard beacons != rangedBeacons else { return }
let difference = Array(rangedBeacons).difference(from: Array(beacons))
// ...
}

Saving then accessing entity from managedObjectContext in CoreData occasionally crashes

I'm struggling to debug a hard-to-reproduce-locally crash in my app. The crash reports show the exception type is EXC_BAD_ACCESS (SIGSEGV) with objc_msgSend at the top of the crashed thread, perhaps suggesting "The process may have attempted to message a deallocated object" (as per Apple's documents).
I have not been able to recreate the crash or find any zombies using the Zombies instrument, despite using an older device and the same simulated device causing the most crashes.
From the trace I'm pretty sure I've been able to work out where the crash is occurring, but I'm not sure what I'm doing wrong.
My app is basically a group database. The app takes a username and password, sending them to a server to check if the person can be logged in. If valid, the app downloads the data on all the people in the group, then finds the logged in person from the downloaded data based on their username.
Because of the way the server code is set up, the username must be present in the downloaded data (if it all downloads correctly), yet my code occasionally fails to find them, and (from the crash logs) also occasionally this attempted finding of the person causes a crash.
coreDataStack.storeContainer.performBackgroundTask() { context in
OverallNetworkCalls.deleteAllLoadPeople(moContext: context) { result in
self.coreDataStack.saveNewContext(context: context)
if result == .success {
let person = AdministrativeHelperFunctions.returnCurrentUserFromUserName(moContext: context)
if let person = person {
DispatchQueue.main.async {
self.activityIndicator.stopAnimating()
}
UserDefaults.standard.set(person.objectID.uriRepresentation(), forKey: udl.CurrentUserMOID.rawValue)
} else {
DispatchQueue.main.async {
self.activityIndicator.stopAnimating()
self.loadingLabel.text = "Data was downloaded but your username isn't there. Try deleting and reloading the app, or contact admin."
}
}
}
func saveNewContext(context: NSManagedObjectContext) {
context.perform {
guard context.hasChanges else { return }
do {
try context.save()
} catch {
//logs the issue locally
}
}
}
func returnCurrentUserFromUserName(moContext: NSManagedObjectContext) -> Person? {
let userName = UserDefaults.standard.string(forKey: "username")
if let userName = userName {
//Create predicate, arrayForResults etc
do {
userNameMatchesArray = try moContext.fetch(fetchRequest)
} catch {
//logs the issue locally
}
if userNameMatchesArray.count == 1 {
return userNameMatchesArray[0]
} else {
return nil
}
} else {
return nil
}
}
My suspicion is that the returnCurrentUserFromUserName function is returning the user before the saveNewContext function has completed its task and that this is contributing to the issue, though given the same managedObjectContext is saving then retrieving the person I had originally assumed this wasn't a problem. I'm also not sure that using "context.perform" in the saveNewContext function is necessary/wise/useful; I'd value feedback on this too if anyone knows best practice inside a performBackgroundTask block.
A non-reproduceable bug is always the most frustrating to fix, and because of this anything I try to fix it won't be shown until I send it to my beta testers and get crashlogs back (or not!).
Thanks in advance for reviewing this problem.

Force reload watchOS 2 Complications

I have issues getting Complications to work. It would be helpful if I was able to reliably refresh them.
Therefore I linked a force-press menu button to the following method
#IBAction func updateComplication() {
let complicationServer = CLKComplicationServer.sharedInstance()
for complication in complicationServer.activeComplications {
complicationServer.reloadTimelineForComplication(complication)
}
}
Unfortunately this leads to the app crashing. with a fatal error: unexpectedly found nil while unwrapping an Optional value.
I understand that calling reloadTimelineForComplication(complication) is budgeted but that can't be the issue here as it doesn't work from the very beginning.
I am currently using watchOS2 + Xcode 7 GM
I'd appreciate any ideas on making Complications refresh while the app is running?
Trace or use the exception breakpoint and focus on reading the whole error message where it tells you exactly on which line it found the nil unexpectedly (I do suspect the complicationServer). Use 'if let' instead of 'let' to force unwrap the respective variable.
private func reloadComplications() {
if let complications: [CLKComplication] = CLKComplicationServer.sharedInstance().activeComplications {
if complications.count > 0 {
for complication in complications {
CLKComplicationServer.sharedInstance().reloadTimelineForComplication(complication)
NSLog("Reloading complication \(complication.description)...")
}
WKInterfaceDevice.currentDevice().playHaptic(WKHapticType.Click) // haptic only for debugging
}
}
}

Resources