{"id":53059,"date":"2026-09-01T16:09:17","date_gmt":"2026-09-01T20:09:17","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=53059"},"modified":"2026-09-01T16:09:17","modified_gmt":"2026-09-01T20:09:17","slug":"tipkit-for-the-real-world","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2026\/09\/01\/tipkit-for-the-real-world\/","title":{"rendered":"TipKit for the Real World"},"content":{"rendered":"<p><a href=\"https:\/\/furbo.org\/2026\/08\/31\/tipkit-for-the-real-world\/\">Craig Hockenberry<\/a>:<\/p>\n<blockquote cite=\"https:\/\/furbo.org\/2026\/08\/31\/tipkit-for-the-real-world\/\">\n<p>Then, when you look at <a href=\"https:\/\/developer.apple.com\/documentation\/tipkit\/highlightingappfeatureswithtipkit\">the sample code<\/a>, it&rsquo;s all SwiftUI. At least the sample compiles and runs because it uses a completely different syntax than what was shown at WWDC.<\/p>\n<p>[&#8230;]<\/p>\n<p>Eventually I stumbled upon <a href=\"https:\/\/developer.apple.com\/documentation\/tipkit\/tipuipopoverviewcontroller\">TipUIPopoverViewController<\/a> which inherits from UIViewController. That should work! [&#8230;] But it didn&rsquo;t: <a href=\"https:\/\/github.com\/chockenberry\/Tipster\/blob\/748b149db9823720be270bd0f4b3ebfd0b9d1b42\/Tipster\/PresentedViewController.swift#L100\">the close button on the popover didn&rsquo;t work<\/a>.<\/p>\n<p>[&#8230;]<\/p>\n<p>Until you realize that any changes you make are <a href=\"https:\/\/fatbobman.com\/en\/posts\/mastering-tipkit-advance\/#finding-answers-from-tipkits-persistent-data\">stored in a SQLite database<\/a>, debugging is very confusing. It&rsquo;s also easy for your own state to get out-of-sync with the Tip state: there is not a single source of truth.<\/p>\n<p>[&#8230;]<\/p>\n<p>Unfortunately, that sample code doesn&rsquo;t scale well. If you have a view with multiple tips, you&rsquo;re going to be littering your code with tip instances, observation tasks, and popover controllers. It&rsquo;s a mess and a clear sign that the TipKit developers didn&rsquo;t think much about UIKit.<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/fatbobman.com\/en\/posts\/mastering-tipkit-advance\/\">Fatbobman<\/a>:<\/p>\n<blockquote cite=\"https:\/\/fatbobman.com\/en\/posts\/mastering-tipkit-advance\/\">\n<p>In the previous article, we introduced the basic usage of TipKit. In this article, we will discuss some advanced topics related to TipKit, such as how to fully customize Tip views (not using TipView and popoverTip), how to use TipKit with UIKit, and how TipKit can share data across different applications, as well as how to reuse Tip declaration code. Additionally, we will attempt to address some common questions and concerns about TipKit.<\/p>\n<\/blockquote>\n\n<p>Previously:<\/p>\n<ul>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2026\/06\/19\/swiftui-in-appleos-27\/\">SwiftUI in appleOS 27<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2025\/06\/18\/swiftui-at-wwdc-2025\/\">SwiftUI at WWDC 2025<\/a><\/li>\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>Craig Hockenberry: Then, when you look at the sample code, it&rsquo;s all SwiftUI. At least the sample compiles and runs because it uses a completely different syntax than what was shown at WWDC. [&#8230;] Eventually I stumbled upon TipUIPopoverViewController which inherits from UIViewController. That should work! [&#8230;] But it didn&rsquo;t: the close button on the [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"apple_news_api_created_at":"2026-09-01T20:09:22Z","apple_news_api_id":"750ae784-e807-40c8-b107-fe4a15940d90","apple_news_api_modified_at":"2026-09-01T20:09:22Z","apple_news_api_revision":"AAAAAAAAAAD\/\/\/\/\/\/\/\/\/\/w==","apple_news_api_share_url":"https:\/\/apple.news\/AdQrnhOgHQMixB_5KFZQNkA","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":[4],"tags":[31,2741,74,71,901,1812,2750],"class_list":["post-53059","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-ios","tag-ios-26","tag-opensource","tag-programming","tag-swift-programming-language","tag-swiftui","tag-tips-app"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/53059","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=53059"}],"version-history":[{"count":1,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/53059\/revisions"}],"predecessor-version":[{"id":53060,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/53059\/revisions\/53060"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=53059"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=53059"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=53059"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}