Documentation of Frameworks that throw ObjC Exceptions?

I recently discovered that CryptokenKit (TKSmartCard.transmit) throws an ObjC exception, and thus crashes a Swift app using TKSmartCard (absent an ObjC wrapper to handle the Objc exception explicitly).

That was surprising, as there was no documentation indicating that TKSmartCard needs to be wrapped in ObjC instead being used directly from Swift. (See https://developer.apple.com/documentation/cryptotokenkit/tksmartcard/1390161-transmit) - the exception is a NSInternalInconsistencyException, which is thrown when certain codepaths are executed in a certain sequence (which indeed, leaves a TKSmartCard in an inconsistent state).

Is there a list of Frameworks that throw ObjC exceptions (and therefore need special handling by Swift when invoking methods/functions)?

As a general rule Objective-C exceptions are not recoverable. A framework should only throw an exception when:

  • It’s passed bad avoidably bad parameters by the caller.

  • It has noticed an internal state problem and wants to trap (roughly equivalent to fatalError(…) in Swift).

In both case, having the process crash is the correct response and I recommend that you not try to subvert that.

In the specific case of CryptoTokenKit, you mentioned “TKSmartCard.transmit”, which I presume is referring to the transmit(_:reply:) method. Under what circumstances are you seeing that throw an Objective-C exception?

And, if you have a crash report handy, please post it here, using the instructions in Posting a Crash Report.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Hi Quinn- I'm not trying to understand why its throwing the ObjC exception (though i wish it was a Swift error, because in the case of the card state, it really is recoverable, I think) - I'm trying to figure out what methods/functions are going to throw exceptions, and how to properly handle it, from a Swift app. Maybe TKSmartCard is not following the guidelines about throwing exceptions?

Another example I just saw today:TKSmartCardSlotManager. slotNames threw this ObjC exception (during awakening from background, seen once):

SIGABRT (#0): Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSDictionaryM: 0x300f8c860> was mutated while being enumerated.'.

I'm guessing there's something happening on resuming from background in the framework that is causing a race condition. I notice that in another thread in the crash report there's something suspicious (this is not a method that is publicly available - I don't know how it gets called): 4 CryptoTokenKit 0x00000001cc7d2934 -[TKSmartCardSlotManager setSlotWithName:endpoint:type:reply:] + 276

The question I am asking is about to what extent we are supposed to be writing ObjC wrappers around Frameworks like TKSmartCard instead of calling the TKSmartCard framework functions directly from Swift, since TKSmartCard seems to be throwing some ObjC exceptions in places I find surprising.


P.S. It feels like you are holding up the entire developer ecosystem on your shoulders, I hope your effort it recognized by Apple. Your work here is very much appreciated! :D

I'm trying to figure out what methods/functions are going to throw exceptions, and how to properly handle it, from a Swift app.

Let me repeat my comment above: Objective-C exceptions are not recoverable. There is no way to properly handle them, even in Objective-C [1].

Maybe TKSmartCard is not following the guidelines about throwing exceptions?

… or you’re not calling it correctly. That’s why I asked for a crash report, so I can track down the throw site and work out what’s going wrong.

However, to be clear, Apple frameworks should not throw language exceptions that you’re expected to handle [2]. If one of our frameworks throws an exception, that’s the equivalent of a fatalError(…) in Swift. The only correct behaviour is to crash the process.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] There are exceptions (hey hey) to this rule, when a class is documented to throw an exception in a very specific case. However, even that’s problematic in modern Objective-C because ARC doesn’t guarantee to reclaim memory when an exception is thrown. So, you can reliably handle an Objective-C exception if:

  • You’re programming in Objective-C.

  • You’re using MRR rather than ARC.

  • The exception is part of the API contract for the API you’re calling.

This is vanishingly uncommon in practice, and hence my generalisation.

[2] Except for the very few cases where the exception is part of the API contract. And we’ve been proactively removing those in recent years. Historically, the two most common ones were:

  • NSFileHandle — We’ve recently introduced APIs that return errors rather than throw a language exception.

  • Distributed Objects — This is now formally deprecated (and there was much rejoicing).

Documentation of Frameworks that throw ObjC Exceptions?
 
 
Q