{"id":45413,"date":"2024-10-17T15:22:36","date_gmt":"2024-10-17T19:22:36","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=45413"},"modified":"2024-10-17T15:23:31","modified_gmt":"2024-10-17T19:23:31","slug":"toothfairy-2-8-5","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2024\/10\/17\/toothfairy-2-8-5\/","title":{"rendered":"ToothFairy 2.8.5"},"content":{"rendered":"<p><a href=\"https:\/\/c-command.com\/blog\/2024\/10\/17\/toothfairy-2-8-5\/\">ToothFairy 2.8.5<\/a> is a maintenance update of my Bluetooth menu bar utility. It fixes a bug where sometimes ToothFairy wouldn&rsquo;t auto-launch at login.<\/p>\n\n<p>An interesting bug was:<\/p>\n<ul><li>\n<p>ToothFairy uses <code>SMLoginItemSetEnabled()<\/code>, which, instead of launching the app directly, launches a helper app that can launch the main app. Originally, it did this using <code>NSWorkspace.launchApplication(_:)<\/code>, but then Xcode reported this as deprecated, so I updated it to the new API, <code>openApplication(at:configuration:completionHandler:)<\/code>. There seemed to be no need to report errors in this case, so I just passed <code>nil<\/code> for the completion handler. The documentation says that the method &ldquo;Launches the app at the specified URL and asynchronously reports back on the app&rsquo;s status.&rdquo; What I didn&rsquo;t realize, and seems contrary to the documentation, is that it doesn&rsquo;t just <em>report<\/em> the success or failure asynchronously, but it seems to also do the <em>launching<\/em> asynchronously. Sometimes the API would return, the helper app would quit, and this would derail the launching. The fix is to keep the helper running until the completion handler has been called.<\/p>\n<\/li><\/ul>","protected":false},"excerpt":{"rendered":"<p>ToothFairy 2.8.5 is a maintenance update of my Bluetooth menu bar utility. It fixes a bug where sometimes ToothFairy wouldn&rsquo;t auto-launch at login. An interesting bug was: ToothFairy uses SMLoginItemSetEnabled(), which, instead of launching the app directly, launches a helper app that can launch the main app. Originally, it did this using NSWorkspace.launchApplication(_:), but then [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"apple_news_api_created_at":"2024-10-17T19:22:40Z","apple_news_api_id":"f9606a47-bad5-4232-a0e5-cd8014775608","apple_news_api_modified_at":"2024-10-17T19:23:33Z","apple_news_api_revision":"AAAAAAAAAAAAAAAAAAAAAA==","apple_news_api_share_url":"https:\/\/apple.news\/A-WBqR7rVQjKg5c2AFHdWCA","apple_news_coverimage":0,"apple_news_coverimage_caption":"","apple_news_is_hidden":false,"apple_news_is_paid":false,"apple_news_is_preview":false,"apple_news_is_sponsored":false,"apple_news_maturity_rating":"","apple_news_metadata":"\"\"","apple_news_pullquote":"","apple_news_pullquote_position":"","apple_news_slug":"","apple_news_sections":"\"\"","apple_news_suppress_video_url":false,"apple_news_use_image_component":false,"footnotes":""},"categories":[2],"tags":[69,30,32,2598,71,1687],"class_list":["post-45413","post","type-post","status-publish","format-standard","hentry","category-technology","tag-cocoa","tag-mac","tag-macapp","tag-macos-15-sequoia","tag-programming","tag-toothfairy"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/45413","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/comments?post=45413"}],"version-history":[{"count":2,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/45413\/revisions"}],"predecessor-version":[{"id":45415,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/45413\/revisions\/45415"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=45413"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=45413"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=45413"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}