onmyway133

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

How to deal with actor reentrancy in Swift

Issue #912 Perform check before and after suspension point actor Worker { var isDoing = false var toBeDone = Set<String>() func work(string: String) async { if isDoing { toBeDone.insert(string) return } isDoing = true await performHeavyWork(string: string) isDoing = false if let first = toBeDone.popFirst() { await work(string: first) } } private func performHeavyWork(string: String) async { try? await Task.sleep(nanoseconds: 5_000_000_000) print(string) } } func main() { let worker = Worker() Array(0 ....

May 5, 2023 ยท 1 min ยท Khoa Pham

How to run parallel Task with Swift concurrency

Issue #911 Make an parallelTask function that wraps TaskGroup public func parallelTask(@ParallelTaskBuilder builder: () -> [ParallelTaskBuilder.Work]) async { await withTaskGroup(of: Void.self) { group in for work in builder() { group.addTask { await work.value } } } } @resultBuilder public struct ParallelTaskBuilder { public typealias Work = Task<Void, Never> public static func buildExpression(_ expression: Work?) -> [Work] { if let expression = expression { return [expression] } return [] } public static func buildExpression(_ expression: Work) -> [Work] { [expression] } public static func buildExpression(_ expression: [Work]) -> [Work] { expression } public static func buildBlock(_ components: Work....

April 27, 2023 ยท 1 min ยท Khoa Pham

How to use Range and NSRange in Swift

Issue #910 Use one-sided range operator let string = "Hello world" string[string.startIndex...] // Hello world string[..<string.endIndex] // Hello world Substring let string = "Hello world" let range = string.startIndex ..< string.index(string.startIndex, offsetBy: 5) string[range] // Hello Convert to and from NSRange let string = "Hello world" let range = string.startIndex... let nsRange = NSRange(range, in: string) let regex = NSRegularExpression(pattern: pattern) let matches = regex.matches(in: string, range: nsRange) for match in matches { let range = Range(match....

March 12, 2023 ยท 1 min ยท Khoa Pham

How to use Tailwind

Issue #909 Resources https://www.tailwindawesome.com/ https://daisyui.com/ https://www.hyperui.dev/ https://tailwind-elements.com/ https://tailwindtemplates.co/ Paid https://flowbite.com/ https://tailwindui.com/ https://tailgrids.com/

February 19, 2023 ยท 1 min ยท Khoa Pham

How to handle status bar with custom overlay UIWindow

Issue #908 When we add another UIWindow, then its rootViewController will decide the style of the status bar, not the rootViewController of the keyWindow anymore childForStatusBarStyle The usual way to fix this is to defer the decision to the correct rootViewController, like in our HUDViewController class HUDViewController: UIViewController { override var childForStatusBarStyle: UIViewController? { let windows = view.window?.windowScene?.windows ?? [] for window in windows where window != self.view.window { return window....

November 22, 2022 ยท 2 min ยท Khoa Pham

How to use SwiftUI Charts

Issue #907 Read more https://swdevnotes.com/swift/2022/customise-a-line-chart-with-swiftui-charts-in-ios-16/ https://github.com/jordibruin/Swift-Charts-Examples

October 30, 2022 ยท 1 min ยท Khoa Pham

How to make SwiftUI widget in iOS

Issue #906 Read more https://developer.apple.com/documentation/widgetkit/making-a-configurable-widget What is the purpose of getSnapshot method from WidgetKit

October 30, 2022 ยท 1 min ยท Khoa Pham

How to use actor in Swift concurrency

Issue #905 Protect mutable state with Swift actors Actor reentrancy Imagine we have two different concurrent tasks trying to fetch the same image at the same time. The first sees that there is no cache entry, proceeds to start downloading the image from the server, and then gets suspended because the download will take a while. While the first task is downloading the image, a new image might be deployed to the server under the same URL....

October 5, 2022 ยท 4 min ยท Khoa Pham

How Task use thread in Swift concurrency

Issue #904 Consider this code where we have an ObservableObject with fetch1 and async fetch2, and a fetch inside ContentView Here the observation in Xcode 14 ViewModel.fetch1: run on main thread ViewModel.fetch2: run on cooperative thread pool ContentView.fetch: run on main thread import SwiftUI import CoreData import Combine class ViewModel: ObservableObject { @Published var string = "" func fetch1() { let url = URL(string: "https://google.com")! let data = try!...

October 4, 2022 ยท 4 min ยท Khoa Pham

How to show animated gif NSImage on Mac

Issue #903 let image = NSImage(contentsOf: url) let imageView = NSImageView(image: image) image.animates = true

September 25, 2022 ยท 1 min ยท Khoa Pham

How to handle shortcut intents in iOS

Issue #902 iOS 13 Intents Extension & Intents UI Extension Donate Shortcuts at the Right Time Siri can predict shortcuts to actions that a user may want to perform using your app, and suggest those shortcuts to the user in places such as Spotlight search, Lock Screen, and the Siri watch face. Siri learns about the shortcuts available for your app through donations that your app makes to Siri....

September 14, 2022 ยท 3 min ยท Khoa Pham

How to use Universal Links in iOS

Issue #901 Apple app site association https://com.example/.well-known/apple-app-site-association Supporting Associated Domains New format from iOS 13 Can also remove components section if we match all URLs { "applinks": { "details": [ { "appIDs": [ "ABCDE12345.com.example.app", "ABCDE12345.com.example.app2" ], "components": [ { "/": "/*", "comment": "Match all URLs" } } ] }, } Application Identifier Prefix appID is in form <Application Identifier Prefix>.<Bundle Identifier> For Application Identifier Prefix , you can find it in https://developer....

August 9, 2022 ยท 3 min ยท Khoa Pham

How to find previous frontmost application in macOS

Issue #900 Listen to didActivateApplicationNotification and check that it is not our app NSWorkspace.shared.notificationCenter .publisher(for: NSWorkspace.didActivateApplicationNotification) .sink(receiveValue: { [weak self] note in guard let app = note.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication, app.bundleIdentifier != Bundle.main.bundleIdentifier else { return } self?.frontMostApp = app }) .store(in: &bag)

August 2, 2022 ยท 1 min ยท Khoa Pham

How to show view below title bar for macOS in SwiftUi

Issue #899 Use NSTitlebarAccessoryViewController var titleBarAccessoryVC: NSTitlebarAccessoryViewController { let vc = NSTitlebarAccessoryViewController() let view = HStack { Spacer() Button { } label: { Text("Save") } .buttonStyle(.borderedProminent) .controlSize(.large) } .padding(.horizontal) vc.view = NSHostingView(rootView: view) return vc } let window: NSWindow = ... window.addTitlebarAccessoryViewController(titleBarAccessoryVC)

July 30, 2022 ยท 1 min ยท Khoa Pham

How to drag using DragGesture in SwiftUI

Issue #898 Change element position using either offset or position, and use DragGesture Use GestureState to store the updating startDragLocation to keep the start location when drag begins, so we can add translation struct MoveModifier: ViewModifier { @Binding var position: CGPoint @GestureState private var startLocation: CGPoint? func body(content: Content) -> some View { content .gesture(gesture) } private var gesture: some Gesture { DragGesture() .onChanged { value in var position = startLocation ?...

July 28, 2022 ยท 1 min ยท Khoa Pham

How to handle slow large dataset Picker when dragging in SwiftUI

Issue #897 During continuous events like dragging or TextField typing, and we have a Picker onscreen with large data set, it will slow down main thread. One option is to explicitly conform that view to Equatable struct FontPicker: View, Equatable { @Binding var fontFamily: String var body: some View { Picker("", selection: $fontFamily) { ForEach(NSFontManager.shared.availableFontFamilies, id: \.self) { family in Text(family) .tag(family) } } } static func == (l: FontPicker, r: FontPicker) -> Bool { l....

July 28, 2022 ยท 1 min ยท Khoa Pham

How to pass FocusState binding in SwiftUI

Issue #896 Use underscore _focus we get access to underlying FocusState object, but underscore _ is private to a View hence canโ€™t be used in extension If we want to pass FocusState to another View or in extension, we can pass its Binding enum FocusElement: Hashable { case name case email } struct ParentView: View { @FocusState var focus: FocusElement? var body: some View { ChildView1(focus: _focus) ChildView2(focus: $focus) } } struct ChildView1: View { @FocusState var focus: FocusElement?...

July 28, 2022 ยท 1 min ยท Khoa Pham

How to move reversed List in SwiftUI

Issue #895 Apply .move on reversed array List(selection: $viewModel.selectedBook) { ForEach(viewModel.books.reversed()) { book in BookCell(book: book) } .onMove { source, dest in var reversed = Array(viewModel.books.reversed()) reversed.move(fromOffsets: source, toOffset: dest) viewModel.books = reversed.reversed() } }

July 25, 2022 ยท 1 min ยท Khoa Pham

How to set popoverPresentationController sourceView in SwiftUI

Issue #894 Use a UIView as source view and set it in background class ViewModel { lazy var sourceView = UIView() } struct SourceView: UIViewRepresentable { let viewModel: ViewModel func makeUIView(context: Context) -> UIView { viewModel.sourceView } func updateUIView(_ uiView: UIView, context: Context) {} } Button(action: { onShowAlert(viewModel.sourceView) }) { Image(systemName: "bookmark") } .background(SourceView(viewModel: viewModel)) let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) alertController.popoverPresentationController?.sourceView = viewModel.sourceView

July 8, 2022 ยท 1 min ยท Khoa Pham

Essential WWDC sample codes

Issue #892 WWDC21 Building a Great Mac App with SwiftUI Add Rich Graphics to Your SwiftUI App

June 10, 2022 ยท 1 min ยท Khoa Pham