Khoa Pham

Khoa Pham

from Oslo 935 posts
I’m open source contributor, writer, speaker and product maker.

How to observe optional ObservableObject in SwiftUI

Issue #988

When working with Core Data, there are times we have optional NSManagedObject to pass around. These objects conform to ObservableObject, and in SwiftUI we can’t @ObservedObject on optional ObservableObject

One way we can workaround …

How to clear background for TextField inside list in macOS

Issue #986

When using TextField in SwiftUI List on Mac, it has unwanted background color when focused. We can turn it off using introspection or a custom TextField wrapper

TextField("Search", text: $searchText)
    .introspect(.textField, on: …

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

image

GitHub Copilot has been available as VS Code extension for a while, …

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. …

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 …

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 …

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 …

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 …

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 …

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 …

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() …

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 …

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 …

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 …

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 …

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], …

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 …

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", …

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 …

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 …

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 …

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 …

How to extend class in Javascript

Issue #965

In JavaScript, classes are a template for creating objects. They encapsulate data with code to work on that data. ES6 introduced a class syntax to the JavaScript language to create classes in a way that’s similar to other …

How to use export all and export default in Javascript

Issue #964

In JavaScript, particularly in modules used in frameworks like React, export statements are used to expose code—such as functions, classes, or constants—from one module so that they can be imported and reused in other modules.

export *

The …

How to escape characters in json and regex with Swift string

Issue #963

In the world of Swift programming, we often come across situations where we need to work with string literals that contain special characters. These characters can include new lines, tabs, backslashes, and quotes — all of which need to be …

How to use nextjs Image

Issue #962

Fill parent div

A boolean that causes the image to fill the parent element, which is useful when the width and height are unknown.

The parent element must assign position: “relative”, position: “fixed”, or position: …

How to check NSTextField is first responder

Issue #961

NSTextField uses NSFieldEditor under the hood, you can check currentEditor if it is the firstResponder

extension NSTextField {
    var isFirstResponder: Bool {
        currentEditor() == window?.firstResponder
    }
}

Building an iOS camera calculator with Core ML’s Vision and Tesseract OCR

Issue #960

Also written on Fritz


Math might be scary, but it’s an essential part of everyday life. Wouldn’t it be cool if we could build an app, point our phone’s camera at an expression, and let the app compute the result? Whenever I’ve needed to …

How to decode dynamic JSON key with JSONDecoder

Issue #959

Decoding JSON in Swift is most of the time very straightforward with help of Codable protocol and JSONDecoder.

Sometimes the json contains dynamic key, like

{
    "shipmunk": {
        "name": "Shipmunk", …

How to bundle js for use in JavaScriptCore in Swift

Issue #958

We can use any bundler, like Parcel, Webpack or Vite. Here I use Webpack 5

Install Webpack and Babel

npm install @babel/polyfill webpack webpack-cli --save-dev

@babel/polyfill is a package provided by Babel, a popular JavaScript compiler. …

How to handle log in JSContext with JavascriptCore

Issue #957

Define console object and set log function to point to our Swift function

import JavaScriptCore

extension JSContext {
    func injectConsoleLog() {
        
        evaluateScript(
        """
            var console = {}; …

How to make attributed TextView for macOS and iOS with SwiftUI

Issue #956

macOS

import Foundation
import SwiftUI
import AppKit

struct AttributedTextView: NSViewRepresentable {
    @Binding var attributedText: NSAttributedString
    var isEditable: Bool = true
    
    final class Coordinator: NSObject { …

Apple Developer Learning resources

Issue #955

Besides WWDC videos & documentation, Apple also has interactive tutorials and books. Below are some of my favorites learning resources

Tutorials

How to show anchor bottom view in SwiftUI

Issue #954

From iOS 15, there’s a handy safeAreaInset that allows us to place additional content extending the safe area.

Shows the specified content beside the modified view.

safeAreaInset allows us to customize which edge and alignment we …

How to debounce text input in React

Issue #953

Use debounce from lodash and useCallback to memoize debounce function

import React, { useCallback } from "react"
import debounce from "lodash/debounce"

const SearchField = (props: Props) => {
    const callback = …

How to remove duplicates in Javascript array while keeping latest occurrence?

Issue #952

Use ES6 Map

The Map object holds key-value pairs and remembers the original insertion order of the keys. Any value (both objects and primitive values) may be used as either a key or a value.

type Deal = {
    name: string,
    link: …

How to drag multiple files in SwiftUI on Mac

Issue #951

Create a custom NSView that handles mouseDragged to beginDraggingSession

struct DraggingSourceViewWrapper: NSViewRepresentable {
    let fileUrls: [URL]
    let onEnd: () -> Void
    
    func makeNSView(context: Context) -> …

How to dynamically build tailwind class names

Issue #950

Inspired by shadcn

Combine

  • tailwind-merge: Utility function to efficiently merge Tailwind CSS classes in JS without style conflicts.
  • clsx: constructing className strings conditionally.
import { clsx, type ClassValue } from "clsx" …

How to store Codable in AppStorage

Issue #949

AppStorage and SceneStorage accepts RawRepresentable where value is Int or String.

Creates a property that can read and write to a string user default, transforming that to RawRepresentable data type.

init(wrappedValue:_:store:)

init( …

How to update widget for iOS 17

Issue #948

iOS 17 has a new Stand by mode so SwiftUI introduces containerBackground for the system to decide when to draw background. It also automatically applies margin to widget so we may need to disable that

To update existing widgets, we can …

How to get Supabase user token from server API

Issue #947

Sometimes Row Level Security is not enough and we want to do all logic server side, then we need a way for the server to get hold onto current user token.

Send JWT token in Authorization header

From client, we can get session from supabase …

How to mirror auth.users on Supabase

Issue #946

For security purposes, the auth schema is not exposed on the auto-generated API. We can make a profiles table in public namespace and mirror data from auth.users when user signs up.

I need id, username and raw_user_metadata so I will …

How to force localized language with SwiftGen

Issue #945

The default SwiftGen generate generated strings L10n file like this

extension L10n {
  private static func tr(_ table: String, _ key: String, _ args: CVarArg..., fallback value: String) -> String {
    let format = BundleToken.bundle. …

How to make tag flow layout using Layout protocol in SwiftUI

Issue #944

SwiftUI in iOS 16 supports Layout protocol to arrange subviews

We need to implement 2 methods

How to use hover annotation in Swift Charts

Issue #943

In this tutorial, we’ll learn how to use Swift Charts to visualize ranking data.

Screenshot 2023-08-18 at 11 48 28

We use default AxisMarks and AxisMarks to let Swift Charts interpolate x and y grid lines. For y axis, I want to have finer grain control over the …

How to use Supabase auth with React Context

Issue #942

Expose supabase with createClient

useSupabase.ts

import { createClient } from '@supabase/supabase-js'

const supabaseUrl = process.env.SUPABASE_URL
const supabaseAnonKey = process.env.SUPABASE_ANON_KEY

export const supabase = …

How to create React app with Parcel

Issue #941

In this tutorial we will be creating a React app with Parcel 2 with Typescript and Tailwind

Install the following dependencies. Parcel supports TypeScript out of the box without any additional configuration.

npm install --save-dev parcel …

How to make Chrome extension with Nextjs 13

Issue #940

We can develop Nextjs 13 apps and export it to a Chrome extension.

Start by init the project

npx create-next-app@latest

Here is the project structure with app router and not using src directory. I put an extension to the root of the …

How to scale image fill without affect layout in SwiftUI

Issue #939

Instead of letting the Image decide the size, we can put it as background or overlay. I use clipped and contentShape to avoid the fill image obscuring touch event

Color.clear
    .frame(height: 100)
    .overlay {
        AsyncImage(url: …

How to move Core Data database to AppGroup folder

Issue #938

To let app and extension to talk to the same database, we need to use AppGroup. Here is how to use replacePersistentStore

Replaces one persistent store with another

actor DatabaseMigrator {
    @AppStorage( …

How to read write files to iCloud Drive

Issue #937

First, you need to enable iCloud Documents capability. Go to target settings -> Signing & Capabilities -> iCloud ` Screenshot 2023-07-28 at 16 09 14

Then inside your Info.plist, add this with your iCloud identifier and app name …

How to make reusable Button component in React

Issue #936

From https://github.com/antonioerdeljac/next13-spotify

import { forwardRef } from "react";
import { twMerge } from "tailwind-merge";

export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement …

How to use keychain in Swift

Issue #934

There are a few keychain wrappers around but for simple needs, you can write it yourself

Here is a basic implementation. I use actor to go with async/await, and a struct KeychainError to contain status code in case we want to deal with …

How to handle route case sensitivity in Nextjs

Issue #933

By default, Nextjs route is case sensitive, so localhost:3000/About and localhost:3000/about are different routes.

To make uppercase routes become lowercase routes, we can add a middleware.tsx file to the src so it is same level as pages …

How to make share and action extension in iOS

Issue #932

Add Share extension and Action extension respectively in Xcode. We can use the same code to both extension

Screenshot 2023-07-12 at 21 11 41

SwiftUI

I usually make a ShareView in SwiftUI with ShareViewModel to control the logic

struct ShareView: View {
    @ …

AppStore screenshots size checklist

Issue #931

AppStore screenshots

Screenshot specifications

iPhone 6.7"

Portrait 1290 x 2796

iPhone 6.5"

Portrait 1242 x 2688

In-App Purchase screenshots

In-app purchase information

iOS 640 x 920 tvO 1920 x1080 pixels macOS 1280 x 800 pixels

How to use AppIntents in iOS 16

Issue #930

AppIntents

Declare AppShortcutsProvider, note that appShortcuts uses @AppShortcutsBuilder syntax

import AppIntents

struct OurShortcutsProvider: AppShortcutsProvider {
    static var shortcutTileColor: ShortcutTileColor = .lightBlue …

How to press and hold button in SwiftUI

Issue #929

We can use ButtonStyleConfiguration to detect isPressed state

struct RecordButton: View {
    var body: some View {
        Button {
        
        } label: {
            Image(systemSymbol: .micFill)
        }
        .buttonStyle( …

How to copy text to the clipboard in Swift

Issue #928

For iOS, use string

Setting this property replaces all current items in the pasteboard with the new item. If the first item has no value of the indicated type, nil is returned.

let pasteboard = UIPasteboard.general
pasteboard.string = …

How to add launch screen in SwiftUI project

Issue #927

For a plain SwiftUI project, Xcode will generate a Info.plist file once you start to edit the Info tab in target settings.

There is a Launch screen (UILaunchScreen) key by default. It has a UILaunchScreen which we don’t need to so we …

How to create UserDefaults property wrapper in Swift

Issue #926

Like AppStorage, we can make a custom UserDefaults property wrapper that conforms to DynamicProperty

@propertyWrapper
public struct UserDefault<Value>: DynamicProperty {
    @State private var value: Value

    let key: String …

How to encrypt using CryptoKit in Swift

Issue #925

Use AES.GCM method with 128 bits key

import CryptoKit

public extension Optional {
    func tryUnwrap() throws -> Wrapped {
        if let value = self {
            return value
        } else {
            throw NSError(domain: …

How to use NavigationSplitView and NavigationStack in SwiftUI

Issue #924

Note

  • Navigation state needs to be in the container of NavigationSplitView for changes to propagate
  • Need to use WindowGroup for navigation bar to work

NavigationSplitView

the navigation split view coordinates with the List in its first …

How to style NavigationLink in macOS

Issue #923

NavigationLink on Mac applies the default button style. We can style it using ButtonStyle, here to use plain style we can just

NavigationLink(value: DetailRoute.books) {
    BooksView()
}
.buttonStyle(.plain)

SwiftUI EnvironmentValues

Issue #922

EnvironmentValues Views in SwiftUI can react to configuration information that they read from the environment using an Environment property wrapper

Updated for iOS 17

SwiftUI Environment values

How to make TextField Stepper in SwiftUI

Issue #921

Use HStack with TextField and a little extension

extension Binding where Value == Int {
    var toString: Binding<String> {
        Binding<String>(
            get: {
                "\(wrappedValue)"
            }, …

How to clear TextEditor background in SwiftUI

Issue #920

For iOS 16 and macOS 13.0

TextEditor(text: $text)
    .scrollContentBackground(.hidden)

For below, use [SwiftUI-Introspect](https://github.com/siteline/SwiftUI-Introspect)

TextEditor(text: $text)
    .instrospectTextView {
        $0. …

Learning Metal for SwiftUI

Issue #919

WWDC23 introduces lots of new additions to SwiftUI, notably Metal shader support with these modifiers

  • colorEffect: Returns a new view that applies shader to self as a filter effect on the color of each pixel.
  • layerEffect: Returns a new …

WWDC23 SwiftUI Q&A

Issue #918

Interesting SwiftUI Q&A during WWDC23

Observable vs ObservableObject

Q: With the new SwiftUI @Observable macro, are there any cases where ObservableObject would still be a better alternative?

A: Use ObservableObject when you need to …

WWDC21 SwiftUI Q&A

Issue #917

Interesting SwiftUI Q&A during WWDC21

@StateObject or ObservedObject?

Q: Let’s say I have a purely SwiftUI flow. I have a ListView with a @StateObject var listFetcher, that makes requests for a list of items. Tapping on an item in the …

What's new in SwiftUI iOS 17 at WWDC23

Issue #916

WWDC23 brings new additions to SwiftUI

Screenshot 2023-06-07 at 22 02 36

Scrolling

The scroll transition modifier is very similar to the visual effect modifier Curt used earlier for the welcome screen. It lets you apply effects to items in your scroll view.

I’m …

How to render markdown view with React

Issue #914

Use react-markdown to parse markdown content, react-syntax-highlighter to highlight code, and rehype-raw to parse raw html

import ReactMarkdown from "react-markdown"
import { Prism as SyntaxHighlighter } from …

How to create Quick look thumbnail for files

Issue #913

Use QuickLookThumbnailing framework

import AppKit
import QuickLookThumbnailing

actor QuicklookService {
    static let shared = QuicklookService()
    
    private let generator = QLThumbnailGenerator.shared
    
    func image( …

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) …

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() { …

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 ..< …

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 …

How to use actor in Swift concurrency

Issue #905

Protect mutable state with Swift actors

Actor reentrancy

abc

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 …

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 …

How to show animated gif NSImage on Mac

Issue #903

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

How to handle shortcut intents in iOS

Issue #902

iOS 13 Intents Extension & Intents UI Extension

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 …

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": { …

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 …

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: { …

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 …

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 { …

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 …

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. …

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 { …

My favorite WWDC videos

Issue #891

Below are my favorite WWDC videos. My focus is to use SwiftUI to make useful apps with great UX. I don’t pay much attention to new frameworks as they come and go, but the underlying reasons and design principles are worth …

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 …

WWDC22 SwiftUI Q&A

Issue #890

Interesting SwiftUI Q&A during 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 …

What's new in SwiftUI iOS 16 at WWDC22

Issue #889

asda

What’s new in SwiftUI

New EnvironmentValues

abc

TextField inside Alert

abc

List uses UICollectionView

See gist https://gist.github.com/onmyway133/fc08111964984ef544a176a6e9806c18

abc

ButtonStyle composition

Screenshot 2022-06-09 at 10 25 30
Section("Hashtags") { …

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 …

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 …

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 …

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 …

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 …

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> …

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 …

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 …

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 …

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

import Combine

public final class DebounceObject: ObservableObject {
    @Published var …

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 …

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. …

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) …

How to generate Polygon wallet account in Swift

Issue #871

Use libraries

import web3
import web3keystore
import KeychainAccess

private final class KeyStorage: EthereumKeyStorageProtocol {
    enum Key: String { …

How to make simple Plist builder with resultBuilder in Swift

Issue #869

We can use PropertyListEncoder from Swift 4

let encoder = PropertyListEncoder()
encoder.outputFormat = .xml
let data = try encoder.encode(model)

Or we can manually do with resultBuilder style

Declare @resultBuilder for PlistBuilder that …

How to generate JWT token for App Store Connect API in Swift

Issue #868

Use JWTKit and code from AppStoreConnect library

import JWTKit

public struct Credential {
    let issuerId: String
    let privateKeyId: String
    let privateKey: String

    public init(
        issuerId: String,
        privateKeyId: …

How to send SPL token in Swift

Issue #867

Using https://github.com/ajamaica/Solana.Swift and the sendSPLToken method. Note that the from is the token account address and amount can have decimals

solana.action.sendSPLTokens(
    mintAddress: MINT_ADDRESS,
    from: …

How to calculate Solana transaction fee

Issue #866

A simple way is to use a fixed fee of 0.000005

For example from https://solscan.io/tx/5DkApvwTYuMqCiA94MhUVKJoLn8MGma9gAWXhreRJKqAs395P5CqEK3R84m3MWjcTKMem53XcLwYErGkaJAbQC2h?cluster=testnet

And call some exchange API, like Coingecko …

How to parse large JSON Dictionary in Swift

Issue #865

We can define some typealias and build extensions on JSONDictionary to easily extract values

typealias JSONDictionary = [String: Any]
typealias JSONArray = [JSONDictionary]

extension JSONDictionary {
    func dict(_ key: String) -> …

How to make simple async URLSession in Swift

Issue #864

Since async URLSession.shared.data is available in iOS 15+, we can build a custom one with withCheckedThrowingContinuation

import UIKit

enum HTTPMethod: String {
    case get = "GET"
    case post = "POST"
}

extension …

How to check SPL token balance on Solana

Issue #863

We will check USDC token balance on Solana testnet.

Firstly, we will use https://usdcfaucet.com/ to airdrop some USDC tokens into our wallet. Secondly, we check USDC token mint address on testnet cluster using Solana Explorer …

How to use subscript in Swift

Issue #861

Make it easy to access common cases, for example UserDefaults

extension UserDefaults {
    enum Key: String {
        case hasBackup
    }

    subscript(key: Key) -> Bool {
        get {
            bool(forKey: key.rawValue)
        } …

How to encode JSON dictionary into JSONEncoder

Issue #860

JSONEncoder deals with type-safe, so we need to declare an enum JSONValue for all possible types. We also need a custom initializer to init JSONValue from a JSON Dictionary

import Foundation

enum JSONValue {
    case string(String) …

How to parse Apple Pay PKPayment in Swift

Issue #859

To parse PKPayment and used with Wyre CreateAppleOrder API, we can declare some Encodable structs

import PassKit
import Foundation

struct PaymentObject: Encodable {
    var billingContact: Contact?
    var shippingContact: Contact? …

How to pop multiple level with NavigationView and NavigationLink in SwiftUI

Issue #858

Use isActive and isDetailLink(false)

Use Introspect

.introspectNavigationController { nav in
    self.nav = nav
}

Read more

How to generate Solana wallet acount in Swift

Issue #857

Use Solana.swift and Mnemonic seed phrase. For production, change endpoint to mainnet

import UIKit
import Solana
import KeychainAccess

enum SolanaError: Swift.Error {
    case accountFailed
    case unauthorized
}

final class …

How to use Apple Pay in iOS

Issue #856

Use PKPaymentRequest and PKPaymentAuthorizationViewController

@MainActor
final class WalletViewModel: NSObject, ObservableObject {
    var canMakePayments: Bool {
        PKPaymentAuthorizationViewController.canMakePayments()
    } …

How to show QR code in SwiftUI

Issue #855

Use CoreImage to generate QR image

import SwiftUI
import CoreImage.CIFilterBuiltins

struct QRView: View {
    let qrCode: String
    @State private var image: UIImage?

    var body: some View {
        ZStack {
            if let image = …

How to not encode with Enum key in Swift

Issue #854

If you use enum case as key in Dictionary, JSONEncoder will encode it as Array. For example

enum Vehicle: String, Codable {
    case car
    case truck
}
struct Container: Codable {
    var map: [Vehicle: String]
}
struct Container2: …

How to disable with ButtonStyle in SwiftUI

Issue #853

With ButtonStyle, the disabled modifier does not seem to work, we need to use allowsHitTesting.

import SwiftUI

struct ActionButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        HStack { …

How to query document id in array in Firestore

Issue #852

Supposed we have Book object

struct Book: Identifiable, Codable, Hashable {
    @DocumentID var id: String?
}

We should use FieldPath instead of id for query

let booksRef: CollectionReference = ...
let ids: [String] = ...

booksRef
    . …

How to provide default Codable in Swift

Issue #851

Use DefaultValue to provide defaultValue in our property wrapper DefaultCodable

public protocol DefaultValue {
    associatedtype Value: Codable
    static var defaultValue: Value { get }
}

public enum DefaultBy {
    public enum True: …

How to use dynamic shape in SwiftUI

Issue #850

Erase with AnyShape

struct AnyShape: Shape {
    init<S: Shape>(_ wrapped: S) {
        innerPath = { rect in
            let path = wrapped.path(in: rect)
            return path
        }
    }

    func path(in rect: CGRect) -> …

How to use Picker with optional selection in SwiftUI

Issue #849

We need to explicitly specify optional in tag

extension AVCaptureDevice: Identifiable {
    public var id: String { uniqueID }
}

@State var device: AVCaptureDevice?

Picker("Camera", selection: $device) {
    ForEach(manager. …

How to deinit NSWindow

Issue #848

Hold a weak reference to NSWindow, and let system window server manages its lifetime

weak var window = NSWindow()
window.isReleasedWhenClosed = true

How to scale system font size to support Dynamic Type

Issue #847

We should use Dynamic Font Type as much as possible, as per Typography guide and https://www.iosfontsizes.com/

But in case we have to use a specific font, we can scale it with UIFontMetrics

import SwiftUI
import UIKit

extension Font { …

How to round specific corner in SwiftUI

Issue #846

We use UIBezierPath with addArc to draw specific corner with different rounding values.

import SwiftUI

extension View {
    func clipCorners(
        topLeft: CGFloat = 0,
        bottomLeft: CGFloat = 0,
        topRight: CGFloat = 0, …

How to show suffix text in TextField in SwiftUI

Issue #845

Suppose we have struct Payment as the state, we declare custom Binding<String> that derives from our state.

struct Payment {
    var amount: Int = 0
}

To show our suffix view, we use .fixedSize(horizontal: true, vertical: false) to …

How to show currency symbol in TextField in SwiftUI

Issue #844

Use custom Binding and validate the text. In case of zero, return empty string to let TextField display placeholder

var textField: some View {
    let text = Binding<String>(
        get: {
            state.amount > 0 ? "$\( …

How to make multiline message text view in SwiftUI

Issue #843

This can be used in message bar input or some popover form. We use sizeThatFits to calculate the height so that it grow under certain height limit

import SwiftUI
import UIKit

struct MessageTextField: View {
    let placeholder: String …

How to read safe area insets in SwiftUI

Issue #842

Declare EnvironmentKey and read safeAreaInsets from key window in connectedScenes

struct SafeAreaInsetsKey: EnvironmentKey {
    static var defaultValue: EdgeInsets {
        UIApplication.shared.keyWindow?.safeAreaInsets.swiftUIInsets ?? …

How to make tab strip with enum cases in SwiftUI

Issue #841

Declare generic on RawRepresentable

import SwiftUI

struct TabStrip<T: RawRepresentable & Hashable>: View where T.RawValue == String {
    let values: [T]
    @Binding var selected: T

    var body: some View {
        ScrollView …

How to replace multiple regex matches in Swift

Issue #840

Used to replace credit card regex 30[0-5]#-######-###L in EasyFake

We can use ? to have non-greedy behavior, or I here use square bracket to fine-tune the expression \{[\d*,]*\d*\} Also, I need to reversed the matches because each …

How to move files with Swift script

Issue #839

Use locales data from faker.js to https://github.com/onmyway133/EasyFake, renaming files since files, regardless of sub directories in Xcode, must have different name.

We use enumerator API on FileManager to traverse all files in all …

How to map Binding with optional value in SwiftUI

Issue #838

We can write our custom Binding

import SwiftUI

extension Binding where Value == Date? {
    func flatten(defaultValue: Date) -> Binding<Date> {
        Binding<Date>(
            get: { wrappedValue ?? defaultValue }, …

How to get view height in SwiftUI

Issue #837

I usually use GeometryReader in background to get size of view, and encapsulate it inside a ViewModifier

struct GetHeightModifier: ViewModifier {
    @Binding var height: CGFloat

    func body(content: Content) -> some View { …

How to prevent wheel Picker conflict with DragGesture in SwiftUI

Issue #836

If we have a Picker inside a View that has DragGesture, chances are when we scroll the wheel, the DragGesture is detected too

To prevent this, we can attach a dummy DragGesture to our Picker

Picker("", selection: $number) { …

How to make equal width buttons in SwiftUI

Issue #835

I usually define ButtonStyle to encapsulate common styles related to buttons. Here we specify .frame(maxWidth: .infinity) to let this button take the whole width as possible

struct MyActionButtonStyle: ButtonStyle {
    func makeBody( …

How to make bottom sheet in SwiftUI

Issue #834

In iOS 15, we can use UISheetPresentationController to show bottom sheet like native Maps app. But before that there’s no such built in bottom sheet in UIKit or SwiftUI.

We can start defining API for it. There are 3 ways to show …

How to show abbreviated ago Date in Swift

Issue #833

Use RelativeDateTimeFormatter. This assumes US locale is used

extension Date {
    private static let relativeFormatter: RelativeDateTimeFormatter = {
        let formatter = RelativeDateTimeFormatter()
        formatter.calendar = …

Icon won't take on final exe

Issue #832

How to bind to nested ObservableObject in SwiftUI

Issue #831

We can normally listen to sub ObservableObject by either listen to its objectWillChange or its Publisher

class SubModel: ObservableObject {
    @Published var count = 0
}

class AppModel: ObservableObject {
    @Published var submodel: …

How to structure navigation in SwiftUI apps

Issue #830

Since iOS 16, it is possible to define programmatic routes with `NavigationStack

I usually start by defining enum Route for all possible routes in the app. Note if your app is complex, you can define multiple Route type, each for different …

How to track contentSize and scroll offset for ScrollView in SwiftUI

Issue #829

Use PreferenceKey with a custom coordinateSpace to make our own TrackableScrollView. Note that the offset here is in reversed to contentOffset in normal UIScrollView

import SwiftUI

struct TrackableScrollView<Content: View>: View { …

How to focus TextField in SwiftUI

Issue #828

From iOS 15, FocusState

Use focused(_:) for single TextField, and focused(_:equals:) for multiple TextField

struct FormView: View {

    @FocusState private var isFocused: Bool
    @State private var name = ""

    var body: some …

How to use debounce in Combine in Swift

Issue #827

I’m trying a simple Future and sink. As long as I have debounce, only receiveCompletion gets called, but not receiveValue

private var bag = Set<AnyCancellable>()

let future = Future<Int, Never> { promise in
    promise(. …

How to use Button inside NavigationLink in SwiftUI

Issue #826

Use isActive binding

@State private var goesToDetail: Bool = false

NavigationLink(
    destination: DetailView(viewModel: viewModel),
    isActive: $goesToDetail) {
    Button(action: { goesToDetail = true }) {
        Text("Next" …

How to structure user state for App in SwiftUI

Issue #825

For many apps that require user authentication, a common practice is to define a shared UserManager with an optional User. This is convenient but it requires us to constantly unwrap and check that user

class UserManager {
    static let …

How to do NavigationLink programatically in SwiftUI

Issue #824

Use a custom NavigationLink with EmptyView as the background, this failable initializer accepts Binding of optional value. This works well as the destination are made lazily.

extension NavigationLink where Label == EmptyView {
    init …

How to make custom navigation bar in SwiftUI

Issue #823

Make atomic components and compose them. Firstly with NavigationBar that has custom leading and trailing content, there we can customize padding.

import SwiftUI

struct NavigationBar<Leading: View, Trailing: View>: View {
    @ …

How to convert NSEvent locationInWindow to window coordinate

Issue #822

Get active screen with mouse

func activeScreen() -> NSScreen? {
    let mouseLocation = NSEvent.mouseLocation
    let screens = NSScreen.screens
    let screenWithMouse = (screens.first { NSMouseInRect(mouseLocation, $0.frame, false) }) …

How to sync width for child views in SwiftUI

Issue #821

Suppose we have a 16:9 preview Image and we want the title Text to be the same width

First we need PreferenceKey to store and sync size

struct SizePreferenceKey: PreferenceKey {
    typealias Value = CGSize
    static var defaultValue: …

How to highlight link in Text in SwiftUI

Issue #820

Use NSDataDetector to detect links, and NSMutableAttributedString to mark link range. Then we enumerateAttributes and build our Text

Screenshot 2021-07-06 at 07 23 56
func attribute(string: String) -> Text {
    guard let detector = try? NSDataDetector(types: …

How to conform UIImage to Codable

Issue #819

Either use EasyStash or make a simple CodableImage

struct CodableImage: Codable {
    let image: UIImage?

    init(image: UIImage) {
        self.image = image
    }

    enum CodingKeys: CodingKey {
        case data
        case scale …

How to show custom context menu in SwiftUI

Issue #818

There’s a lot to do to imitate iOS ContextMenu look and feel

  • vibrancy blur background
  • haptics feedback
  • targeted view position
  • interaction dismiss gesture

For now here’s a rough implementation of a custom context menu where we …

How to declare View with ViewBuilder in SwiftUI

Issue #817

Thanks to resultBuilder and container type in Swift, the following are possible in SwiftUI

Local variable

struct ChartView {
    var body: some View {
        computation
    }

    @ViewBuilder
    var computation: some View {
        let …

How to make custom Menu in SwiftUI

Issue #816

SwiftUI supports Menu but the menu items only appear after the menu button is touched. We can initiate the look and feel of Menu with a custom implementation

Screenshot 2021-07-01 at 21 11 02
import SwiftUI

struct CustomMenu<Content: View>: View {
    @ViewBuilder …

How ObservableObject work in SwiftUI

Issue #815

When ever a property marked with @Published change, ObservableObject will emit objectWillChange.send hence telling the View that observes it to reinvalidate.

In WWDC 2021 session Discover concurrency in SwiftUI they mention how …

How to cancel vertical scrolling on paging TabView in SwiftUI

Issue #814

From iOS 14, TabView has the PageTabViewStyle that turns TabView into the equivalent UIPageViewController.

We can of course implement our own Pager but the simple DragGesture does not bring the true experience of a paging UIScrollView or …

How to make simple swipe vertically to dismiss in SwiftUI

Issue #813

Use simultaneousGesture to not collide with potential horizontal scrolling in carousel view, and check that we’ more accidentally swipe horizontally.

import SwiftUI

struct SwipeToDismissModifier: ViewModifier {
    var onDismiss: () …

How to make carousel pager view in SwiftUI

Issue #812

Use GeometryReader to set width and a DragGesture on LazyVStack

CarouselView(
    pageCount: images.count,
    currentIndex: $selectedImageIndex
) {
    ForEach(0 ..< images) { image in
        // AsyncImage
    }
}
struct CarouselView …

How to use SwiftFormat

Issue #811

Don’t add SwiftFormat as SPM package, instead use command line directly

if which swiftformat >/dev/null; then
  swiftformat .
else
  echo "warning: SwiftFormaat not installed, download from …

How to update Firestore value with KeyPath in Swift

Issue #810

struct User {
    var createdAt: Date
    var name: Sttring
    var locked: Bool
}
extension KeyPath where Root == User {
    var keyPathString: String {
        switch self {
        case \User.createdAt: return "createdAt" …

How to show context menu with custom preview in SwiftUI

Issue #809

Add a hidden overlay UIContextMenuInteraction. Provide preview in previewProvider and actions in actionProvider. Use @ViewBuilder to make declaring preview easy.

extension View {
    func contextMenuWithPreview<Content: View>( …

How to login with Apple in SwiftUI

Issue #808

Make SignInWithAppleButton

Wrap ASAuthorizationAppleIDButton inside UIViewRepresentable

import SwiftUI
import UIKit
import AuthenticationServices

struct SignInWithAppleButton: View {
    @Environment(\.colorScheme)
    private var …

How to use SwiftLint in SPM project

Issue #807

Don’t add SwiftLint via SPM, but just add a Run Script Build phrase

if which swiftlint >/dev/null; then
  swiftlint
else
  echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi …

How to show modal window in AppKit

Issue #806

Use runModal

https://developer.apple.com/documentation/appkit/nsapplication/1428590-runmodalsession

Blocks main queue

A loop that uses this method is similar in some ways to a modal event loop run with runModal(for:), except with this …

How to perform action during long press in SwiftUI

Issue #805

Use LongPressGesture to detect when long-press gesture has been recognized, and chain with DragGesture to check when pressing still occurs

Image(systemName: SFSymbol.deleteLeft.rawValue)
    .imageScale(.medium)
    .onTapGesture { …

How to fallback img in React

Issue #804

<img 
    src={user.avatarUrl} 
    onError={(e) => {
        e.target.onerror = null; 
        e.target.src = "/images/default.png"
    }}
/>

Extract to React Component

interface Props {
    src: string
    className: …

How to use videojs in React

Issue #803

import React from 'react';
import videojs from 'video.js'
import 'video.js/dist/video-js.css';

export default class VideoPlayer extends React.Component {
    createPlayer() {
        // instantiate Video.js …

How to use FontAwesome 5 in Nextjs

Issue #802

npm i --save @fortawesome/fontawesome-svg-core \
             @fortawesome/free-solid-svg-icons \
             @fortawesome/free-brands-svg-icons \
             @fortawesome/react-fontawesome
import { faApple, faGithub, faTwitter } from …

How to use Bulma in Nextjs

Issue #801

Read

npm install bulma sass

In styles/index.scss

@import '~bulma/bulma';

In _app.tsx

import '../styles/index.scss'

How to make your apps stand out on the AppStore

Issue #799

Besides coming up with a good idea and building the app, there are many other things you can do to boost your apps’ visibility

Twitter thread https://twitter.com/onmyway133/status/1387851727714635776 Thread reader …

How to use SwiftGen and LocalizedStringKey in SwiftUI

Issue #798

swiftgen.yml

strings:
  inputs: PastePal/Resources/Localizable/en.lproj
  outputs:
    - templatePath: swiftgen-swiftui-template.stencil
      output: PastePal/Resources/Strings.swift

Template from …

How to use ForEach with indices in SwiftUI

Issue #796

One seemingly obvious way to use ForEach on array with indices is using enumerated

struct Book: Hashable, Identifiable {
    let id: UUID
    let name: String
}

struct BooksView: View {
    let books: [Book]

    var body: some View { …

How to resize NSImage with padding

Issue #795

extension NSImage {
    func resize(width: CGFloat, height: CGFloat, padding: CGFloat) -> NSImage {
        let img = NSImage(size: CGSize(width: width, height: height))

        img.lockFocus()
        let ctx = NSGraphicsContext. …

How to convert from paid to freemium in SwiftUI with RevenueCat

Issue #794

I’ve been distributing my apps PastePal and Push Hero as a paid upfront apps on Appstore. I’ve quickly come to realize the importance of trials since many have requested a tryout before purchasing.

Manual sending out trials …

How to repeat array of object in Swift

Issue #793

To create array containing number of repeated value in Swift, we can use Array.init(repeating:count:)

let fiveZs = Array(repeating: "Z", count: 5)
print(fiveZs)
// Prints "["Z", "Z", "Z", "Z", …

How to use dynamic color in iOS

Issue #792

iOS 13 introduced Dark Mode with User Interface Style that makes it easy to support dark and light theme in our apps. Before we dive in, here are some official resources

How to use View protocol in SwiftUI

Issue #791

SwiftUI has View protocol which represents part of your app’s user interface and provides modifiers that you use to configure views.

You create custom views by declaring types that conform to the View protocol. Implement the required …

How too save image to Photo library in iOS

Issue #790

Use UIImageWriteToSavedPhotosAlbum

Adds the specified image to the user’s Camera Roll album.

Let’s make an NSObject delegate class so we can perform target action to notify about completion

import UIKit

struct ImageService { …

How to manage WindowGroup in SwiftUI for macOS

Issue #789

Using WindowGroup

New in SwiftUI 2.0 for iOS 14 and macOS 11.0 is WindwGroup which is used in App protocol. WindowGroup is ideal for document based applications where you can open multiple windows for different content or files. For …

How to show img tag from GitHub markdown in Hugo

Issue #788

I just convert my blog https://onmyway133.com/ from Hexo.js back to Hugo again. Hugo now uses goldmark as the default markdown processor instead of blackfriday

All works well, except that I use GitHub markdown to write articles, which use …

How to name Boolean property in Swift

Issue #787

In Swift, property, especially for Boolean flagging, uses the regular verb form for the third person. There are few exceptions, such as enable

NSManagedObjectContext.automaticallyMergesChangesFromParent
UIView.clipsToBounds
UIView. …

How to use with block configure in Swift

Issue #786

Sometimes we need to update some properties between objects, for example

book.name = updatedBook.name
book.page = updatedBook.page
book.publishedAt = updatedBook.publishedAt

Repeating the caller book is tedious and error-prone. In Kotlin, …

How to use Core Data

Issue #785

Core Data

Calling mergeChanges on a managed object context will automatically refresh any managed objects that have changed. This ensures that your context always contains all the latest …

How to force resolve Swift Package in Xcode

Issue #784

Every time I switch git branches, SPM packages seem to be invalidated and Xcode does not fetch again, no matter how many times I reopen. Running xcodebuild -resolvePackageDependencies does fetch but Xcode does not recognize the resolved …

How to listen to remote changes in CloudKit CoreData

Issue #783

Remove chane notification

Read Consuming Relevant Store Changes

If the import happens through a batch operation, the save to the store doesn’t generate an NSManagedObjectContextDidSave notification, and the view misses these relevant …

How to listen to Published outside of SwiftUI view

Issue #782

Use $ to access Publisher

final class Store: ObservableObject {
    @Published var showsSideWindow: Bool = false
}
var anyCancellables = Set<AnyCancellable>()

store.$showsSideWindow
    .removeDuplicates()
    .throttle(for: 0.2, …

How to filter non numeric digit from String in Swift

Issue #781

This sounds like an easy task, but a quick search on Stackoverflow results in this with highest votes https://stackoverflow.com/questions/29971505/filter-non-digits-from-string

CharacterSet.decimalDigits contains more than just digits

This …

How to build container view in SwiftUI

Issue #780

To make a container view that accepts child content, we use ViewBuilder

struct ContainerView<Content: View>: View {
    let content: Content

    init(@ViewBuilder content: () -> Content) {
        self.content = content()
    } …

How to tune performance with ButtonBehavior in SwiftUI

Issue #779

With Xcode 12.4, macOS 11.0 app. Every time we switch the system dark and light mode, the CPU goes up to 100%. Instruments show that there’s an increasing number of ButtonBehavior

Screenshot 2021-02-24 at 10 12 05

Suspect State in a row in LazyVStack

Every cell has …

How to use GroupBox in SwiftUI

Issue #778

For now using GroupBox has these issues in macOS

  • Prevents dragging scroll indicator to scroll
  • Switch from light to dark mode may cause 100% CPU usage

How to suppress selector warning in Swift

Issue #777

Sometimes we need to use dynamic selector and that triggers warning in Swift

Selector("updateWithCount:") // Use '#selector' instead of explicitly constructing a 'Selector'

In ObjC we can use clang macro to …

How to make simple search bar in SwiftUI

Issue #776

We need to use a custom Binding to trigger onChange as onEditingChanged is only called when the user selects the textField, and onCommit is only called when return or done button on keyboard is tapped.

import UIKit
import SwiftUI
import …

How to fix share and action extension not showing up in iOS 14

Issue #775

My share sheet and action extension not showing up in iOS 14, built-in Xcode 12.3. The solution is to restart test device, and it shows up again.

Also make sure your extension targets have the same version and build number, and same …

How to add home screen quick action in SwiftUI

Issue #774

Start by defining your quick actions. You can use UIApplicationShortcutIcon(type:) for predefined icons, or use UIApplicationShortcutIcon(systemImageName:) for SFSymbol

enum QuickAction: String {
    case readPasteboard
    case clear …

How to use EquatableView in SwiftUI

Issue #773

From John Harper ’s tweet

SwiftUI assumes any Equatable.== is a true equality check, so for POD views it compares each field directly instead (via reflection). For non-POD views it prefers the view’s == but falls back to its own …

How to add new property in Codable struct in SwiftUI

Issue #772

I use Codable structs in my apps for preferences, and bind them to SwiftUI views. If we add new properties to existing Codable, it can’t decode with old saved json as we require new properties. We can either do cutom decoding with …

How to show close button in NSTextField in AppKit

Issue #771

Use NSSearchField instead

How to handle escape in NSTextField in SwiftUI

Issue #770

Handle cancelOperation somewhere up in responder chain

class MyWindow: NSWindow {
    let keyHandler = KeyHandler()

    override func cancelOperation(_ sender: Any?) {
        super.cancelOperation(sender)
        keyHandler.onEvent(.esc) …

How to fit ScrollView to content in SwiftUI

Issue #769

If we place ScrollView inside HStack or VStack, it takes all remaining space. To fit ScrollView to its content, we need to get its content size and constrain ScrollView size.

Use a GeometryReader as Scrollview content background, and get …

How to show modal window in SwiftUI for macOS

Issue #768

Use custom NSWindow, set level in becomeKey and call NSApp.runModal to show modal

final class ModalWindow: NSWindow {
    override func becomeKey() {
        super.becomeKey()

        level = .statusBar
    }

    override func close() { …

How to use custom Key for NSCache

Issue #766

Need to use a class, best is to subclass from NSObject

let cache = NSCache<Key, UIImage>()
final class Key: NSObject {
    override func isEqual(_ object: Any?) -> Bool {
        guard let other = object as? Key else { …

How to show multiple popover in SwiftUI

Issue #765

In SwiftUI currently, it’s not possible to attach multiple .popover to the same View. But we can use condition to show different content

struct ClipboardCell: View {
    enum PopoverStyle {
        case raw
        case preview
    } …

How to handle keyDown in SwiftUI for macOS

Issue #764

Use a custom KeyAwareView that uses an NSView that checks for keyDown method. In case we can’t handle certain keys, call super.keyDown(with: event)

import SwiftUI
import KeyboardShortcuts

struct KeyAwareView: NSViewRepresentable { …

How to extend custom View in SwiftUI

Issue #763

I usually break down a big struct into smaller views and extensions. For example I have a ClipboardCell that has a lot of onReceive so I want to move these to another component.

One way to do that is to extend ClipboardCell

struct …

How to use Sparkle for macOS app

Issue #762

Install Sparkle

  • For now, the latest stable version is 1.24.0 which supports CocoaPods OK, but still, have issues with SPM. Support non sandboxed apps
  • Version 2.0.0 is in beta and supports sandboxed apps

To install, use CocoaPods

platform …

How to use ScrollViewReader in SwiftUI

Issue #761

Explicitly specify id

ScrollView {
    ScrollViewReader { proxy in
        LazyVStack(spacing: 10) {
            ForEach(items) { item in
                Cell(item: item)
                    .id(item.id)
            }
        }
        . …

How to handle keyDown in NSResponder

Issue #760

import AppKit
import Omnia

class MyWindow: NSWindow {
    override func keyDown(with event: NSEvent) {
        super.keyDown(with: event)

        if isKey(NSDeleteCharacter, event: event) {
            NotificationCenter.default.post( …

How to handle NSSearchToolbarItem in macOS 11

Issue #758

extension NSToolbarItem.Identifier {
    static let searchItem: NSToolbarItem.Identifier = NSToolbarItem.Identifier("SearchItem")
}

let searchItem = NSSearchToolbarItem(itemIdentifier: .searchItem)

extension AppDelegate: …

How to do launch at login for macOS apps

Issue #757

  • Use SMLoginItemSetEnabled from Service Management framework
  • Use a helper background app that checks and invokes our main application
  • Copy our helper app into Library/LoginItems
helper_dir="$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH …

How to fix overlapped navigation titles in SwiftUI

Issue #756

extension NavigationLink {
    func fixOverlap() -> AnyView {
        if UIDevice.current.userInterfaceIdiom == .phone {
            return self.isDetailLink(false).erase()
        } else {
            return self.erase()
        } …

How to create and notarize dmg file

Issue #753

  • Archive and export app from Xcode
  • Create dmg
  • Use create-dmg It is said that we don’t need to notarize the app, we can just notarize the whole dmg
  • Send dmg to notarize

This takes a while

xcrun altool -t osx -f PastePal.dmg --primary …

How to use module import in nodejs

Issue #752

Use esm

npm install esm

In our code, import as normal

const fs = require('fs');
// intended to be run after babel, and in ./dist folder
import factory from 'data'
const shell = require('shelljs')

Then use esm to …

How to use relative file module with Create React app

Issue #751

Declare data/package.json to make it into node module

{
    "name": "data",
    "version": "0.1.0",
    "private": true,
    "homepage": ".",
    "main": "main.js"
} …

How to open downloaded app from browser in Big Sur

Issue #750

Recently when distributing staging releases of my app PastePal via GitHub release or Google Drive, people had hard time opening it

Screenshot 2021-01-15 at 10 26 26

The displayed error is

You do not have permission to open the application

The more verbose error when …

How to add alternative app icons for iOS

Issue #749

Some apps want to support alternative app icons in Settings where user can choose to update app icon. Here’s some must do to make it work, as of Xcode 12.2

  • In Info.plist, must declare CFBundleIcons with both CFBundlePrimaryIcon and …

How to make popup button in SwiftUI for macOS

Issue #748

There is said to be PopUpButtonPickerStyle and MenuPickerStyle but these don’t seem to work.

There’s Menu button it shows a dropdown style. We fake it by fading this and overlay with a button. allowsHitTesting does not work, …

How to use UITextView in SwiftUI

Issue #747

Need to use Coordinator conforming to UITextViewDelegate to apply changes back to Binding

import SwiftUI
import UIKit

struct MyTextView: UIViewRepresentable {
    @Binding
    var text: String

    final class Coordinator: NSObject, …

How to check app going to background in SwiftUI

Issue #746

From iOS 13, the default is to support multiple scene, so the the old UIApplicationDelegate lifecycle does not work. Double check your Info.plist for UIApplicationSceneManifest key

<key>UIApplicationSceneManifest</key> …

How to use selection in List in SwiftUI

Issue #745

I used to use selection with Binding where wrappedValue is optional, together with tag in SwiftUI for macOS, and it shows current selection

@Binding
var selection: Tag? = .all

List(section: $selection) {
    Text("All")
         . …

How to simplify communication patterns with closure in Swift

Issue #744

As someone who builds lots of apps, I try to find quick ways to do things. One of them is to avoid repetitive and cumbersome APIs. That’s why I built Anchors to make Auto Layout more convenient, Omnia to add missing extensions. The next …

How to use Apple keyboard key symbols

Issue #743

•  = Apple logo • ⌘ = Command • ⇧ = Shift • ⌫ = Backspace/Delete • ⇪ = Caps lock • ⌥ = Option/Alt • ⌃ = Control • ⎋ = Escape • ←↑→↓ = Arrow Keys • ↩ = Return

How to make Auto Layout more convenient in iOS

Issue #742

Auto Layout has been around since macOS 10.7 and iOS 6.0 as a nicer way to do layouts over the old resizing masks. Besides some rare cases when we need to manually specify origins and sizes, Auto Layout is the preferred way to do …

How to form product idea

Issue #740

How to gain product ideas?

  1. Scratch your own itch. If you don’t have any itch to scratch, stop here. This is awkward. Go travelling. Go exploring the world. The world always has problems and needs solution. Image

  2. Build any …

How to join AppStore Small Business Program

Issue #739

New program reduces App Store commission to 15 percent for small businesses earning up to $1 million per year

  1. “earning up to $1 million” means proceeds, not sales. This is what we get after Apple’s cut. “up …

How to deep work

Issue #738

Just found out the book Deep Work by Cal Newport and it has some interesting guidelines Here’s a very good summary of the book

https://www.youtube.com/watch?v=gTaJhjQHcf8&ab_channel=ProductivityGame

  1. Put a boundary on …

How to make tiled image in SwiftUI

Issue #737

Use resizingMode of .tile with a tile image from https://www.transparenttextures.com/

Image("transparentTile")
    .resizable(capInsets: .init(), resizingMode: .tile)
    .scaleEffect(2)
    .aspectRatio(contentMode: .fit)
    . …

How to use WebView in SwiftUI

Issue #736

struct MyWebView: NSViewRepresentable {
    let url: URL
    @Binding
    var isLoading: Bool

    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }

    func makeNSView(context: Context) -> WKWebView { …

How to use GeometryReader in SwiftUI

Issue #735

From my previous post How to use flexible frame in SwiftUI we know that certain views have different frame behaviors. 2 of them are .overlay and GeometryReader that takes up whole size proposed by parent.

By default GeometryReader takes up …

How to use flexible frame in SwiftUI

Issue #734

In SwiftUI there are fixed frame and flexible frame modifiers.

Fixed frame Positions this view within an invisible frame with the specified size.

Use this method to specify a fixed size for a view’s width, height, or both. If you only …

How to disable scrolling in NSTextView for macOS

Issue #733

NSTextView has this handy method to make scrollable NSTextView NSTextView.scrollableTextView(). The solution is to get to the responder outside enclosing NSScrollView, in my case it is the SwiftUI hosting view

class DisabledScrollTextView: …

How to override attribute string in Swift

Issue #732

Use NSMutableAttributedString and add attribute for whole range

let a: NSAttributedString
let m: NSMutableAttributedString = NSMutableAttributedString(attributedString: a)
let range = NSRange(location: 0, length: a.length)
m.addAttribute(. …

How to make view appear with delay in SwiftUI

Issue #731

Sometimes we don’t want to show progress view right away

HUDProgressView()
    .transition(
        AnyTransition.asymmetric(
            insertion: AnyTransition.opacity.animation(Animation.default.delay(1)),
            removal: …

How to make attributed string Text in SwiftUI for macOS

Issue #730

Use NSTextField with maximumNumberOfLines

import AppKit
import SwiftUI

struct AttributedText: NSViewRepresentable {

    let attributedString: NSAttributedString

    init(_ attributedString: NSAttributedString) {
        self. …

How to do copy paste delete in Swift for macOS

Issue #729

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
    @IBAction func copy(_ sender: Any) {
        print("copy", sender)
    }


    @IBAction func paste(_ sender: Any) {
        print("paste", sender) …

How to make simple NSItemProvider in Swift

Issue #728

NSItemProvider(object: StringProvider(string: string))

class StringProvider: NSObject, NSItemProviderWriting {
    let string: String
    init(string: String) {
        self.string = string
        super.init()
    }

    static var …

How to use hashtag raw string in Swift

Issue #727

Use # in Swift 5 to specify raw string, for example regular expression

#"^#?(?:[0-9a-fA-F]{3}){1,2}$"#

Read more

How to make UserDefaults property wrapper

Issue #726

@propertyWrapper
struct UserDefault<Value> {
    let key: String
    let defaultValue: Value
    let container: UserDefaults = .standard

    var wrappedValue: Value {
        get {
            return container.object(forKey: key) as …

How to use Set to check for bool in Swift

Issue #725

When you want to check for existence using Bool, consider using Set over Dictionary with Bool, as Set guarantee uniqueness. If using Dictionary instead, the value for key is Optional<Bool> where we have to check for both optional and …

How to make visual effect blur in SwiftUI for macOS

Issue #724

We can use .blur modifier, but with VisualEffectView gives us more options for material and blending mode.

public struct VisualEffectView: NSViewRepresentable {
    let material: NSVisualEffectView.Material
    let blendingMode: …

How to make simple HUD in SwiftUI

Issue #723

Use @ViewBuilder to build dynamic content for our HUD. For blur effect, here I use NSVisualEffectView, but we can use .blur modifier also

struct HUD<Content>: View where Content: View {
    let content: () -> Content

    init(@ …

How to instrument SwiftUI app

Issue #722

With Xcode 12, we can fire up Instrument to profile our app. Select SwiftUI template

Screenshot 2020-12-26 at 00 02 03

There are many profiles in that template, I find SwiftUI and Time Profile very useful. Here’s the profile I run for my app PastePal

SwiftUI View …

How to force set frame explicitly for NSWindow

Issue #721

For setFrame to take effect

mainWindow.setFrame(rect, display: true)

we can remove auto save frame flag

mainWindow.setFrameAutosaveName("MyApp.MainWindow")

How to rotate NSStatusItem

Issue #720

NSStatusItem is backed by NSButton, we can animate this inner button. We need to specify position and anchorPoint for button’s layer so it rotates around its center point

guard
    let button = statusItem.button
else { return }

let …

How to show image and text in menu item in SwiftUI for macOS

Issue #719

From SwiftUI 2 for macOS 11.0, we have access to Menu for creating menu and submenu. Usually we use Button for interactive menu items and Text for disabled menu items.

The easy way to customize menu with image is to call Menu with content …

How to make sharing menu in SwiftUI for macOS

Issue #718

Use NSSharingService.sharingServices(forItems:) with an array of one empty string gives a list of sharing items. There we show image and title of each menu item.

We should cache sharing items as that can cause performance issue

import …

How to make stepper with plus and minus buttons in SwiftUI for macOS

Issue #717

Try to use predefined system colors in Human Interface Guidelines for macOS

Here we use this color unemphasizedSelectedTextBackgroundColor for button background

Screenshot 2020-12-21 at 06 24 16
HStack(spacing: 1) {
    makeUnderListButton(action: {}, icon: .plus) …

How to fix Picker not showing selection in SwiftUI

Issue #716

I have an enum that conforms to CaseIterable that I want to show in Picker

enum Position: String, Codable, CaseIterable, Identifiable {
    var id: String { rawValue }
    case left
    case right
    case bottom
    case top
}

Picker( …

My year in review 2020

Issue #715

I remember this time last year in December 2019, I spent almost every single bit of my free time on Puma because I want a Swift friendly version of fastlane that suits my need and leverages Swift 5 features.

Here’s my review of my …

How to do didSet for State and Binding in SwiftUI

Issue #714

Below is an example of a parent ContentView with State and a child Sidebar with a Binding.

The didSet is only called for the property that is changed.

When we click Button in ContentView, that changes State property, so only the didSet in …

How to add toolbar programatically in macOS

Issue #713

To setup toolbar, we need to implement NSToolbarDelegate that provides toolbar items. This delegate is responsible for many things

  • Set visible and allowed items with toolbarDefaultItemIdentifiers
  • Provide item with itemForItemIdentifier …

How to declare network Error with enum in Swift

Issue #712

Describe all possible paths in your program with enum. This is great to track down bugs and to not miss representing potential cases in UI. Errors can come from app layer, backend layer to network issues.

Enum is handy in both UIKit and …

How to programatically select row in List in SwiftUI

Issue #711

List has a selection parameter where we can pass selection binding. As we can see here selection is of type optional Binding<Set<SelectionValue>>? where SelectionValue is any thing conforming to Hasable

@available(iOS 13.0, …

How to show sidebar in SwiftUI for macOS

Issue #710

Starting from macOS 11, we can use List with SidebarListStyle inside NavigationView to declare master detail view. The SidebarListStyle makes list translucent. It automatically handles selection and marks selected row in list with accent …

How to mock UNNotificationResponse in unit tests

Issue #708

The best way to test is to not have to mock at all. The second best way is to have your own abstraction over the things you would like to test, either it is in form of protocol or some function injection.

But in case you want a quick way …

How to support right click menu to NSStatusItem

Issue #707

The trick is to set the button oinside of statusItem to send actions on both leftMouseUp and rightMouseUp.

Another thing to note is we use popUpMenu on NSStatusItem, although it is marked as deprecated on macOS 10.14. We can set menu but …

How to convert struct to Core Data NSManagedObject

Issue #706

Use Mirror and set key value as NSManagedObject subclasses from NSObject

import CoreData

final class ManagedObjectConverter {
    func convert<M>(m: M, context: NSManagedObjectContext) throws -> NSManagedObject {
        let …

How to format ISO date string in Javascript

Issue #705

Supposed we have date in format ISO8601 and we want to get rid of T and millisecond and timezone Z

const date = new Date()
date.toDateString() // "Sat Dec 05 2020"
date.toString() // "Sat Dec 05 2020 06:58:19 GMT+0100 (Central …

How to declare Error in Swift

Issue #704

We used to declare enum that conforms to Error, but any type like struct or class can conform to Error as well.

enum NetworkError: Error {
    case failToCreateRequest
    case failToParseResponse
    case failToReachServe
}

struct …

How to convert from paid to free with IAP

Issue #703

What is receipt

Read When to refresh a receipt vs restore purchases in iOS?

From iOS 7, every app downloaded from the store has a receipt (for downloading/buying the app) at appStoreReceiptURL. When users purchases something via In App …

How to disable NSTextView in SwiftUI

Issue #702

The trick is to use an overlay

MessageTextView(text: $input.message)
    .overlay(obscure)

var obscure: AnyView {
    if store.pricingPlan.isPro {
        return EmptyView().erase()
    } else {
        return Color.black.opacity(0.01). …

How to add under highlight to text in css

Issue #701

Use mark. This does not work for multiline

<p>
    <mark css={css`
        display: inline-block;
        line-height: 0em;
        padding-bottom: 0.5em;
        `}>{feature.title}
    </mark>
</p>

Another way is …

How to use default system fonts in React apps

Issue #700

In index.css

body {
    margin: 0;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica …

How to make simple overlay container in React

Issue #699

Use term ZStack like in SwiftUI, we declare container as relative position. For now it uses only 2 items from props.children but can be tweaked to support mutiple

class App extends React.Component {
    render() {
        return ( …

How to search using regular expression in Xcode

Issue #698

Xcode has powerful search. We can constrain search to be scoped in workspace, project or some folders. We can also constrain case sensitivity.

Another cool thing that people tend to overlook is, besides searching based on text, we can …

How to write to temporary file in Swift

Issue #697

Use temporaryDirectory from FileManager and String.write

func writeTempFile(books: [Book]) -> URL {
    let url = FileManager.default.temporaryDirectory
        .appendingPathComponent(UUID().uuidString)
        .appendingPathExtension( …

How to use functions with default arguments in Swift

Issue #696

Which methods do you think are used here

import Cocoa

struct Robot {
    let a: Int
    let b: Int
    let c: Int

    init(a: Int = 1, c: Int = 3) {
        self.a = a
        self.b = 0
        self.c = c
        print("Init with a= …

How to check IAP Transaction error

Issue #695

Inspect SKPaymentTransaction for error. In Swift, any Error can be safely bridged into NSError there you can check errorDomain and code

private func handleFailure(_ transaction: SKPaymentTransaction) {
    guard let error = transaction. …

How to use nested ObservableObject in SwiftUI

Issue #694

I usually structure my app to have 1 main ObservableObject called Store with multiple properties in it.

final class Store: ObservableObject {
    @Published var pricingPlan: PricingPlan()
    @Published var preferences: Preferences()
} …

How to check dark mode in AppKit for macOS apps

Issue #693

AppKit app has its theme information stored in UserDefaults key AppleInterfaceStyle, if is dark, it contains String Dark.

Another way is to detect appearance via NSView

struct R {
    static let dark = DarkTheme()
    static let light = …

How to check dark mode with color scheme in SwiftUI

Issue #692

Use colorScheme environment, for now it has 2 cases dark and light

struct MainView: View {
    @Environment(\.colorScheme) var colorScheme

    var body: some View {
        Text(colorScheme == .dark ? "Dark Mode" : "Light …

How to avoid multiple match elements in UITests from iOS 13

Issue #691

Supposed we want to present a ViewController, and there exist both UIToolbar in both the presenting and presented view controllers.

From iOS 13, the model style is not full screen and interactive. From UITests perspective there are 2 …

How to use accessibility container in UITests

Issue #690

Use accessibilityElements to specify containment for contentView and buttons. You can use Accessibility Inspector from Xcode to verify.

class ArticleCell: UICollectionViewCell {
    let authorLabel: UILabel
    let dateLabel: UILabel …

How to make full size content view in SwiftUI for macOS

Issue #689

func applicationDidFinishLaunching(_ aNotification: Notification) {
    // extend to title bar
    let contentView = ContentView()
        // .padding(.top, 24) // can padding to give some space
        .edgesIgnoringSafeArea(.top)

    // …

How to override styles in SwiftUI

Issue #688

In the app I’m working on Elegant Converter, I usually like preset theme with a custom background color and a matching foreground color.

Thanks to SwiftUI style cascading, I can just declare in root MainView and it will be inherited …

When to use function vs property in Swift

Issue #687

Although I do Swift, I often follow Kotlin guideline https://kotlinlang.org/docs/reference/coding-conventions.html#functions-vs-properties

In some cases functions with no arguments might be interchangeable with read-only properties. …

How to use CoreData safely

Issue #686

I now use Core Data more often now. Here is how I usually use it, for example in Push Hero

From iOS 10 and macOS 10.12, NSPersistentContainer that simplifies Core Data setup quite a lot. I usually use 1 NSPersistentContainer and its …

How to pass ObservedObject as parameter in SwiftUI

Issue #685

Since we have custom init in ChildView to manually set a State, we need to pass ObservedObject. In the ParentView, use underscore _ to access property wrapper type.

struct ChildView: View {
    @ObservedObject
    var store: Store

    @ …

How to do equal width in SwiftUI

Issue #684

In SwiftUI, specifying maxWidth as .infinity means taking the whole available width of the container. If many children ask for max width, then they will be divided equally. This is similar to weight in LinearLayout in Android or css …

What define a good developer

Issue #683

I always find myself asking this question “What define a good developer?” I ’ve asked many people and the answers vary, they ’re all correct in certain aspects

Good programmer is someone who has a solid knowledge …

How to test push notifications in simulator and production iOS apps

Issue #682

After has recently reminded about his updating APNs provider API which makes me realised a lot has changed about push notifications, both in terms of client and provider approach.

The HTTP/2-based Apple Push Notification service (APNs) …

How to style multiline Text in SwiftUI for macOS

Issue #681

Only need to specify fixedSize on text to preserve ideal height.

The maximum number of lines is 1 if the value is less than 1. If the value is nil, the text uses as many lines as required. The default is nil.

Text(longText)
    .lineLimit …