Cocoa exceptions: pre-and post-Mojave

  1. 2 months ago

    Michael D

    Aug 8 Pre-Release Testers, Xojo Pro

    Sam noted this earlier:

    Cocoa exceptions are no longer logged to the console.
    Workaround: none yet.
    Note: Trying to prepare applications for Mojave are hard when things have changed, which causes a Cocoa Exception. This results in a function silently failing, with no pointers or indication why. You must manually step through code until you find the line it fails on, then do research to figure out why that line fails.

    This just bit me in a big way.

    I was trying to work out the declares to detect Dark Mode, and used the following code:

    #if TargetMacOS
    function IsDarkMode() as boolean
      // see https://developer.apple.com/documentation/appkit/nsappearance
      
      Declare Function NSClassFromString Lib "Foundation" (classname As CFStringRef) As Ptr
      Declare Function NSAppearanceCurrentApperance Lib "Foundation" Selector "currentAppearance:" (classname As Ptr) As Ptr
      Declare Function NSAppearanceName Lib "Foundation" Selector "name:" (obj As Ptr) As CFStringRef
      
      dim nsa as Ptr = NSClassFromString("NSAppearance")
      dim currentAppearance as Ptr = NSAppearanceCurrentApperance(nsa)
      if currentAppearance <> nil then
        dim name as string = NSAppearanceName(currentAppearance)
        if name = "NSAppearanceNameDarkAqua" then
          return true
        end if
      end if
      return false
    #else
      return false
    #endif
    end function

    Looks good, right?

    Except there are two flaws which are subtle but fatal.

    Without fixing the flaws, this function dies silently mid-stream. And by "dies" I do not mean "crashes" or "throws an exception" - no. Instead, the thread just disappears. This is extremely hard to debug and very user unfriendly. Very non "Xojo" like.

    Puzzle:
    • can anyone identify the flaws?

    Questions:
    • can Xojo do something to prevent these types of errors from being so incredibly hard to find and fix?

  2. Sam R

    Aug 8 Pre-Release Testers, Xojo Pro Hengchun, Pingtung, Taiwan

    1. You need to get the appearance from an Appearance compatible object (one that adheres to the Appearance protocol), mainly a window, or under Mojave, the application also.

    2. I can't answer that one.

  3. Michael D

    Aug 8 Pre-Release Testers, Xojo Pro

    @Sam R 1. You need to get the appearance from an Appearance compatible object (one that adheres to the Appearance protocol), mainly a window, or under Mojave, the application also.

    Close but not quite. The fixed code works under 10.12 and 10.14.

    The bug is subtle.

    Hint: this is more like https://priceonomics.com/the-typo-that-destroyed-a-space-shuttle/

    only it wasn't a Hypen

  4. Sam R

    Aug 8 Pre-Release Testers, Xojo Pro Hengchun, Pingtung, Taiwan

    @Michael D Declare Function NSAppearanceName Lib "Foundation" Selector "name:" (obj As Ptr) As CFStringRef

  5. Sam R

    Aug 8 Pre-Release Testers, Xojo Pro Hengchun, Pingtung, Taiwan

    @Michael D Close but not quite. The fixed code works under 10.12 and 10.14.

    Huh? My understanding of the appearance framework was that it only worked on the objects that it adhered to? At least that's how I've been using it. Then again, I am more familiar with using it in 10.10 + to force my applications to have a dark theme.

    p.s. If you use the right declares at the right time (i.e. right event) you don't need to know which theme is being used, you'll get the correct colors for the controls that the OS doesn't auto update for you.

  6. Ulrich B

    Aug 9 Pre-Release Testers, Xojo Pro Europe (Germany, Berlin) · xo...
    Edited 2 months ago

    @Michael D • can anyone identify the flaws?

    Without having checked the code completely: Two selectors are wrong. They must be
    "currentAppearance" and "name"
    (without the colons).

    EDIT: I’ve been searching console up and down and finally found a clue under the "devices" tab (Mojave 18A353d):

    standard 10:45:26.921128 +0200 My Application.debug +[NSAppearance currentAppearance:]: unrecognized selector sent to class 0x7fff88ac44d8

    EDIT II: Below that message, I see two private errors listed marked "<private>" (showing only the pid and thread ID), and further below

    standard 10:45:28.905691 +0200 My Application.debug 27366555: RECEIVED OUT-OF-SEQUENCE NOTIFICATION: 191 vs 296, 512, <private>
    standard 10:45:30.639889 +0200 My Application.debug LSExceptions shared instance invalidated for timeout.

    Could that be a hint to the reason macOS does not show a crash window in this case?

  7. Greg O

    Aug 9 Xojo Inc

    I’d also like to point out that NSAppearance is in the AppKit framework, not Foundation.

  8. Michael D

    Aug 9 Pre-Release Testers, Xojo Pro

    @Ulrich B Without having checked the code completely: Two selectors are wrong. They must be
    "currentAppearance" and "name"
    (without the colons).

    This is correct!

    @Greg OLone I’d also like to point out that NSAppearance is in the AppKit framework, not Foundation.

    Weirdly, that doesn't seem to matter - the corrected code works for me (in 10.12.6 and 10.14 beta 6 at least):

    Public Function IsDarkMode() as boolean
      #if TargetMacOS
        // see https://developer.apple.com/documentation/appkit/nsappearance
        Declare Function NSClassFromString Lib "Foundation" (classname As CFStringRef) As Ptr
        Declare Function NSAppearanceCurrentApperance Lib "Foundation" Selector "currentAppearance" (classname As Ptr) As Ptr
        Declare Function NSAppearanceName Lib "Foundation" Selector "name" (obj As Ptr) As CFStringRef
        dim nsa as Ptr = NSClassFromString("NSAppearance")
        dim currentAppearance as Ptr = NSAppearanceCurrentApperance(nsa)
        if currentAppearance <> nil then
          dim name as string = NSAppearanceName(currentAppearance)
          if name = "NSAppearanceNameDarkAqua" then
            return true
          end if
        end if
        return false
      #else
        return false
      #endif
    End Function

    Does Xojo or macOS have some sort of search function to find the function even if we provide the wrong framework?

  9. Greg O

    Aug 9 Xojo Inc

    @Michael D Does Xojo or macOS have some sort of search function to find the function even if we provide the wrong framework?

    It's a bug that it works.

  10. Sam R

    Aug 9 Pre-Release Testers, Xojo Pro Hengchun, Pingtung, Taiwan

    @Greg OLone It's a bug that it works.

    Isn't that a "feature"?

  11. Christoph D

    Aug 9 Pre-Release Testers, Xojo Pro

    I am pretty sure Xojo Inc will make the new changes for Mojave work in the next Xojo release (auto switching Light/Dark mode, ..) ;-) ;-)

or Sign Up to reply!