Hi there, I’m Khoa aka onmyway133 👋

  • 🧑‍💻 I love crafting high quality and useful apps

  • 🔥 I love open source. My GitHub open source has 1.6k followers with packages that are integrated by 45k+ apps and over 3.4m+ downloads on CocoaPods.

  • ✍️ I write here on my blog and on Medium, which has over 2.4k+ followers with tons of articles and 90k+ monthly views.

  • 🖥 Follow me for sharings about Swift, SwiftUI, iOS and macOS development

My favorite WWDC videos

Issue #891 WWDC18 Designing Fluid Interfaces Testing Tips & Tricks WWDC22 The craft of SwiftUI API design: Progressive disclosure Read more https://onmyway133.com/posts/favorite-wwdc-2017-sessions/ https://onmyway133.com/posts/favorite-wwdc-2018-sessions/ https://onmyway133.com/posts/favorite-wwdc-2019-sessions/ https://www.hackingwithswift.com/articles/239/wwdc21-wrap-up-and-recommended-talks https://www.hackingwithswift.com/articles/190/the-best-wwdc-videos-of-all-time

June 10, 2022 · 1 min · Khoa Pham

WWDC swiftui-lounge

Issue #890 In WWDC21, WWDC22 Apple provide a Slack channel https://wwdc22.slack.com/ for people to interact with Apple engineers in digital lounges. Here I note down some interesting Q&As WWDC22 What’s the difference between a custom ViewModifier vs View extension Q: What’s the difference between a custom ViewModifier (without DynamicProperty) that uses some built-in modifiers in body(content:), and a custom View extension func that just use those built-in modifiers? Similarly, what’s the difference between a custom ViewModifier with some DynamicProperty and a custom View with some DynamicProperty (also has a @ViewBuilder content property to receive content to modify) ?...

June 10, 2022 · 31 min · Khoa Pham

What's new in SwiftUI iOS 16 at WWDC22

Issue #889 What’s new in SwiftUI New EnvironmentValues TextField inside Alert List uses UICollectionView See gist https://gist.github.com/onmyway133/fc08111964984ef544a176a6e9806c18 ButtonStyle composition Section("Hashtags") { VStack(alignment: .leading) { HStack { Toggle("#Swiftastic", isOn: $swiftastic) Toggle("#WWParty", isOn: $wwdcParty) } HStack { Toggle("#OffTheCharts", isOn: $offTheCharts) Toggle("#OneMoreThing", isOn: $oneMoreThing) } } .toggleStyle(.button) .buttonStyle(.bordered) } Customize Charts struct MonthlySalesChart: View { var body: some View { Chart(data, id: \.month) { BarMark( x: .value("Month", $0.month, unit: .month), y: .value("Sales", $0.sales) ) } ....

June 9, 2022 · 5 min · Khoa Pham

How to use any vs some in Swift

Issue #888 Embrace Swift generics This generic pattern is really common, so there’s a simpler way to express it. Instead of writing a type parameter explicitly, we can express this abstract type in terms of the protocol conformance by writing “some Animal”. The “some” in “some Animal” indicates that there is a specific type that you’re working with. func feed<A>(animal: A) where A: Animal {} func feed(animal: some Animal) An abstract type that represents a placeholder for a specific concrete type is called an opaque type....

June 8, 2022 · 5 min · Khoa Pham

How to use Swift

Issue #887 What’s new https://www.whatsnewinswift.com https://www.hackingwithswift.com/articles/249/whats-new-in-swift-5-7 https://www.hackingwithswift.com/articles/247/whats-new-in-swift-5-6

June 7, 2022 · 1 min · Khoa Pham

How to use SwiftUI

Issue #886 SwiftUI iOS 16 https://bigmountainstudio.github.io/What-is-new-in-SwiftUI/ https://swiftwithmajid.com/2022/06/07/what-is-new-in-swiftui-after-wwdc22/ https://www.hackingwithswift.com/articles/250/whats-new-in-swiftui-for-ios-16 SwiftUI https://www.hackingwithswift.com/articles/235/whats-new-in-swiftui-for-ios-15 https://www.hackingwithswift.com/articles/221/whats-new-in-swiftui-for-ios-14 https://talk.objc.io/collections/swiftui-layout-explained SwiftUI practices 8 Common SwiftUI Mistakes – and how to fix them! https://www.youtube.com/watch?v=qkcKTJhDyLs 5 Steps to Better SwiftUI Views https://www.youtube.com/watch?v=uC3X4FoielU SwiftUI tips and tricks https://www.hackingwithswift.com/quick-start/swiftui/swiftui-tips-and-tricks SwiftUI Tips https://www.youtube.com/watch?v=M2e1Z9enFHo Tips thread https://twitter.com/twostraws/status/1465801488920465414?s=20 Quick Friday tips https://twitter.com/search?src=typed_query&q=%22Quick%20Friday%20tip%22%20(from%3Ascottsmithdev Reference https://github.com/onmyway133/awesome-swiftui https://swiftontap.com/

June 7, 2022 · 1 min · Khoa Pham

How to convert NSImage to PNG Data

Issue #885 Create NSBitmapImageRep with preferred size and draw NSImage onto that. Need to construct NSBitmapImageRep specifically instead of using convenient initializers like NSBitmapImageRep(data:), NSBitmapImageRep(cgImage:) to avoid device dependant resolution issue. extension NSImage { func pngData( size: CGSize, imageInterpolation: NSImageInterpolation = .high ) -> Data? { guard let bitmap = NSBitmapImageRep( bitmapDataPlanes: nil, pixelsWide: Int(size.width), pixelsHigh: Int(size.height), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: .deviceRGB, bitmapFormat: [], bytesPerRow: 0, bitsPerPixel: 0 ) else { return nil } bitmap....

June 6, 2022 · 1 min · Khoa Pham

How to get notification userInfo at launch

Issue #884 When user taps on push notification, depending on app state SceneDelegate Checking UIScene.ConnectionOptions.notificationResponse?.notification.request.content.userInfo in scene(_:willConnectTo:options:) app terminated: sometimes nil app in background: notification info UNUserNotificationCenter Checking UNNotificationResponse.notification.request.content.userInfo in userNotificationCenter(_:didReceive:withCompletionHandler:) app terminated: notification info app in background: notification info

June 1, 2022 · 1 min · Khoa Pham

How SwiftUI works

Issue #883 Read more https://www.objc.io/blog/2020/11/10/hstacks-child-ordering/ https://talk.objc.io/collections/swiftui-layout-explained https://rensbr.eu/blog/swiftui-escaping-closures/ https://rensbr.eu/blog/swiftui-render-loop/ https://movingparts.io/variadic-views-in-swiftui

May 31, 2022 · 1 min · Khoa Pham

How to use popover in SwiftUI

Issue #882 In SwiftUI, .popover shows as popover on Mac and iPad, but as .sheet on iPhone (compact size class) We can use minWidth, minHeight to specify sizes on Mac and iPad. On iPhone, we can check and wrap it inside NavigationView. Setting navigationTitle without being embedded in NavigationView has not effect `` .popover(isPresented: $showsEdit) { EditSnippetView( snippet: snippet ) .frame(minWidth: 300, alignment: .topLeading) .navigationTitle("Tags") .modifier( EmbedInNavigationModifier() ) }

May 29, 2022 · 1 min · Khoa Pham

How to select in List in SwiftUI

Issue #881 Specify optional value for List(selection:). This keeps selection on macOS, but not on iPad. On iPad each row in the List needs to be NavigationLink, no need for .tag. The selection is not updated, need to manually update with onTapGesture struct Sidebaer: View { class ViewModel: ObservableObject { @Published var group: BookGroup? } @StateObject private var vm = ViewModel() var body: some View { List(selection: $vm.group) { allView foldersView tagsView }

May 27, 2022 · 1 min · Khoa Pham

How to use native SSL Pinning

Issue #880 From iOS 14, we can do Identity Pinning: How to configure server certificates for your app right from Info.plist <key>NSAppTransportSecurity</key> <dict> <key>NSPinnedDomains</key> <dict> <key>awesome.apps.example.com</key> <dict> <key>NSIncludesSubdomains</key> <true/> <key>NSPinnedCAIdentities</key> <array> <dict> <key>SPKI-SHA256-BASE64</key> <string>12312312312xasdas123asdasdasdasdsad</string> </dict> </array> </dict> </dict> </dict> There are a few drawbacks The subdomains works for multiple part host as well, as long as it is 1 subdomain level Need to duplicate values in each Info.plist Need to duplicate values if the host differs Can’t use User Defined Settings variables in localized Info....

May 23, 2022 · 1 min · Khoa Pham

How to use NSPersistentCloudKitContainer

Issue #879 Setting Up Core Data with CloudKit Enable iCloud Enable CloudKit and Push Notifications Enable Remote Notifications in the Background Creating a Core Data Model for CloudKit Initialize Your CloudKit Schema During Development let container = NSPersistentCloudKitContainer(name: "Earthquakes") // Only initialize the schema when building the app with the // Debug build configuration. #if DEBUG do { // Use the container to initialize the development schema....

May 11, 2022 · 2 min · Khoa Pham

How to allow multiple selection in List in SwiftUI

Issue #878 Note that Explicit id is needed, although Book already conforms to Identifiable selection needs a default value class BookViewModel: ObservableObject { @Published var books: [Book] = [] @Published var selectedBooks: Set<Book> = [] } List(selection: $viewModel.selectedBooks) { ForEach(viewModel.books, id: \.self) { book in BookRow(book: book) } }

April 30, 2022 · 1 min · Khoa Pham

How to use ViewBuilder in SwiftUI

Issue #877 Over the course of making several SwiftUI apps, I’ve discovered quite a few hidden magic of SwiftUI that are quite fun. Here are 6 interesting SwiftUI features in View Builder many don’t know are even possible 🤯 View protocol with enum Struct is not the only way to describe #SwiftUI views. Learn how you can achieve the same thing with just enum Conform primitive type to View protocol You can also conform any value type or primitive type to View protocol...

April 11, 2022 · 2 min · Khoa Pham

How to debounce TextField search in SwiftUI

Issue #876 Make a dedicate DebounceObject to debounce (or throttle). Then we can even observe with onChange on the debouncedText or just use it directly to sort public final class DebounceObject: ObservableObject { @Published var text: String = "" @Published var debouncedText: String = "" private var bag = Set<AnyCancellable>() public init(dueTime: TimeInterval = 0.5) { $text .removeDuplicates() .debounce(for: .seconds(dueTime), scheduler: DispatchQueue.main) .sink(receiveValue: { [weak self] value in self?.debouncedText = value }) ....

March 26, 2022 · 1 min · Khoa Pham

How to create document based macOS app

Issue #875 Read newDocument This method calls openUntitledDocumentAndDisplay(_:). Read openUntitledDocumentAndDisplay The default implementation of this method calls defaultType to determine the type of new document to create, calls makeUntitledDocument(ofType:) to create it, then calls addDocument(_:) to record its opening. Read defaultType The default implementation of this method returns the first Editor type declared by the CFBundleDocumentTypes array in the application’s Info.plist, or returns nil if no Editor type is declared....

March 19, 2022 · 1 min · Khoa Pham

How to add dot indicator to tab bar item in iOS

Issue #874 From iOS 13, use UITabBarAppearance and UITabBarItemAppearance let appearance = UITabBarAppearance() let itemAppearance = UITabBarItemAppearance(style: .stacked) itemAppearance.normal.badgeBackgroundColor = .clear itemAppearance.normal.badgeTextAttributes = [.foregroundColor: UIColor.red] profileViewController.tabBarItem.badgeValue = "●" Read more https://emptytheory.com/2019/12/31/using-uitabbarappearance-for-tab-bar-changes-in-ios-13/

March 15, 2022 · 1 min · Khoa Pham

How to use Multipeer Connectivity

Issue #873 Use assistant let assistant = MCAdvertiserAssistant(serviceType: "my-service, discoveryInfo: nil, session: mcSession) assistant.start() let browser = MCBrowserViewController(serviceType: "my-service", session: mcSession) browser.delegate = self present(browser, animated: true) Manual let advertiser = MCNearbyServiceAdvertiser(peer: localPeerID, discoveryInfo: nil, serviceType: self.serviceType) advertiser.startAdvertisingPeer() let browser = MCNearbyServiceBrowser(peer: localPeerID, serviceType: self.serviceType) browser.startBrowsingForPeers() Enable in Info.plist <key>NSLocalNetworkUsageDescription</key> <string>Enable local network discovery to use Peer Share</string> <key>NSBonjourServices</key> <array> <string>_my-service._tcp</string> <string>_my-service._udp</string> </array> Read more https://www.hackingwithswift.com/example-code/networking/how-to-create-a-peer-to-peer-network-using-the-multipeer-connectivity-framework https://www.toptal.com/ios/collusion-ios-multipeerconnectivity

March 15, 2022 · 1 min · Khoa Pham

How to generate Polygon wallet account in Swift

Issue #871 Use libraries https://github.com/argentlabs/web3.swift https://github.com/bswags/web3keystore import web3 import web3keystore import KeychainAccess private final class KeyStorage: EthereumKeyStorageProtocol { enum Key: String { case privateKey case phrase } private let keychain = Keychain(service: "com.example.myapp") func storePrivateKey(key: Data) throws { try keychain.set(key, key: Key.privateKey.rawValue) } func loadPrivateKey() throws -> Data { if let data = try keychain.getData(Key.privateKey.rawValue) { return data } else { throw EthereumKeyStorageError.failedToLoad } } var phrase: String? { get { try?...

February 24, 2022 · 2 min · Khoa Pham