Swift Discovery

Hi there, I’m Khoa aka onmyway133 đź‘‹

  • 🧑‍💻 I love crafting high quality and useful apps
  • 🔥 I love open source. My GitHub open source has 2.3k 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.7k+ followers with tons of articles and 90k+ monthly views.
  • đź–Ą Follow me for sharings about Swift, SwiftUI, iOS and macOS development

How to use GitHub Copilot for Xcode

Issue #985 During GitHub Universe 2024, GitHub announced that GitHub Copilot code completion in Xcode is available in public preview. The project is open source at CopilotForXcode GitHub Copilot has been available as VS Code extension for a while, but this is first time we have official extension for Xcode. GitHub Copilot for Xcode supports multiple programming languages commonly used in the Apple ecosystem, including Swift and Objective-C Here’s how to use this new extension in Xcode....

November 1, 2024 Â· 2 min Â· 360 words Â· Khoa

How to conditionally render widgets in iOS

Issue #984 The WidgetBundle lets us expose multiple widgets from a single widget extension It uses WidgetBundleBuilder to constructs a widget bundle’s body. In iOS 18, if we include ControlWidget then we need to check iOSApplicationExtension iOS 18. For now in Xcode 16 there’s a bug that prevents existing widgets from appearing in iOS 17. We can leverage WidgetBundleBuilder to conditionally render widgets for each iOS version import SwiftUI import WidgetKit import Widgets @main struct OurAppWidgetBundle: WidgetBundle { var body: some Widget { if #available(iOSApplicationExtension 18....

September 25, 2024 Â· 1 min Â· 123 words Â· Khoa

How to open app with Control Widget on iOS 18

Issue #983 In iOS 18, we can make Control Widget in Widget extension import WidgetKit import SwiftUI @available(iOS 18.0, *) struct BookControlWidget: ControlWidget { var body: some ControlWidgetConfiguration { StaticControlConfiguration(kind: "Book") { ControlWidgetButton(action: BookIntent()) { Label("Book", systemImage: "airplane") } } .displayName("Book") } } import AppIntents @available(iOS 18.0, *) struct BookIntent: AppIntent { static let title: LocalizedStringResource = "Book" static var openAppWhenRun = true static var isDiscoverable = true func perform() async throws -> some IntentResult & OpensIntent { let url = URL(string: "myapp://book")!...

September 25, 2024 Â· 2 min Â· 389 words Â· Khoa

How to use NSFetchedResultsController memory wise in Core Data

Issue #982 If you’re using NSFetchedResultsController in Core Data, it might take up a lot of memory, especially when working with large datasets. To keep your app running smoothly, it’s important to manage memory efficiently Use Fetch Limits and Batch Fetching If your dataset is large, limit the number of objects fetched at a time. You can achieve this by setting a fetchBatchSize and a fetchLimit on your NSFetchRequest. fetchBatchSize: This controls how many objects Core Data will fetch in memory at a time....

September 24, 2024 Â· 3 min Â· 547 words Â· Khoa

How to use NSDragOperation

Issue #981 NSDragOperation represent which operations the dragging source can perform on dragging items. There are several types of drag operations, and each one has a different purpose and visual cue. Copy Operation .copy What It Does: The item you’re dragging will be copied. This means the original stays in place, and a duplicate is created in the new location. When to Use: Use this when you want to create a copy of a file or item, without removing it from the original spot....

September 23, 2024 Â· 3 min Â· 609 words Â· Khoa

How to make NSCollectionView with diffable data source and SwiftUI

Issue #980 NSCollectionView, available since macOS 10.5+, is a good choice to present a list of content. Let’s make a SwiftUI wrapper for NSCollectionView with diffable data source and compositional layout Use NSViewControllerRepresentable First, let’s create a SwiftUI view that will represent the macOS view controller. We’ll use the NSViewControllerRepresentable protocol to bridge SwiftUI and AppKit. import SwiftUI import AppKit struct CollectionView: NSViewControllerRepresentable { func makeNSViewController(context: Context) -> CollectionViewController { return CollectionViewController() } func updateNSViewController(_ nsViewController: CollectionViewController, context: Context) { nsViewController....

August 15, 2024 Â· 3 min Â· 627 words Â· Khoa

How to use React Query useQuery with debounce

Issue #979 When dealing with user input, such as in an autocomplete component, it’s common to implement debouncing to reduce the number of API calls and improve the user experience. React Query’s useQuery hook makes it easy to manage the state and lifecycle of API requests, and by combining it with debouncing, you can create a powerful and efficient data fetching solution. In this tutorial, we’ll walk through an example of using useQuery with debouncing to fetch country details based on user input in an autocomplete component....

August 14, 2024 Â· 4 min Â· 727 words Â· Khoa

How to handle tap gesture in SwiftUI Charts

Issue #978 From iOS 17, SwiftUI Charts has chartGesture, together with SpatialTapGesture we can check tap location and convert that to Charts value Chart {} .chartGesture { chart in SpatialTapGesture() .onEnded { value in let result = chart.value(at: value.location, as: (Int, Double).self) if let index = result?.0, let log = logs[safe: index] { print(log) } } }

August 7, 2024 Â· 1 min Â· 57 words Â· Khoa

How to sign in with Apple and Firebase and Supabase

Issue #977 Show ASAuthorizationController with a simple nonce. Once we have the idToken, create an OAuthProvider.appleCredential and pass to Firebase Auth final class AppleLoginService: NSObject { static let shared = AppleLoginService() private var nonce: String? func show() { let nonce = generateNonce() self.nonce = nonce let provider = ASAuthorizationAppleIDProvider() let request = provider.createRequest() request.requestedScopes = [.fullName, .email] request.nonce = nonce?.sha256 let vc = ASAuthorizationController(authorizationRequests: [request]) vc.delegate = self vc.presentationContextProvider = self vc....

August 3, 2024 Â· 1 min Â· 207 words Â· Khoa

How to serve a local development environment over https using pnpm and webpack

Issue #976 When developing locally, especially when interacting with third-party services that have CORS restrictions, serving your development environment over a custom domain with HTTPS can be crucial. Let’s walk through the steps to achieve this with pnpm and webpack. In our example, the domain we want to use is local.onmyway133.com Map Localhost to Your Domain Name First, we need to map our custom domain to localhost. Open your hosts file to add this mapping....

July 29, 2024 Â· 2 min Â· 316 words Â· Khoa

How to use React Custom Hooks as the View Model pattern

Issue #975 When building a React application, separating the logic and state management from the UI can make your code easier to manage, test, and reuse. This is where the view model pattern comes in handy. By using a custom hook as a view model, you can keep your components focused on displaying the UI while the hook handles all the complex logic and state. Let’s break down how to do this with a simple example....

July 16, 2024 Â· 5 min Â· 967 words Â· Khoa

How to use memory in lowdb

Issue #974 In lowdb 7, we can use MemorySync https://github.com/typicode/lowdb/blob/main/src/examples/in-memory.ts import { LowSync, MemorySync, SyncAdapter } from '../index.js' import { JSONFileSync } from '../node.js' declare global { // eslint-disable-next-line @typescript-eslint/no-namespace namespace NodeJS { interface ProcessEnv { NODE_ENV: 'test' | 'dev' | 'prod' } } } type Data = Record<string, unknown> const defaultData: Data = {} const adapter: SyncAdapter<Data> = process.env.NODE_ENV === 'test' ? new MemorySync<Data>() : new JSONFileSync<Data>('db.json') const db = new LowSync<Data>(adapter, defaultData) db....

July 11, 2024 Â· 1 min Â· 75 words Â· Khoa

How to detect Barcode and QR code

Issue #973 Before iOS 11, we used to use CIDetector and CIDetectorTypeQRCode to detect QR code CIDetector An image processor that identifies notable features, such as faces and barcodes, in a still image or video. CIDetectorTypeQRCode A detector that searches for Quick Response codes (a type of 2D barcode) in a still image or video, returning CIQRCodeFeature objects that provide information about detected barcodes. func readQrOnly(image: CGImage) async -> String? { let ciImage = CIImage(cgImage: image) let detector = CIDetector( ofType: CIDetectorTypeQRCode, context: nil, options: [ CIDetectorAccuracy: CIDetectorAccuracyHigh ] ) guard let detector = detector else { return nil } let features = detector ....

June 6, 2024 Â· 2 min Â· 271 words Â· Khoa

How to make swifty UserDefaults

Issue #972 We want to have a swifty UserDefaults API that works with subscript and in a type safe manner. extension Defaults.Keys { static let string = Defaults.Key("string", default: "0") } XCTAssertEqual(defaults[.string], "0") defaults[.string] = "1" XCTAssertEqual(defaults[.string], "1") UserDefaults plist compatibility Define Compatible protocol that allows value to be plist compatible The value parameter can be only property list objects: NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. For NSArray and NSDictionary objects, their contents must be property list objects....

May 28, 2024 Â· 3 min Â· 504 words Â· Khoa

How to use act vs waitFor using React Testing Library

Issue #971 When testing React components, dealing with tasks that happen at different times is super important to make sure your tests give reliable results. React Testing Library gives you two important tools for dealing with these situations: act and waitFor. Even though they both help with handling actions that don’t happen right away, they’re used in different situations. act: Ensuring Synchronous Updates The act function wraps parts of your code that cause updates linked to changes in state, effects, or other delayed actions....

March 13, 2024 Â· 4 min Â· 672 words Â· Khoa

How to use OSLog and OSLogStore in Swift

Issue #970 We can use Logger to log and OSLogStore to retrieve logs import OSLog import ReuseAcross final class LogService { static let shared = LogService() let logger = Logger( subsystem: "com.example.myapp", category: "Log" ) func export() -> [String] { do { let store = try OSLogStore(scope: .currentProcessIdentifier) let position = store.position(timeIntervalSinceLatestBoot: 1) let logs = try store .getEntries(at: position) .compactMap { $0 as? OSLogEntryLog } .filter { $0.subsystem == Bundle....

February 8, 2024 Â· 1 min Â· 104 words Â· Khoa

How to include custom error payload in hapi Boom

Issue #969 Hapi.js, commonly referred to as Hapi, is an open-source, back-end web application framework for building and deploying web applications and APIs in Node.js In Hapi.js, you can use the Boom module to create and return error responses in a standardized way. Boom provides a set of functions to generate HTTP error objects with consistent properties, making it easier to handle errors and communicate them to clients Read Error transformation...

January 31, 2024 Â· 1 min Â· 114 words Â· Khoa

How to read image paste from clipboard in React

Issue #968 Are you looking to grab images directly from your clipboard with a button click on your web page? The Async Clipboard API makes this quite easy and efficient. Let’s break it down into simpler steps: Requesting Permission The first time you try to read something from the clipboard using this method, your browser will ask for permission. This is a security feature to ensure that websites don’t access your clipboard without your consent....

January 30, 2024 Â· 2 min Â· 261 words Â· Khoa

How to create user gitignore

Issue #967 Git is a helpful tool for managing code and projects, but sometimes you want to ignore certain files or folders only on your computer without affecting everyone else. That’s where the .user_gitignore file comes in. It allows you to create personalized ignore rules for your local Git setup without changing the global project settings. gitignore Before we get into .user_gitignore, let’s quickly go over what a regular .gitignore file does....

January 30, 2024 Â· 2 min Â· 280 words Â· Khoa

How to use useCallback in React

Issue #966 The use of useCallback and useMemo in React hooks is an adaptation to address certain limitations inherent in the functional programming style adopted by React. In JavaScript, every entity, whether it’s a function, variable, or any other type, gets created in memory when the code within a function’s scope is executed. This poses a challenge for React’s rendering logic, which determines the need for re-rendering based on changes in input props and context....

January 26, 2024 Â· 2 min Â· 398 words Â· Khoa