A better way to update UICollectionView data in Swift with diff framework
Issue #1010
A Better Way to Update UICollectionView Data in Swift with Diff Framework
Familiar Friends
It’s hard …
Explore our Topics page to easily navigate the wide range of content available on our blog. This is your gateway to discovering the diverse conversations and ideas that our blog covers.
Issue #1010
It’s hard …
Issue #1009
SwiftUI’s Observation framework makes reactive UI updates effortless—when a property changes, views that depend on it automatically refresh. But what happens when your data lives in UserDefaults? You might want subscription status, …
Issue #1007
Testing in Swift has always required inheriting from XCTestCase and prefixing every method with test. Sound familiar? With Swift 6, Apple introduced Swift Testing — a framework that feels native to modern Swift …
Issue #1006
When building macOS apps, you often need images that fill their container while keeping their aspect ratio - like cover photos or thumbnails. NSImageView doesn’t do this well out of the box. Here’s how to build a custom …
Issue #998
Traditionally, if we wanted to quickly test a function or a piece of logic, we would open a separate Playground file (.playground).
From Xcode 26 we can have access to the new #Playground macro in Swift 6.2. This allows us to declare a …
Issue #997
An interesting feature in iOS 26 is the ability to create morph “Liquid Glass” effects, where views with the .glassEffect() modifier can fluidly morph into one another. This is achieved using GlassEffectContainer and the …
Issue #996
When creating widgets for iOS, especially those that need user input to be useful, one common challenge is guiding the user to configure them. Before iOS 18, a user would add a widget, but then would have to know to long-press it and …
Issue #995
With iOS 18, SwiftUI introduces matchedTransitionSource and navigationtransition as a powerful new way to create zoom animations between views. This allows you to smoothly transition from a small view to a larger, more detailed view, …
Issue #994
With iOS 18, Apple introduced a powerful new tool for creating beautiful, dynamic backgrounds: MeshGradient. Forget simple two-color gradients; mesh gradients let you blend a whole grid of colors together smoothly, creating stunning, …
Issue #993
Before iOS 17, if you wanted to animate a number changing, SwiftUI would just fade the old number out and fade the new one in. It worked, but it wasn’t very exciting.
Here’s how that looked:
struct OldCounterView: View {
@ …Issue #992
In the past, making your screen update when data changed in UIKit meant writing extra code, either with didSet, Combine or some other callbacks. Now, it’s automatic.
With the latest iOS 26 updates, UIKit can automatically watch your …
Issue #989
In Swift 6, Apple introduced stricter rules to help make your code safer when using concurrency (like async, await, Task, and actor). These rules check that types used in concurrent code are safe to share across threads.
Types that are …
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 …
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: …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. …
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 …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
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.
.copyIssue #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
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() …Issue #973
Before iOS 11, we used to use CIDetector and CIDetectorTypeQRCode to detect QR code
An image processor that identifies notable features, such as faces and barcodes, in a still image or video.
A detector …
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], …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", …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 …
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
}
}
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 …
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", …Issue #958
We can use any bundler, like Parcel, Webpack or Vite. Here I use Webpack 5
npm install @babel/polyfill webpack webpack-cli --save-dev
@babel/polyfill is a package provided by Babel, a popular JavaScript compiler. …
Issue #957
Define console object and set log function to point to our Swift function
import JavaScriptCore
extension JSContext {
func injectConsoleLog() {
evaluateScript(
"""
var console = {}; …Issue #955
Besides WWDC videos & documentation, Apple also has interactive tutorials and books. Below are some of my favorites learning resources
Tutorials
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 …
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( …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 …
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. …Issue #944
SwiftUI in iOS 16 supports Layout protocol to arrange subviews
We need to implement 2 methods
Issue #943
In this tutorial, we’ll learn how to use Swift Charts to visualize ranking data.
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 …
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: …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( …Issue #937
First, you need to enable iCloud Documents capability. Go to target settings -> Signing & Capabilities -> iCloud
`
Then inside your Info.plist, add this with your iCloud identifier and app name …
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 …
Issue #932
Add Share extension and Action extension respectively in Xcode. We can use the same code to both extension
I usually make a ShareView in SwiftUI with ShareViewModel to control the logic
struct ShareView: View {
@ …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 = …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: …Issue #924
Note
the navigation split view coordinates with the List in its first …
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)
Issue #913
Use QuickLookThumbnailing framework
import AppKit
import QuickLookThumbnailing
actor QuicklookService {
static let shared = QuicklookService()
private let generator = QLThumbnailGenerator.shared
func image( …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) …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() { …Issue #910
let string = "Hello world"
string[string.startIndex...] // Hello world
string[..<string.endIndex] // Hello world
let string = "Hello world"
let range = string.startIndex ..< …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
The usual way to fix this is to defer the decision to the correct …
Issue #905
Protect mutable state with Swift actors
Actor reentrancy
Imagine we have two different concurrent tasks trying to fetch the same image at the same time. The first sees that there is no cache entry, proceeds to start downloading the …
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
Issue #903
let image = NSImage(contentsOf: url)
let imageView = NSImageView(image: image)
image.animates = true
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 …Issue #899
Use NSTitlebarAccessoryViewController
var titleBarAccessoryVC: NSTitlebarAccessoryViewController {
let vc = NSTitlebarAccessoryViewController()
let view = HStack {
Spacer()
Button {
} label: { …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 …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 …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. …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 …
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
Issue #889



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

Section("Hashtags") { …Issue #888
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 …
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 …
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 …
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 …
Issue #878
Note that
id is needed, although Book already conforms to Identifiableselection needs a default valueclass BookViewModel: ObservableObject {
@Published var books: [Book] = []
@Published var selectedBooks: Set<Book …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 🤯
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 …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 …
Issue #874
From iOS 13, use UITabBarAppearance and UITabBarItemAppearance
let appearance = UITabBarAppearance()
let itemAppearance = UITabBarItemAppearance(style: .stacked)
itemAppearance.normal.badgeBackgroundColor = .clear
itemAppearance.normal. …Issue #873
Use assistant
let assistant = MCAdvertiserAssistant(serviceType: "my-service, discoveryInfo: nil, session: mcSession)
assistant.start()
let browser = MCBrowserViewController(serviceType: "my-service", session: mcSession) …Issue #871
Use libraries
import web3
import web3keystore
import KeychainAccess
private final class KeyStorage: EthereumKeyStorageProtocol {
enum Key: String { …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 …
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: …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 …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 …
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)
} …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) …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? …Issue #858
isDetailLink(false).introspectNavigationController { nav in
self.nav = nav
}
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 …Issue #856
Use PKPaymentRequest and PKPaymentAuthorizationViewController
@MainActor
final class WalletViewModel: NSObject, ObservableObject {
var canMakePayments: Bool {
PKPaymentAuthorizationViewController.canMakePayments()
} …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 = …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: …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 { …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
. …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: …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. …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 { …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 …
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 ? "$\( …Issue #842
Declare EnvironmentKey and read safeAreaInsets from key window in connectedScenes
struct SafeAreaInsetsKey: EnvironmentKey {
static var defaultValue: EdgeInsets {
UIApplication.shared.keyWindow?.safeAreaInsets.swiftUIInsets ?? …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 …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 …
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 …
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 }, …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 { …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) { …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( …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 …
Issue #833
Use RelativeDateTimeFormatter. This assumes US locale is used
extension Date {
private static let relativeFormatter: RelativeDateTimeFormatter = {
let formatter = RelativeDateTimeFormatter()
formatter.calendar = …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: …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 { …Issue #828
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 …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(. …Issue #826
Use isActive binding
@State private var goesToDetail: Bool = false
NavigationLink(
destination: DetailView(viewModel: viewModel),
isActive: $goesToDetail) {
Button(action: { goesToDetail = true }) {
Text("Next" …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 …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 …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 {
@ …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) }) …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: …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 …Issue #818
There’s a lot to do to imitate iOS ContextMenu look and feel
For now here’s a rough implementation of a custom context menu where we …
Issue #817
Thanks to resultBuilder and container type in Swift, the following are possible in SwiftUI
struct ChartView {
var body: some View {
computation
}
@ViewBuilder
var computation: some View {
let …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
import SwiftUI
struct CustomMenu<Content: View>: View {
@ViewBuilder …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 …
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 …
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" …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>( …Issue #808
Wrap ASAuthorizationAppleIDButton inside UIViewRepresentable
import SwiftUI
import UIKit
import AuthenticationServices
struct SignInWithAppleButton: View {
@Environment(\.colorScheme)
private var …Issue #806
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 …
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 { …Issue #798
swiftgen.yml
strings:
inputs: PastePal/Resources/Localizable/en.lproj
outputs:
- templatePath: swiftgen-swiftui-template.stencil
output: PastePal/Resources/Strings.swift
Template from …
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 { …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. …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 …
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", …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
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 …
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 { …Issue #789
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 …
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. …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, …
Issue #785
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 …
Issue #783
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 …
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, …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
This …
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()
} …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
Every cell has …
Issue #778
For now using GroupBox has these issues in macOS
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 …
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 …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 …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 …
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 …
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) …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 …
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() { …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 { …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
} …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 { …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 …Issue #762
To install, use CocoaPods
platform …Issue #761
Explicitly specify id
ScrollView {
ScrollViewReader { proxy in
LazyVStack(spacing: 10) {
ForEach(items) { item in
Cell(item: item)
.id(item.id)
}
}
. …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( …Issue #758
extension NSToolbarItem.Identifier {
static let searchItem: NSToolbarItem.Identifier = NSToolbarItem.Identifier("SearchItem")
}
let searchItem = NSSearchToolbarItem(itemIdentifier: .searchItem)
extension AppDelegate: …Issue #757
Library/LoginItemshelper_dir="$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH …Issue #756
extension NavigationLink {
func fixOverlap() -> AnyView {
if UIDevice.current.userInterfaceIdiom == .phone {
return self.isDetailLink(false).erase()
} else {
return self.erase()
} …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
CFBundleIcons with both CFBundlePrimaryIcon and …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, …
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, …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> …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")
. …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 …
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 …
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)
. …Issue #736
struct MyWebView: NSViewRepresentable {
let url: URL
@Binding
var isLoading: Bool
func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}
func makeNSView(context: Context) -> WKWebView { …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 …
Issue #734
In SwiftUI there are fixed frame and flexible frame modifiers.
Use this method to specify a fixed size for a view’s width, height, or both. If you only …
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: …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(. …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: …Issue #730
Use NSTextField with maximumNumberOfLines
import AppKit
import SwiftUI
struct AttributedText: NSViewRepresentable {
let attributedString: NSAttributedString
init(_ attributedString: NSAttributedString) {
self. …Issue #729
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBAction func copy(_ sender: Any) {
print("copy", sender)
}
@IBAction func paste(_ sender: Any) {
print("paste", sender) …Issue #728
NSItemProvider(object: StringProvider(string: string))
class StringProvider: NSObject, NSItemProviderWriting {
let string: String
init(string: String) {
self.string = string
super.init()
}
static var …Issue #727
Use # in Swift 5 to specify raw string, for example regular expression
#"^#?(?:[0-9a-fA-F]{3}){1,2}$"#
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 …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 …
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: …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(@ …Issue #721
For setFrame to take effect
mainWindow.setFrame(rect, display: true)
we can remove auto save frame flag
mainWindow.setFrameAutosaveName("MyApp.MainWindow")
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 …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 …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 …
Issue #713
To setup toolbar, we need to implement NSToolbarDelegate that provides toolbar items. This delegate is responsible for many things
toolbarDefaultItemIdentifiersitemForItemIdentifier …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 …
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, …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 …
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 …
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 …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 …Issue #703
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 …
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 …
Issue #697
Use temporaryDirectory from FileManager and String.write
func writeTempFile(books: [Book]) -> URL {
let url = FileManager.default.temporaryDirectory
.appendingPathComponent(UUID().uuidString)
.appendingPathExtension( …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= …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. …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()
} …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 = …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 …
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 …Issue #689
func applicationDidFinishLaunching(_ aNotification: Notification) {
// extend to title bar
let contentView = ContentView()
// .padding(.top, 24) // can padding to give some space
.edgesIgnoringSafeArea(.top)
// …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 …
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. …
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 …
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
@ …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 …
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) …
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 …Issue #680
For List in SwiftUI for macOS, it has default background color because of the enclosing NSScrollView via NSTableView that List uses under the hood. Using listRowBackground also gives no effect
The solution is to use a library like …
Issue #679
While redesigning UI for my app Push Hero, I ended up with an accordion style to toggle section.
It worked great so far, but after 1 collapsing, all image and text views have reduced opacity. This does not happen for other elements like …
Issue #678
Use enumerated to get index so we can assign to item in list. Here is how I show list of device tokens in my app Push Hero
private var textViews: some View {
let withIndex = input.deviceTokens.enumerated().map({ $0 })
let binding: …Issue #677
The quick way to add new properties without breaking current saved Codable is to declare them as optional. For example if you use EasyStash library to save and load Codable models.
import SwiftUI
struct Input: Codable {
var bundleId: …Issue #675
Use wrappedValue to get the underlying value that Binding contains
extension View {
func addOverlay(shows: Binding<Bool>) -> some View {
HStack {
self
Spacer()
}
.overlay( …Issue #674
Specify minWidth to ensure miminum width, and use .layoutPriority(1) for the most important pane.
import SwiftUI
struct MainView: View {
@EnvironmentObject var store: Store
var body: some View {
HSplitView { …Issue #673
To draw rounded 2 corners at top left and top right, let’s start from bottom left
let path = UIBezierPath()
// bottom left
path.move(to: CGPoint(x: 0, y: bounds.height))
// top left corner
path.addArc(withCenter: CGPoint(x: radius, y …Issue #672
Supposed we want to stitch magazines array into books array. The requirement is to sort them by publishedDate, but must keep preferredOrder of books. One way to solve this is to declare an enum to hold all possible cases, and then do a …
Issue #671
Use adjustsFontForContentSizeCategory
A Boolean that indicates whether the object automatically updates its font when the device’s content size category changes.
If you set this property to YES, the element adjusts for a new …
Issue #670
To test for viewWillDisappear during UINavigationController popViewController in unit test, we need to simulate UIWindow so view appearance works.
final class PopTests: XCTestCase {
func testPop() {
let window = UIWindow(frame: …Issue #660
Apply tintColor does not seem to have effect.
datePicker.setValue(UIColor.label, forKeyPath: "textColor")
datePicker.setValue(false, forKey: "highlightsToday")
Issue #656
Lately I’ve been challenging myself to declare switch statement in SwiftUI, or in a more generalized way, execute any anonymous function that can return a View
Note that this approach does not work yet, as …
Issue #646
Pass DispatchQueue and call queue.sync to sync all async works before asserting
Use DispatchQueueType and in mock, call the work immediately
import Foundation
public protocol DispatchQueueType {
func …Issue #644
import XCTest
extension XCTestCase {
/// Asynchronously assertion
func XCTAssertWait(
timeout: TimeInterval = 1,
_ expression: @escaping () -> Void,
_: String = "",
file _: StaticString = …Issue #639
Never use String(format: "%.2f %%", 1.2 because each region can have different separator and placement of percent sign.
Use NumberFormatter instead
let formatter = NumberFormatter()
formatter.numberStyle = .percent
formatter. …Issue #638
Use commandDefinitions in XCSourceEditorExtension.
import Foundation
import XcodeKit
class SourceEditorExtension: NSObject, XCSourceEditorExtension {
func extensionDidFinishLaunching() {
}
var commandDefinitions: [[ …Issue #638
Use commandDefinitions in XCSourceEditorExtension.
import Foundation
import XcodeKit
class SourceEditorExtension: NSObject, XCSourceEditorExtension {
func extensionDidFinishLaunching() {
}
var commandDefinitions: [[ …Issue #636
Normally we can just wrap NSTextField
struct SearchTextField: NSViewRepresentable {
@Binding var text: String
var hint: String
var onCommit: (String) -> Void
func makeNSView(context: NSViewRepresentableContext< …Issue #635
textField.delegate = self
NSTextFieldDelegate
func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
if (commandSelector == #selector(NSResponder.insertNewline(_:))) {
// …Issue #634
public enum Weapon: String, Decodable {
case sword = "SWORD"
case gun = "GUN"
case unknown = "UNKNOWN"
public init(from decoder: Decoder) throws {
let rawValue = try decoder. …Issue #633
Use autoclosure and AnyView
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public extension View {
func applyIf<T: View>(_ condition: @autoclosure () -> Bool, apply: (Self) -> T) -> AnyView {
if …Issue #630
For SwiftUI app using NSPopover, to show context popover menu, we can ask for windows array, get the _NSPopoverWindow and calculate the position. Note that origin of macOS screen is bottom left
(lldb) po NSApp.windows
▿ 2 elements
- 0 : …Issue #628
extension XCUIElementQuery: Sequence {
public typealias Iterator = AnyIterator<XCUIElement>
public func makeIterator() -> Iterator {
var index = UInt(0)
return AnyIterator {
guard index < …Issue #627
Algorithm from https://www.w3.org/WAI/ER/WD-AERT/#color-contrast
extension NSColor {
var isLight: Bool {
guard
let components = cgColor.components,
components.count >= 3
else { return false } …Issue #626
SwiftUI does not trigger onAppear and onDisappear like we expect. We can use NSView to trigger
import SwiftUI
struct AppearAware: NSViewRepresentable {
var onAppear: () -> Void
func makeNSView(context: …Issue #625
For some strange reasons, content inside ForEach does not update with changes in Core Data NSManagedObject. The workaround is to introduce salt, like UUID just to make state change
struct NoteRow: View {
let note: Note
let id: UUID …Issue #624
By default the approaches above grant you access while the app remains open. When you quit the app, any folder access you had is lost.
To gain persistent access to a folder even on subsequent launches, we’ll have to take advantage of a …
Issue #622
Read Implementing Batch Deletes
If the entities that are being deleted are not loaded into memory, there is no need to update your application after the NSBatchDeleteRequest has been executed. However, if you are deleting objects in the …
Issue #620
For NSWindow having levelother than .normal, need to override key and main property to allow TextField to be focusable
class FocusWindow: NSWindow {
override var canBecomeKey: Bool { true }
override var canBecomeMain: Bool { …Issue #618
Create custom Binding
List {
ForEach(self.items) { (item: item) in
ItemRowView(item: item)
.popover(isPresented: self.makeIsPresented(item: item)) {
ItemDetailView(item: item)
}
}
} …Issue #617
On macOS 11, we can use .help modifier to add tooltip
Button()
.help("Click here to open settings")
If you support macOS 10.15, then create empty NSView and use as overlay. Need to updateNSView in case we toggle the state of …
Issue #614
struct MyTabView: View {
@EnvironmentObject
var preferenceManager: PreferenceManager
var body: some View {
VOrH(isVertical: preferenceManager.preference.position.isVertical) {
OneTabView(image: …Issue #612
Use runModal
This method runs a modal event loop for the specified window synchronously. It displays the specified window, makes it key, starts the run loop, and processes events for that window. (You do not need to show the window …
Issue #611
enum WindowPosition: String, CaseIterable {
case left
case top
case bottom
case right
}
Picker(selection: $preference.position, label: Text("Position")) {
ForEach(WindowPosition.allCases, id: \.self) { …Issue #610
Set NSVisualEffectView as contentView of NSWindow, and our main view as subview of it. Remember to set frame or autoresizing mask as non-direct content view does not get full size as the window
let mainView = MainView()
.environment(\. …Issue #609
Use animator proxy and animate parameter
var rect = window.frame
rect.frame.origin.x = 1000
NSAnimationContext.runAnimationGroup({ context in
context.timingFunction = CAMediaTimingFunction(name: .easeIn)
window.animator().setFrame( …Issue #608
An NSRunningApplication instance for the current application.
NSRunningApplication.current
The running app instance for the app that receives key events.
NSWorkspace.shared.frontmostApplication
Issue #607
Implement Equatable and Comparable and use round
struct RGBA: Equatable, Comparable {
let red: CGFloat
let green: CGFloat
let blue: CGFloat
let alpha: CGFloat
init(_ red: CGFloat, _ green: CGFloat, _ blue: CGFloat, _ …Issue #606
Use ObjectIdentifier
A unique identifier for a class instance or metatype.
final class Worker: Hashable {
static func == (lhs: Worker, rhs: Worker) -> Bool {
return ObjectIdentifier(lhs) == ObjectIdentifier(rhs)
} …Issue #605
I use custom TextView in a master detail application.
import SwiftUI
struct TextView: NSViewRepresentable {
@Binding var text: String
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeNSView …Issue #603
Need to set correct frame for mask layer or UILabel, as it is relative to the coordinate of the view to be masked
let aView = UIView(frame: .init(x: 100, y: 110, width: 200, height: 100))
let textLayer = CATextLayer()
textLayer. …Issue #602
ForEach(store.blogs.enumerated().map({ $0 }), id: \.element.id) { index, blog in
}
```
##
Issue #600
Use same CACurrentMediaTime
final class AnimationSyncer {
static let now = CACurrentMediaTime()
func makeAnimation() -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: "opacity")
animation. …Issue #599
Specify tag
enum Authentication: Int, Codable {
case key
case certificate
}
TabView(selection: $authentication) {
KeyAuthenticationView()
.tabItem {
Text("🔑 Key")
}
.tag( …Issue #598
It’s hard to see any iOS app which don’t use UITableView or UICollectionView, as they are the basic and important foundation to represent data. UICollectionView is very basic to use, yet a bit tedious for common use cases, but …
Issue #597
TextView(font: R.font.text!, lineCount: nil, text: $text, isFocus: $isFocus)
.padding(8)
.background(R.color.inputBackground)
.cornerRadius(10)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(isFocus ? R.color. …Issue #596
UNUserNotificationCenter.current().getNotificationSettings(completionHandler: { (settings: UNNotificationSettings) in
let status: UNAuthorizationStatus = .authorized
settings.setValue(status.rawValue, forKey: …Issue #594
In some case, we should not use base type like UTType.text but to be more specific like UTType.utf8PlainText
import UniformTypeIdentifiers
var dropTypes: [UTType] {
[
.fileURL,
.url,
.utf8PlainText,
. …Issue #592
Hard to customize
Picker(selection: Binding<Bool>.constant(true), label: EmptyView()) {
Text("Production").tag(0)
Text("Sandbox").tag(1)
}.pickerStyle(RadioGroupPickerStyle())
Issue #590
Use custom NSTextField as it is hard to customize TextFieldStyle
import SwiftUI
struct MaterialTextField: View {
let placeholder: String
@Binding var text: String
@State var isFocus: Bool = false
var body: some View { …Issue #589
import SwiftUI
struct MyTextField: View {
@Binding
var text: String
let placeholder: String
@State
private var isFocus: Bool = false
var body: some View {
FocusTextField(text: $text, …Issue #589
class FocusAwareTextField: NSTextField {
var onFocusChange: (Bool) -> Void = { _ in }
override func becomeFirstResponder() -> Bool {
let textView = window?.fieldEditor(true, for: nil) as? …Issue #588
class FocusAwareTextField: NSTextField {
var onFocus: () -> Void = {}
var onUnfocus: () -> Void = {}
override func becomeFirstResponder() -> Bool {
onFocus()
let textView = window?.fieldEditor(true, …Issue #587
From https://github.com/twostraws/ControlRoom/blob/main/ControlRoom/NSViewWrappers/TextView.swift
import SwiftUI
/// A wrapper around NSTextView so we can get multiline text editing in SwiftUI.
struct TextView: …Issue #586
Add fonts to target. In Info.plist, just need to specify font locations, most of the time they are at Resources folder
ATSApplicationFontsPath (String - macOS) identifies the location of a font file or directory of fonts in the …
Issue #583
In UITests, we can use press from XCUIElement to test drag and drop
let fromCat = app.buttons["cat1"].firstMatch
let toCat = app.buttons["cat2"]
let fromCoordinate = fromCat.coordinate(withNormalizedOffset: CGVector(dx: 0, …Issue #582
Run on device, Xcode -> Debug -> View debugging -> Rendering -> Color blended layer
On Simulator -> Debug -> Color Blended Layer
Issue #580
Implement scene(_:openURLContexts:) in your scene delegate.
If the URL launches your app, you will get …
Issue #579
Use same action, or we can roll our own implementation
An NSButton configured as a radio button (with the -buttonType set to NSRadioButton), will now operate in a radio button group for applications linked on 10.8 and later. To have the …
Issue #578
zh-Hans_HK
[language designator]-[script designator]_[region designator]
A language ID identifies a language used in many regions, a dialect used in a specific region, or a script used in …
Issue #577
objc[45250]: Class AVAssetDownloadTask is implemented in both /Applications/Xcode.app/Contents/Developer/Platforms/ …Issue #576
See Spek
https://developer.apple.com/documentation/xctest/xctestcase/1496271-testinvocations
Returns an array of invocations representing each test method in the test case.
Because …
Issue #575
Check for example _runtime(_ObjC) or os(macOS if you plan to use platform specific feature …
Issue #574
expr -l Swift -- import UIKit
expr -l Swift -- let $collectionView = unsafeBitCast(0x7fddd8180000, to: UICollectionView.self)
expr -l Swift -- $collectionView.safeAreaInsets
Issue #569
From documentation https://developer.apple.com/documentation/uikit/uicollectionviewlayout/1617726-initiallayoutattributesforappear
This method is called after the prepare(forCollectionViewUpdates:) method and before the …
Issue #568
import UIKit
var mapping: [String: (UIViewController) -> Void] = [:]
var hasSwizzled = false
public func track< …Issue #567
import UIKit
public protocol AdapterDelegate: class {
/// Apply model to view
func configure(model: Any, view: UIView, indexPath: IndexPath)
/// Handle …Issue #566
public class HUDContainer: UIVisualEffectView, AnimationAware {
private let innerContentView: UIView & AnimationAware
public let label = UILabel()
public var …Issue #564
Step 1: Create executable
swift package init --type executable
Step 2: Edit package
// swift-tools-version:5.1
// The …Issue #562
Timer.scheduledTimer(withTimeInterval: seconds, repeats: false, block: { _ in
completion(.success(()))
})
RunLoop.current.run()
Issue #560
After adding bot to …
Issue #559
public class GetDestinations {
public init() {}
public func getAvailable(workflow: Workflow) throws -> [Destination] {
let processHandler = DefaultProcessHandler(filter: { $0.starts(with: "name=") })
let …Issue #558
public class GetDestinations {
public init() {}
public func getAvailable(workflow: Workflow) throws -> [Destination] {
let processHandler = DefaultProcessHandler(filter: { $0.starts(with: "name=") })
let …Issue #556
Instead of learning XMLParser, we can make a lightweight version
import Foundation
public protocol XmlItem {
func toLines() -> [String]
}
public struct XmlString: XmlItem {
public let key: String
public let value: String …Issue #554
A class must inherit from NSObject, and we have 3 ways to trigger property change
Use setValue(value: AnyObject?, forKey key: String) from NSKeyValueCoding
class MyObjectToObserve: NSObject {
var myDate = NSDate()
func …
Issue #553
Read Swift asserts - the missing manual
debug release release
function -Onone -O -Ounchecked
assert() YES NO NO
assertionFailure() YES NO NO** …Issue #551
import Foundation
public extension String {
func matches(pattern: String) throws -> [String] {
let regex = try NSRegularExpression(pattern: pattern)
let results = regex.matches(in: self, options: [], …Issue #549
public class Sequence: Task {
public func run(workflow: Workflow, completion: @escaping TaskCompletion) {
let semaphore = DispatchSemaphore(value: 0)
runFirst(tasks: tasks, workflow: workflow, completion: …Issue #547
func sync<T>(_ work: (@escaping ([T]) -> Void) -> Void) -> [T] {
let semaphore = DispatchSemaphore(value: 1)
var results = [T]()
work { values in
results = values
semaphore.signal()
} …Issue #542
See code Puma
Build is UsesXcodeBuild is UsesCommandLine
/// Any task that uses command line
public protocol UsesCommandLine: AnyObject {}
public extension UsesCommandLine {
func runBash(
workflow: …Issue #533
struct ContentView: View {
@Environment(\.locale) var locale: Locale
var body: some View {
VStack {
Text(LocalizedStringKey("hello"))
.font(.largeTitle)
Text(flag(from: …Issue #532
func flag(from country: String) -> String {
let base : UInt32 = 127397
var s = ""
for v in country.uppercased().unicodeScalars {
s.unicodeScalars.append(UnicodeScalar(base + v.value)!)
}
return s
} …Issue #528
A lens is a first-class reference to a subpart of some data type. For instance, we have _1 which is the lens that …
Issue #527
import Foundation
import Combine
public typealias TaskCompletion = (Result<(), Error>) -> Void
public protocol Task: AnyObject {
var name: String { get }
func run(workflow: Workflow, completion: TaskCompletion)
}
public …Issue #526
public class Build: UsesXcodeBuild {
public var arguments = [String]()
public init(_ closure: (Build) -> Void = { _ in }) {
closure(self)
}
}
public class Workflow {
public var …Issue #525
Example Puma

Puma.xcodeproj as a sub project of our test projectLink Binary with Libraries, select Puma framework …Issue #524
/// Any task that uses command line
public protocol UsesCommandLine: AnyObject {
var program: String { get }
var arguments: Set<String> { get set }
}
public extension UsesCommandLine {
func run() throws {
let …Issue #523
In Puma I want to make build tools for iOS and Android, which should share some common infrastructure. So we can organize dependencies like.
Puma -> PumaAndroid, PumaiOS -> PumaCore -> xcbeautify, Files, Colorizer
// …Issue #522
Sometimes ago I created Puma, which is a thin wrapper around Xcode commandline tools, for example xcodebuild
There’s lots of arguments to pass in xcodebuild, and there are many tasks like build, test and archive that all uses this …
Issue #518
let userDefaults = UserDefaults(suiteName: suiteName)
userDefaults.removePersistentDomain(forName: suiteName)
https://developer.apple.com/documentation/foundation/userdefaults/1417339-removepersistentdomain
Calling this method is …
Issue #510
Use Dictionary(grouping:by:)
func groups(countries: [Country]) -> [Group] {
let dictionary = Dictionary(grouping: countries, by: { String($0.name.prefix(1)) })
let groups = dictionary
.map({ (key: String, value: [Country …Issue #506
When a function expects AnyPublisher<[Book], Error> but in mock, we have Just
func getBooks() -> AnyPublisher<[Book], Error> {
return Just([
Book(id: "1", name: "Book 1"),
Book(id: …Issue #504
https://twitter.com/NeoNacho/status/1181245484867801088?s=20
There’s no way to have platform specific sources or targets today, so you’ll have to take a different approach. I would recommend wrapping all OS specific files in #if os and …
Issue #493
Declare in Podfile
pod 'Firebase/Core'
pod 'Firebase/RemoteConfig'
Use RemoteConfigHandler to encapsulate logic. We introduce Key with CaseIterable and defaultValue of type NSNumber to manage default values.
import Firebase …Issue #485
The easiest way to show image picker in iOS is to use UIImagePickerController, and we can bridge that to SwiftUI via UIViewControllerRepresentable
We conform to UIViewControllerRepresentable and make a …
Issue #483
Every item in list must be uniquely identifiable
List {
ForEach(books, id: \.bookId) { book in
NavigationLink(destination:
BookView(book: book)
.navigationBarTitle(book.name)
) { …Issue #479
From ISO8601 spec, the problems are the representation and time zone
ISO 8601 = year-month-day time timezone
For date and time, there are basic (YYYYMMDD, hhmmss, ...) and extended format (YYYY-MM-DD, hh:mm:ss, ...)
Time zone can be Zulu, …Issue #477
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public extension View {
}
#if canImport(UIKit)
import UIKit
#elseif canImport(OSX)
import AppKit
#endif
In watchOS app, it still can import …
Issue #475
For a snack bar or image viewing, it’s handy to be able to just flick or toss to dismiss
We can use UIKit Dynamic, which was introduced in iOS 7, to make this happen.
Use UIPanGestureRecognizer to drag view around, UISnapBehavior to …
Issue #474
Go to Project -> Swift Packages, add package. For example https://github.com/onmyway133/EasyStash
Select your WatchKit Extension target, under Frameworks, Libraries and Embedded Content add the library
If we use CocoaPods, …
Issue #473
Use UIScreen.didConnectNotification
NotificationCenter.default.addObserver(forName: UIScreen.didConnectNotification,
object: nil, queue: nil) { (notification) in
// Get the new screen …Issue #472
Use convenient code from Omnia
To make view height dynamic, pin UILabel to edges and center
import UIKit
final class ErrorMessageView: UIView {
let box: UIView = {
let view = UIView()
view. …Issue #471
let navigationController = UINavigationController(rootViewController: viewControllerA)
navigationController.pushViewController(viewControllerB, animated: true)
In view controller B, need to set hidesBottomBarWhenPushed in init
final class …Issue #470
Use NSTextAttachment inside NSAttributedString
extension UILabel {
func addTrailing(image: UIImage) {
let attachment = NSTextAttachment()
attachment.image = image
let attachmentString = NSAttributedString( …Issue #469
If there are lots of logics and states inside a screen, it is best to introduce parent and child container, and switch child depends on state. Each child acts as a State handler.
In less logic case, we can introduce a Scenario class that …
Issue #465
Use EasyStash
import EasyStash
final class Store<T: Codable & ItemProtocol>: Codable {
var items = [T]()
func bookmark(item: T) {
items.append(item)
}
func unbookmark(item: T) {
guard let index …Issue #464
typealias Completion = (Result<User, Error>) -> Void
func validate(completion: @escaping Completion, then: (String, String, @escaping Completion) -> Void) {}
Issue #463
func zoom(location1: CLLocation, location2: CLLocation) {
let bounds = GMSCoordinateBounds(coordinate: location1.coordinate, coordinate: location2.coordinate)
let update = GMSCameraUpdate.fit(bounds, withPadding: 16)
mapView. …Issue #462
Using object, we don’t need to care about nil vs false like in UserDefaults, our object is the source of truth
class StoringHandler<T: Codable> {
private let key: Storage.Keys
private let storage = Deps.storage …Issue #461
With UIAlertController we can add buttons and textfields, and just that
func addAction(UIAlertAction)
func addTextField(configurationHandler: ((UITextField) -> Void)?)
To add custom content to UIAlertController, there are some …
Issue #460
extension UIView {
func findRecursively<T: UIView>(type: T.Type, match: (T) -> Bool) -> T? {
for view in subviews {
if let subview = view as? T, match(subview) {
return subview …Issue #456
From WWDC 2018 What’s New in User Notifications
Instead, the notifications from your app will automatically start getting delivered.
Notifications that are delivered with provisional authorization will have a prompt like this on …
Issue #455
There are times we want to log if user can receive push notification. We may be tempted to merely use isRegisteredForRemoteNotifications but that is not enough. From a user ’s point of view, they can either receive push notification …
Issue #453
From documentation
A type-erased hashable value.
DiscussionThe AnyHashable type forwards equality comparisons and hashing operations to an underlying hashable value, hiding its specific underlying type.You can store mixed-type keys in …
Issue #452
Use UserNotifications framework
import FirebaseMessaging
import UserNotifications
final class PushHandler: NSObject {
private let center = UNUserNotificationCenter.current()
private let options: UNAuthorizationOptions = [.alert] …Issue #451
For some services, we need to deal with separated APIs for getting ids and getting detail based on id.
To chain requests, we can use flatMap and Sequence, then collect to wait and get all elements in a single publish
Transforms …
Issue #450
Following the signatures of ScrollView and Group, we can create our own container
public struct ScrollView<Content> : View where Content : View {
/// The content of the scroll view.
public var content: Content
}
extension …Issue #446
Suppose we have Service protocol, and want to use in List
protocol Service {
var name: String { get }
}
struct MainView: View {
let services = [
Car()
Plane()
]
var body: some View {
List(services) …Issue #445
Run swift package init
Check enum for version for each platform https://developer.apple.com/documentation/swift_packages/supportedplatform/tvosversion
Example …
Issue #444
To avoid compiler error Unprintable ASCII character found in source file, from Swift 5, we can use isASCII.
Run this from the generator app that generates Swift code.
let normalized = weirdString.filter({ $0.isASCII })
For more check, see …
Issue #443
let textField = NSTextField()
textField.focusRingType = .none
let textView = NSTextView()
textView.insertionPointColor = R.color.caret
textView.isRichText = false
textView.importsGraphics = false
textView.isEditable = true
textView. …Issue #442
On macOS, coordinate origin is bottom left
let window = NSWindow(contentRect: rect, styleMask: .borderless, backing: .buffered, defer: false)
window.center()
let frame = window.frame
window.setFrameOrigin(CGPoint(x: frame.origin.x, y: 100 …Issue #441
Make object conform to Equatable and Hashable and use Set to eliminate duplications. Set loses order so we need to sort after uniquing
struct App: Equatable, Hashable {
static func == (lhs: App, rhs: App) -> Bool {
return …Issue #439
We need to provide NSLocalizedDescriptionKey inside user info dictionary, otherwise the outputt string may not be what we want.
Issue #438
In Storyboard, NSTextField has an Action option that specify whether Send on Send on Enter only` should be the default behaviour.

In code, NSTextFieldDelegate notifies whenever text field value changes, and target action …
Issue #437
Use Omnia for itemId extension
HeaderCell.swift
final class HeaderCell: NSView, NSCollectionViewSectionHeaderView {
let label: NSTextField = withObject(NSTextField(labelWithString: "")) {
$0.textColor = R.color. …Issue #435
Use NSMenu and popUp
func showQuitMenu() {
let menu = NSMenu()
let aboutItem = NSMenuItem(
title: "About",
action: #selector(onAboutTouched(_:)),
keyEquivalent: ""
)
let quitItem = …Issue #434
When calling collectionView.reloadData(), selected indexpath stays the same, but be aware that order of data may have changed
let selectedData = ...
let indexPathForSelectedData = ...
collectionView.scrollToItem(
at: …Issue #433
style and isOn propertylet checkButton = NSButton(checkboxWithTitle: "", target: nil, action: nil)
checkButton.stylePlain(title: "Autosave", color: R.color.text, font: R.font.text)
checkButton. …Issue #432
Read Container Directories and File System Access
When you adopt App Sandbox, your application has access to the following locations:
The app container directory. Upon first launch, the operating system creates a special directory for …
Issue #429
Use https://github.com/markedjs/marked
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Marked in the browser</title>
</head>
<body>
<div id="content" …Issue #428
Need to set target
let item = NSMenuItem(
title: title,
action: #selector(onMenuItemClicked(_:)),
keyEquivalent: ""
)
item.target = self
Sometimes, need to check autoenablesItems
Indicates whether the menu …
Issue #427
Use ClickedCollectionView to detect clicked index for context menu.
Embed NSCollectionView inside NSScrollView to enable scrolling
import AppKit
public class CollectionViewHandler<Item: Equatable, Cell: …Issue #426
https://rxmarbles.com/#throttle
Returns an Observable that emits the first and the latest item emitted by the source Observable during sequential time windows of a specified duration. This operator makes sure that no two …
Issue #425
flatMap: map and flatten array of arrays
compactMap: map and flatten array of optionals
Issue #422
To constrain views outside to elements inside UICollectionViewCell, we can use UILayoutGuide.
Need to make layout guide the same constraints as the real elements
let imageViewGuide = UILayoutGuide()
collectionView.addLayoutGuide( …Issue #421
private func maskCvcIfAny() {
guard
let view = paymentTextField.subviews.first(where: { !($0 is UIImageView) }),
let cvcField = view.subviews
.compactMap({ $0 as? UITextField })
.first(where: { $0.tag == 2 …Issue #414
Codable is awesome, but sometimes we just need to quickly get value in a deepy nested JSON. In the same way I did for Dart How to resolve deep json object in Dart, let’s make that in Swift.
See …
Issue #412
When the value of this property is true, the …
Issue #411
class ViewController: UIViewController, UICollectionViewDropDelegate, UICollectionViewDragDelegate {
// MARK: - UICollectionViewDragDelegate
func collectionView(_ collectionView: UICollectionView, …Issue #410
import AppKit
import Anchors
class DraggingView: NSView {
var didDrag: ((FileInfo) -> Void)?
let highlightView = NSView()
override init(frame frameRect: NSRect) {
super.init(frame: frameRect) …Issue #409
let stepper = NSStepper()
let textField = NSTextField(wrappingLabelWithString: "\(myLocalCount)")
stepper.integerValue = myLocalCount
stepper.minValue = 5
stepper.maxValue = 24
stepper.valueWraps = false
stepper.target = self …Issue #408
Podfile
pod 'MASShortcut'
let shortcut = MASShortcut(keyCode: kVK_ANSI_K, modifierFlags: [.command, .shift])
MASShortcutMonitor.shared()?.register(shortcut, withAction: {
self.showPopover(sender: self.statusItem.button)
})
Issue #407
https://developer.apple.com/documentation/appkit/nsworkspace/1524399-selectfile
In macOS 10.5 and later, this method does not follow symlinks when selecting the file. If the fullPath parameter contains any symlinks, this method selects …
Issue #406
let progressIndicator = NSProgressIndicator()
progressIndicator.isIndeterminate = true
progressIndicator.style = .spinning
progressIndicator.startAnimation(nil)
Issue #405
Enable Read/Write for User Selected File under Sandbox to avoid bridge absent error
func showSave(
name: String,
window: NSWindow
) async -> URL? {
let panel = NSSavePanel()
panel.directoryURL = FileManager.default. …Issue #404
let animation = CAKeyframeAnimation(keyPath: "position.y")
animation.values = [50, 20, 50]
animation.keyTimes = [0.0, 0.5, 1.0]
animation.duration = 2
animation.repeatCount = Float.greatestFiniteMagnitude
animation.autoreverses = …Issue #403
The application sends this message to your delegate when the application’s last window is closed. It sends this …
Issue #402
I want to test if a date has passed another date
let base = Date(timeIntervalSince1970: 1567756697)
XCTAssertEqual(validator.hasPassed(event: event, date: base), true)
My hasPassed is using Calendar.current
func minuteSinceMidnight(date: …Issue #395
Prefer static enum to avoid repetition and error. The Log should have methods with all required fields so the call site is as simple as possible. How to format and assign parameters is encapsulated in this Analytics.
import Foundation …Issue #377
OneSignal is an alternative for Parse for push notifications but the sdk has many extra stuff and assumptions and lots of swizzling.
We can just use Rest to make API calls. From https://github.com/onmyway133/Dust
Every official push …
Issue #376
https://github.com/onmyway133/Omnia/blob/master/Sources/Shared/Debouncer.swift
import Foundation
public class Debouncer {
private let delay: TimeInterval
private var workItem: DispatchWorkItem?
public init(delay: TimeInterval …Issue #375
final class LifecyclerHandler {
private var observer: AnyObject!
var action: (() -> Void)?
private let debouncer = Debouncer(delay: 1.0)
func setup() {
observer = NotificationCenter.default.addObserver( …Issue #374
Add accessibilityIdentifier to the parent view of GMSMapView. Setting directly onto GMSMapView has no effect
accessibilityIdentifier = "MapView"
let map = app.otherElements.matching(identifier: …Issue #373
UIButton.contentEdgeInsets does not play well with Auto Layout, we need to use intrinsicContentSize
final class InsetButton: UIButton {
required init(text: String) {
super.init(frame: .zero)
titleLabel?.textColor = . …Issue #371
Scrolling UIScrollView is used in common scenarios like steps, onboarding.
From iOS 11, UIScrollView has contentLayoutGuide and frameLayoutGuide
https://developer.apple.com/documentation/uikit/uiscrollview/2865870-contentlayoutguide …
Issue #368
See https://github.com/onmyway133/Omnia/blob/master/Sources/iOS/NSLayoutConstraint.swift
extension NSLayoutConstraint {
/// Disable auto resizing mask and activate constraints
///
/// - Parameter constraints: constraints to …Issue #365
import WebKit
import SafariServices
final class WebViewHandler: NSObject, WKNavigationDelegate {
var show: ((UIViewController) -> Void)?
let supportedSchemes = ["http", "https"]
func webView(_ webView: …Issue #364
AppFlowController.swift
import UIKit
import GoogleMaps
import Stripe
final class AppFlowController: UIViewController {
private lazy var window = UIWindow(frame: UIScreen.main.bounds)
func configure() {
GMSServices. …Issue #362
let tapGR = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
@objc private func handleTap(_ gr: UITapGestureRecognizer) {
didTouch?()
}
We need to use lazy instead of let for gesture to work
lazy var tapGR = …Issue #361
protocol Task {}
struct Build: Task {}
struct Test: Task {}
@_functionBuilder
public struct TaskBuilder {
public static func buildBlock(_ tasks: Task...) -> [Task] {
tasks
}
}
public func run(@TaskBuilder builder: () …Issue #360
Given a streaming service
service Server {
rpc GetUsers(GetUsersRequest) returns (stream GetUsersResponse);
}
To get a response list in Swift, we need to do observe stream, which is a subclass of ClientCallServerStreaming
func getUsers( …Issue #356
StripeHandler.swift
From Stripe 16.0.0 https://github.com/stripe/stripe-ios/blob/master/CHANGELOG.md#1600-2019-07-18
Migrates STPPaymentCardTextField.cardParams property type from STPCardParams to STPPaymentMethodCardParams
final class …Issue #355
final class CurrencyFormatter {
func format(amount: UInt64, decimalCount: Int) -> String {
let formatter = NumberFormatter()
formatter.minimumFractionDigits = 0
formatter.maximumFractionDigits = decimalCount …Issue #354
In Construction, we have a build method to apply closure to inout struct.
We can explicitly define that with withValue
func withValue<T>(_ value: T, closure: (inout T) -> Void) -> T {
var mutableValue = value
closure …Issue #350
Read Authenticate with Firebase on iOS using a Phone Number
Info.plist
<key>FirebaseAppDelegateProxyEnabled</key>
<string>NO</string>
Enable Capability -> Background …
Issue #347
Add a hidden UITextField to view hierarchy, and add UITapGestureRecognizer to activate that textField.
Use padding string with limit to the number of labels, and prefix to get exactly n characters.
DigitView.swift
import UIKit
final …Issue #346
We have FrontCard that contains number and expiration date, BackCard that contains CVC. CardView is used to contain front and back sides for flipping transition.
We leverage STPPaymentCardTextField from Stripe for working input fields, …
Issue #345
UIButton with system type has implicit animation for setTitle(_:for:)
Use this method to set the title for the button. The title you specify derives its formatting from the button’s associated label object. If you set both a title and an …
Issue #344
addSubview can trigger viewDidLayoutSubviews, so be careful to just do layout stuff in viewDidLayoutSubviews
This method establishes a strong reference to view and sets its next responder to the receiver, which is its new superview. …
Issue #340
https://nshipster.com/formatter/#datecomponentsformatter
Results in no padding 0
func format(second: TimeInterval) -> String? {
let formatter = DateComponentsFormatter()
formatter.unitsStyle = . …Issue #337
Normally we just present from any UIViewController in any UINavigationController in UITabBarController and it will present over tabbar
present(detailViewController, animated: true, completion: nil)
If we have animation with …
Issue #336
Use NSPopUpButton
var pullsDown: Bool
A Boolean value indicating whether the button displays a pull-down or pop-up menu.
func addItem(withTitle: String)
Adds an item with the specified title to the end of the menu.
Should disable …
Issue #335
This is useful when we want to get the first meaningful line in a big paragraph
let scanner = Scanner(string: text)
var result: NSString? = ""
scanner.scanUpTo("\n", into: &result)
return result as String?
Issue #334
NSSecureCoding has been around since iOS 6 and has had some API changes in iOS 12
A protocol that enables encoding and decoding in a manner that is robust against object substitution attacks. …
Issue #333
In a traditional pager with many pages of content, and a bottom navigation with previous and next button. Each page may have different content, and depending on each state, may block the next button.
The state of next button should state …
Issue #332
From moveItem(at:to:)
Moves an item from one location to another in the collection view.
After rearranging items in your data source object, use this method to synchronize those changes with the collection view. Calling this method lets …
Issue #331
From NSSegmentedControl
The features of a segmented control include the following: A segment can have an image, text (label), menu, tooltip, and tag. A segmented control can contain images or text, but not both.
let languageMenu = NSMenu( …Issue #330
When adding NSTextView in xib, we see it is embedded under NSClipView. But if we try to use NSClipView to replicate what’s in the xib, it does not scroll.
To make it work, we can follow Putting an NSTextView Object in an NSScrollView …
Issue #329
Firstly, to make UIStackView scrollable, embed it inside UIScrollView. Read How to embed UIStackView inside UIScrollView in iOS
It’s best to listen to keyboardWillChangeFrameNotification as it contains frame changes for Keyboard in …
Issue #328
Sometimes we want to validate forms with many fields, for example name, phone, email, and with different rules. If validation fails, we show error message.
We can make simple Validator and Rule
class Validator {
func validate(text: …Issue #327
In terms of tests, we usually have files for unit test, UI test, integeration test and mock.
Out of sight, out of mind.
Unit tests are for checking specific functions and classes, it’s more convenient to browse them side by side …
Issue #326
Traditionally, from Swift 4.2 we need guard let self
addButton.didTouch = { [weak self] in
guard
let self = self,
let product = self.purchasedProduct()
else {
return
self.delegate?.productViewController …Issue #325
UILabel as placeholder and move itoffsetX for translation is 10%Issue #324
view.addSubview(scrollView)
scrollView.addSubview(stackView)
NSLayoutConstraint.on([
scrollView.pinEdges(view: view),
stackView.pinEdges(view: scrollView)
])
NSLayoutConstraint.on([
stackView.widthAnchor.constraint(equalTo: …Issue #323
Use proxy animator()
let indexPath = IndexPath(item: index, section: 0)
collectionView.animator().deleteItems(at: Set(arrayLiteral: indexPath))
let indexPath = IndexPath(item: 0, section: 0)
collectionView.animator().insertItems(at: Set( …Issue #322
lazy var gr = NSClickGestureRecognizer(target: self, action: #selector(onPress(_:)))
gr.buttonMask = 0x2
gr.numberOfClicksRequired = 1
view.addGestureRecognizer(gr)
Issue #321
class ClickedCollectionView: NSCollectionView {
var clickedIndex: Int?
override func menu(for event: NSEvent) -> NSMenu? {
clickedIndex = nil
let point = convert(event. …Issue #320
NSTextAttachmentCellProtocolRich Text and GraphicsIssue #319
ATSApplicationFontsPath …
Issue #318
I do UI in code, and usually separate between View and ViewController.
class ProfileView: UIView {}
class ProfileViewController: UIViewController {
override func loadView() {
self.view = ProfileView()
}
}
But in places where …
Issue #315
extension PanCollectionViewController: UIGestureRecognizerDelegate {
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
let velocity = panGR.velocity(in: panGR.view)
return abs( …Issue #312
class ClosableWindow: NSWindow {
override func close() {
self.orderOut(NSApp)
}
}
let window = ClosableWindow(
contentRect: rect,
styleMask: [.titled, .closable],
backing: .buffered,
defer: false
}
window. …Issue #311
See Omnia https://github.com/onmyway133/Omnia/blob/master/Sources/iOS/UICollectionView.swift#L30
extension HorizontalUsersViewController: UIScrollViewDelegate {
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { …Issue #309
let placemark = MKPlacemark(coordinate: coordinate, addressDictionary: nil)
let mapItem = MKMapItem(placemark: placemark)
mapItem.name = shop.name
mapItem.openInMaps(launchOptions: [:])
Issue #308
If you don’t want to use https://github.com/onmyway133/EasyClosure yet, it’s easy to roll out a closure based UIButton. The cool thing about closure is it captures variables
final class ClosureButton: UIButton {
var …Issue #307
import MapKit
let formatter = MKDistanceFormatter()
formatter.unitStyle = .abbreviated
formatter.units = .metric
distanceLabel.text = formatter.string(fromDistance: distance) // 700m, 1.7km
Issue #306
let json: [String: Any] = [
"id": "123",
"name": "Thor",
"isInMarvel": true
]
let data = try JSONSerialization.data(withJSONObject: json, options: [])
let string = String(data: data, …Issue #305

This year I’m lucky enough to get the ticket to WWDC and I couldn’t be more satisfied. 5 conference days full of awesomeness, talks, labs and networking, all make WWDC special and memorial conference for every attendee.
As …
Issue #303
Instead of setting up custom framework and Playground, we can just display that specific view as root view controller
window.rootViewController = makeTestPlayground()
func makeTestPlayground() -> UIViewController {
let content = …Issue #302
final class CarouselLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard let attributes = super. …Issue #301
Make it more composable using UIViewController subclass and ThroughView to pass hit events to underlying views.
class PanViewController: UIViewController {
var animator = UIViewPropertyAnimator(duration: 0, curve: .easeOut)
lazy …Issue #297
let button = NSButton()
button.wantsLayer = true
button.isBordered = false
button.setButtonType(.momentaryChange)
button.attributedTitle = NSAttributedString(
string: "Click me",
attributes: [
NSAttributedString.Key …Issue #296
Original answer https://stackoverflow.com/a/54793979/1418457
In your NSCollectionViewItem subclass, override isSelected and change background color of the layer. Test in macOS 10.14 and Swift 4.2
class Cell: NSCollectionViewItem { …Issue #288
Use this property to specify a …
Issue #270
As you know, in the Pragmatic Programmer, section Your Knowledge Portfolio, it is said that
Learn at least one new language every year. Different languages solve the same problems in different ways. By learning several different …
Issue #243
From https://developer.apple.com/documentation/coregraphics/1455137-cgwindowlistcopywindowinfo
Generates and returns information about the selected windows in the current user session.
struct MyWindowInfo {
let frame: CGRect
let …Issue #233
Shake
let midX = box.layer?.position.x ?? 0
let midY = box.layer?.position.y ?? 0
let animation = CABasicAnimation(keyPath: "position")
animation.duration = 0.06
animation.repeatCount = 4 …Issue #232
From https://github.com/xhamr/paintcode-path-scale with some updates
extension CGRect {
var center: CGPoint {
return CGPoint( x: self.size.width/2.0,y: self.size.height/2.0)
}
}
extension CGPoint {
func vector(to p1: …Issue #230
CAReplicatorLayer is a layer that creates a specified number of sublayer copies with varying geometric, temporal, and color transformations
Here we use instanceTransform which applies transformation matrix around the center of the …
Issue #229
let animation = CASpringAnimation(keyPath: #keyPath(CALayer.transform))
animation.fromValue = 0
animation.valueFunction = CAValueFunction(name: CAValueFunctionName.rotateZ)
animation.timingFunction = CAMediaTimingFunction(name: …Issue #228
CAAnimation is about presentation layer, after animation completes, the view snaps back to its original state. If we want to keep the state after animation, then the wrong way is to use CAMediaTimingFillMode.forward and …
Issue #227
final class SearchBox: UIView {
lazy var textField: UITextField = {
let textField = UITextField()
let imageView = UIImageView(image: R.image.search()!)
imageView.frame.size = CGSize(width: 20 + 8, height: 20) …Issue #226
Take screenshot
xcrun simctl io booted screenshot image.png
Record video
xcrun simctl io booted recordVideo video.mp4
Issue #225
<key>UIAppFonts</key>
<array>
<string>OpenSans-Bold.ttf</string>
<string>OpenSans-BoldItalic.ttf</string>
<string>OpenSans-ExtraBold.ttf</string>
<string> …Issue #224
let tabBarController = UITabBarController()
let navigationController1 = UINavigationController(rootViewController: viewController1)
let navigationController2 = UINavigationController(rootViewController: viewController2)
let …Issue #222
For more mature networking, visit https://github.com/onmyway133/Miami
final class NetworkClient {
let session: URLSession
let baseUrl: URL
init(session: URLSession = .shared, baseUrl: URL) {
self.session = session …Issue #219
import UIKit
import Stripe
final class MainController: UIViewController {
func showPayment() {
let addCardViewController = …Issue #218
Recorderclass …Issue #216
https://docs.sonarqube.org/latest/setup/get-started-2-minutes/
~/sonarqube~/sonarqube/bin/macosx-universal-64/sonar.sh …Issue #214
extension Result {
func to(subject: PublishSubject<Success>) {
switch self {
case .success(let value):
subject.onNext(value)
case .failure(let error):
subject.onError(error) …Issue #212
Pre iOS 10
func schedule() {
DispatchQueue.main.async {
self.timer = Timer.scheduledTimer(timeInterval: 20, target: self,
selector: #selector(self.timerDidFire(timer:)), userInfo: nil, repeats: …Issue #211
Functions in Swift are distinguishable by
so that these are all valid, and works for subscript as well
struct A {
// return type
func get() -> String { return "" } …Issue #200
let home = NSSearchPathForDirectoriesInDomains(.applicationScriptsDirectory, .userDomainMask, true).first!
let path = home.appending(".XcodeWayExtensions/XcodeWayScript.scpt")
let exists = FileManager.default.fileExists(atPath: …Issue #197
https://grpc.io/docs/quickstart/go.html
Install the protoc compiler that is used to generate gRPC service code. The simplest way to do this is to download pre-compiled binaries for your platform(protoc-
- .zip) from here: …
Issue #195
URLSession offer tons of thing that it’s hard to use with wrappers like AlamofireIssue #194
DispatchWorkItemIssue #193
var components = URLComponents(string: "https://google.com/")
components?.path = "abc/"
components?.url
-> nil
var components = URLComponents(string: "https://google.com/")
components?.path = "/abc/" …Issue #185
You may encounter curry in everyday code without knowing it. Here is a bit of my reflections on curry and how to apply it in Javascript and Swift.
In Haskell, all function officially takes only 1 parameter. …
Issue #176
Enable executable
chmod +x executable
Add executable file to target
Use Process with correct launchPad
import Foundation
protocol TaskDelegate: class {
func task(task: Task, didOutput string: String)
func taskDidComplete(task: Task)
} …Issue #175
let process = Process()
process.launchPath = "/bin/pwd"
process.arguments = []
Should be the same as FileManager.default.currentDirectoryPath
Issue #174
Disable vibrancy mode of NSPopover
let popover = NSPopover()
popover.appearance = NSAppearance(named: NSAppearance.Name.aqua)
Issue #173
You might need to flip NSClipView
import AppKit
import Anchors
import Omnia
final class ScrollableStackView: NSView {
final class FlippedClipView: NSClipView {
override var isFlipped: Bool {
return true
} …Issue #171
var views: NSArray?
NSNib(nibNamed: NSNib.Name("ProfileView"), bundle: nil)?.instantiate(withOwner: nil, topLevelObjects: &views)
let profileView = views!.compactMap({ $0 as? ProfileView }).first!
Issue #154
The most common UI element in iOS is UITableView, and the most common task is to display the UITableViewCell using the model.
Although the title specifies UITableViewCell, but the problem involves other views (UICollectionView, custom …
Issue #148
From https://github.com/devxoul/Pure/blob/master/Sources/Pure/FactoryModule.swift
public protocol FactoryModule: Module {
/// A factory for `Self`.
associatedtype Factory = Pure.Factory<Self>
/// Creates an instance of a …Issue #147
Each language and platform has its own coding style guide. This goes true when it comes to abbreviations. I’ve had some debates about whether to use JSON or Json, URL or Url, HTTP or Http.
I personally prefer camelCase, so I’m …
Issue #144
There are times we want the same UIViewController to look good when it’s presented modally or pushed from UINavigationController stack. Take a look at BarcodeScanner and the PR https://github.com/hyperoslo/BarcodeScanner/pull/82
When …
Issue #140
I need to generate QR code in https://github.com/onmyway133/AddressGenerator. Fortunately with CoreImage filter, it is very easy. Code is in Swift 4
import AppKit
final class QRCodeGenerator {
func generate(string: String, size: CGSize) …Issue #137
Use a custom NavigationController
import UIKit
class NavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
navigationBar.tintColor = .white
navigationBar.barStyle = .black …Issue #131
Here’s how to create NSCollectionView programatically. We need to embed it inside NScrollView for scrolling to work. Code is in Swift 4
let layout = NSCollectionViewFlowLayout()
layout.minimumLineSpacing = 4 …Issue #130
Code is in Swift 4
let byteCount = 32
let result = UnsafeMutablePointer<UInt8>.allocate(capacity: byteCount)
extension Data {
func toPointer() -> UnsafePointer<UInt8 …Issue #124
We all know that there’s a potential crash with UIVisualEffectView on iOS 11. The fix is to not add sub views directly to UIVisualEffectView, but to its contentView. So we should change
effectView.addSubview(button)
to
effectView. …Issue #122
From Set
You can create a set with any element type that conforms to the Hashable protocol. By default, most types in the standard library are hashable, including strings, numeric and Boolean types, enumeration cases without associated …
Issue #121
These are different
class DiffService<T: MKAnnotation & Equatable>
class DiffService<T: MKAnnotation, Equatable>
Issue #119
This is about collection update, how to provide correct IndexPath and a simple diffing algorithm
Issue #113
This is a follow up from my post Learning from Open Source: Using Playground on how to actually add a playground to your production project.
The idea is simple: create a framework so that Playground can access the code. This demo an iOS …
Issue #110
Medium version https://medium.com/@onmyway133/url-routing-with-compass-d59c0061e7e2
Apps often have many screens, and UIViewController works well as the basis for a screen, together with presentation and navigation APIs. Things are fine …
Issue #106
Every new architecture that comes out, either iOS or Android, makes me very excited. I’m always looking for ways to structure apps in a better way. But after some times, I see that we’re too creative in creating architecture, …
Issue #105
Are you willing to take vaccines you don’t know about?
I like open source. I ’ve made some and contributed to some. I also use other people ’s open source libraries and learn a lot from them 😇
Open source can help us …
Issue #99
I’ve been searching for efficient ways to diff collections, here are some interesting papers that I find
Myers
Issue #98
The safeAreaLayoutGuide was introduced in iOS 11. And it is advised to stop using topLayoutGuide bottomLayoutGuide as these are deprecated.
To use safeAreaLayoutGuide, you need to do iOS version check
if #available(iOS 11.0, *) { …Issue #97
The Coordinator pattern can be useful to manage dependencies and handle navigation for your view controllers. It can be seen from BackchannelSDK-iOS, take a look at BAKCreateProfileCoordinator for example
@implementation …Issue #96
Another cool thing about ios-oss is how it manages dependencies. Usually you have a lot of dependencies, and it’s good to keep them in one place, and inject it to the objects that need.
The Environment is simply a struct that holds …
Issue #94
One thing I like about kickstarter-ios is how they use Playground to quickly protoyping views.
We use Swift Playgrounds for iterative development and styling. Most major screens in the app get a corresponding playground where we can see a …
Issue #93
Hi, here is how I indent my code. Let me know what you think 😉
When possible, configure your editor to use 2 spaces for tab size. You will love it ❤️

If there are many parameters, …
Issue #75
We should use DispatchQueue to build thread safe code. The idea is to prevent two read and write from happening at the same time from 2 different threads, which cause data corruption and unexpected behaviors. Note that you should try to …
Issue #58
Do you know that an optional can itself contain an optional, that contains another optional? In that case, we need to unwrap multiple times

You mostly see it when you try to access window
let window = UIApplication.shared.delegate?.window …Issue #54
Today I’m trying to change the year of a Date object to 2000 in Swift.
let date = Date()
Firstly, I tried with date(bySetting:) but it does not work with past year. It simply returns nil
Calendar.current.date(bySetting: .year, value: …Issue #48
Continue my post https://github.com/onmyway133/blog/issues/45. When you work with features, like map view, you mostly need permissions, and in UITests you need to test for system alerts.
This is the code. Note that …
Issue #45
You should mock a location to ensure reliable test
Go to Xcode -> File -> New -> GPX File

It looks like
<?xml version="1.0"?>
<gpx version="1.1" creator="Xcode" …Issue #36
Usually in an app, we have these flows: onboarding, login, main. And we usually set OnboardingController, LoginController and MainController as the root view controller respectively depending on the state.
I find it useful to have the …
Issue #35
Auto Layout is awesome. Just declare the constraints and the views are resized accordingly to their parent ’s bounds changes. But sometimes it does not look good, because we have fixed values for padding, width, height, and even fixed …
Issue #34
In an iOS project, we often see this in AppDelegate
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions …Issue #33
I see that my answer to the question What’s the meaning of Base SDK, iOS deployment target, Target, and Project in xcode gets lots of views, so I think I need to elaborate more about it
Good read
Issue #26
When working on Scale I think it’s good to have a way to group the digit so that it is easier to reason
Luckily, Swift already supports this. See The Swift Programming Language - Numeric Literals
Numeric literals can contain extra …
Issue #24
There is Lighter View Controllers, and there is Lighter AppDelegate, too
Since working with iOS, I really like the delegate pattern, in which it helps us defer the decision to another party.
The iOS application delegates its event to …
Issue #21
The other day I was trying t
Issue #20
The other day I was doing refresh control, and I saw this Swift Protocols with Default Implementations as UI Mixins
extension Refreshable where Self: UIViewController
{
/// Install the refresh control on the table view
func …Issue #17
I always forget how to write correct #available( or #if swift(>=3.0) or just lazy to write required init?(coder aDecoder: NSCoder) every time I make a subclass. That’s why I made SwiftSnippets to save time for these tedious tasks. …
Issue #13
There is time we have models that have some kind of inheritance, like Dog, Cat, Mouse can be Animal. We can use composition to imitate inheritance, we just need to make sure it has unique primary key
These are pretty much basic …
Issue #10
There is time we want to execute an action only once. We can surely introduce a flag, but it will be nicer if we abstract that out using composition. Then we have
class Once {
var already: Bool = false
func run(@noescape block: () …Issue #4
Realm is great. But without primary key, it will duplicate the record, like https://github.com/realm/realm-java/issues/2730, http://stackoverflow.com/questions/32322460/should-i-define-the-primary-key-for-each-entity-in-realm, … So to …
Issue #2
When I was reading through Swinject, I found something interesting https://github.com/Swinject/Swinject/blob/master/Sources/Container.swift
public convenience init(parent: Container? = nil, registeringClosure: (Container) -> Void) { …Issue #1010
It’s hard …
Issue #1009
SwiftUI’s Observation framework makes reactive UI updates effortless—when a property changes, views that depend on it automatically refresh. But what happens when your data lives in UserDefaults? You might want subscription status, …
Issue #1007
Testing in Swift has always required inheriting from XCTestCase and prefixing every method with test. Sound familiar? With Swift 6, Apple introduced Swift Testing — a framework that feels native to modern Swift …
Issue #997
An interesting feature in iOS 26 is the ability to create morph “Liquid Glass” effects, where views with the .glassEffect() modifier can fluidly morph into one another. This is achieved using GlassEffectContainer and the …
Issue #996
When creating widgets for iOS, especially those that need user input to be useful, one common challenge is guiding the user to configure them. Before iOS 18, a user would add a widget, but then would have to know to long-press it and …
Issue #995
With iOS 18, SwiftUI introduces matchedTransitionSource and navigationtransition as a powerful new way to create zoom animations between views. This allows you to smoothly transition from a small view to a larger, more detailed view, …
Issue #994
With iOS 18, Apple introduced a powerful new tool for creating beautiful, dynamic backgrounds: MeshGradient. Forget simple two-color gradients; mesh gradients let you blend a whole grid of colors together smoothly, creating stunning, …
Issue #993
Before iOS 17, if you wanted to animate a number changing, SwiftUI would just fade the old number out and fade the new one in. It worked, but it wasn’t very exciting.
Here’s how that looked:
struct OldCounterView: View {
@ …Issue #992
In the past, making your screen update when data changed in UIKit meant writing extra code, either with didSet, Combine or some other callbacks. Now, it’s automatic.
With the latest iOS 26 updates, UIKit can automatically watch your …
Issue #991
When building apps in SwiftUI or React, we often need to store values that change — like a counter, user input, or a list of items.
To do this:
useState.@State and @StateObject.But here’s something cool: …
Issue #990
In many popular apps like LinkedIn, Reddit, we can tap again on a bar bar item to scroll to top. Although this behavior is not built in by iOS, we can implement that very easily.
The idea is to keep track of previous selection so we can …
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 …Issue #973
Before iOS 11, we used to use CIDetector and CIDetectorTypeQRCode to detect QR code
An image processor that identifies notable features, such as faces and barcodes, in a still image or video.
A detector …
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], …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 …
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 …
Issue #957
Define console object and set log function to point to our Swift function
import JavaScriptCore
extension JSContext {
func injectConsoleLog() {
evaluateScript(
"""
var console = {}; …Issue #956
import Foundation
import SwiftUI
import AppKit
struct AttributedTextView: NSViewRepresentable {
@Binding var attributedText: NSAttributedString
var isEditable: Bool = true
final class Coordinator: NSObject { …Issue #955
Besides WWDC videos & documentation, Apple also has interactive tutorials and books. Below are some of my favorites learning resources
Tutorials
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 …
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( …Issue #937
First, you need to enable iCloud Documents capability. Go to target settings -> Signing & Capabilities -> iCloud
`
Then inside your Info.plist, add this with your iCloud identifier and app name …
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 …
Issue #932
Add Share extension and Action extension respectively in Xcode. We can use the same code to both extension
I usually make a ShareView in SwiftUI with ShareViewModel to control the logic
struct ShareView: View {
@ …Issue #931
Portrait 1290 x 2796
Portrait 1242 x 2688
iOS 640 x 920 tvO 1920 x1080 pixels macOS 1280 x 800 pixels
Issue #930
Declare AppShortcutsProvider, note that appShortcuts uses @AppShortcutsBuilder syntax
import AppIntents
struct OurShortcutsProvider: AppShortcutsProvider {
static var shortcutTileColor: ShortcutTileColor = .lightBlue …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
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. …Issue #919
WWDC23 introduces lots of new additions to SwiftUI, notably Metal shader support with these modifiers
Issue #918
Interesting SwiftUI Q&A during WWDC23
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 …
Issue #916
WWDC23 brings new additions to SwiftUI
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 …
Issue #915
Here are my favorite iOS articles
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() { …Issue #910
let string = "Hello world"
string[string.startIndex...] // Hello world
string[..<string.endIndex] // Hello world
let string = "Hello world"
let range = string.startIndex ..< …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
The usual way to fix this is to defer the decision to the correct …
Issue #905
Protect mutable state with Swift actors
Actor reentrancy
Imagine we have two different concurrent tasks trying to fetch the same image at the same time. The first sees that there is no cache entry, proceeds to start downloading the …
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
Issue #902
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 …
Issue #901
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": { …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 { …Issue #884
When user taps on push notification, depending on app state
Checking UIScene.ConnectionOptions.notificationResponse?.notification.request.content.userInfo in scene(_:willConnectTo:options:)
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> …Issue #879
Initialize Your CloudKit Schema During Development
let …Issue #874
From iOS 13, use UITabBarAppearance and UITabBarItemAppearance
let appearance = UITabBarAppearance()
let itemAppearance = UITabBarItemAppearance(style: .stacked)
itemAppearance.normal.badgeBackgroundColor = .clear
itemAppearance.normal. …Issue #873
Use assistant
let assistant = MCAdvertiserAssistant(serviceType: "my-service, discoveryInfo: nil, session: mcSession)
assistant.start()
let browser = MCBrowserViewController(serviceType: "my-service", session: mcSession) …Issue #856
Use PKPaymentRequest and PKPaymentAuthorizationViewController
@MainActor
final class WalletViewModel: NSObject, ObservableObject {
var canMakePayments: Bool {
PKPaymentAuthorizationViewController.canMakePayments()
} …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 { …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 …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( …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 …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 {
@ …Issue #820
Use NSDataDetector to detect links, and NSMutableAttributedString to mark link range. Then we enumerateAttributes and build our Text
func attribute(string: String) -> Text {
guard let detector = try? NSDataDetector(types: …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 …
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 …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>( …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 …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 …
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 …
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
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 { …Issue #785
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 …
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 …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 …
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
CFBundleIcons with both CFBundlePrimaryIcon and …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, …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> …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 …
Issue #703
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 …
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 …
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) …
Issue #673
To draw rounded 2 corners at top left and top right, let’s start from bottom left
let path = UIBezierPath()
// bottom left
path.move(to: CGPoint(x: 0, y: bounds.height))
// top left corner
path.addArc(withCenter: CGPoint(x: radius, y …Issue #671
Use adjustsFontForContentSizeCategory
A Boolean that indicates whether the object automatically updates its font when the device’s content size category changes.
If you set this property to YES, the element adjusts for a new …
Issue #670
To test for viewWillDisappear during UINavigationController popViewController in unit test, we need to simulate UIWindow so view appearance works.
final class PopTests: XCTestCase {
func testPop() {
let window = UIWindow(frame: …Issue #660
Apply tintColor does not seem to have effect.
datePicker.setValue(UIColor.label, forKeyPath: "textColor")
datePicker.setValue(false, forKey: "highlightsToday")
Issue #631
When your app moves to the background, the system …
Issue #603
Need to set correct frame for mask layer or UILabel, as it is relative to the coordinate of the view to be masked
let aView = UIView(frame: .init(x: 100, y: 110, width: 200, height: 100))
let textLayer = CATextLayer()
textLayer. …Issue #600
Use same CACurrentMediaTime
final class AnimationSyncer {
static let now = CACurrentMediaTime()
func makeAnimation() -> CABasicAnimation {
let animation = CABasicAnimation(keyPath: "opacity")
animation. …Issue #598
It’s hard to see any iOS app which don’t use UITableView or UICollectionView, as they are the basic and important foundation to represent data. UICollectionView is very basic to use, yet a bit tedious for common use cases, but …
Issue #593
#if canImport(Combine) is not enough, need to specify in Other Linker Flags
OTHER_LDFLAGS = -weak_framework Combine
Issue #583
In UITests, we can use press from XCUIElement to test drag and drop
let fromCat = app.buttons["cat1"].firstMatch
let toCat = app.buttons["cat2"]
let fromCoordinate = fromCat.coordinate(withNormalizedOffset: CGVector(dx: 0, …Issue #582
Run on device, Xcode -> Debug -> View debugging -> Rendering -> Color blended layer
On Simulator -> Debug -> Color Blended Layer
Issue #580
Implement scene(_:openURLContexts:) in your scene delegate.
If the URL launches your app, you will get …
Issue #571
From CGFloat.pi / 2 to -CGFloat.pi / 2 + epsilon
Issue #570
@available(iOS 11.0, *)
override func viewSafeAreaInsetsDidChange() {
super.viewSafeAreaInsetsDidChange()
self.collectionView.reloadData()
}
Use …
Issue #569
From documentation https://developer.apple.com/documentation/uikit/uicollectionviewlayout/1617726-initiallayoutattributesforappear
This method is called after the prepare(forCollectionViewUpdates:) method and before the …
Issue #567
import UIKit
public protocol AdapterDelegate: class {
/// Apply model to view
func configure(model: Any, view: UIView, indexPath: IndexPath)
/// Handle …Issue #550
Issue #539
extension XCTestCase {
func takeScreenshot(name: String) {
let screenshot = XCUIScreen.main.screenshot()
let attach = XCTAttachment(screenshot: screenshot)
attach.lifetime = .keepAlways …Issue #538
UIToolbar -> _UIToolbarContentView -> _UIButtonBarStackVie
_UIToolbarContentView's width should equal 0
_UIToolbarContentView's height should equal 0
Workaround that fixes 1 warning
toolbar. …Issue #537
In xcodebuild, specify launch arguments.
You can specify this under Launch Arguments in Run action of the app scheme or UITest scheme
-AppleLanguages (jp) -AppleLocale (jp_JP)
(lldb) po ProcessInfo().arguments
▿ …Issue #536
extension UITextField {
func setLeftView(_ view: UIView, padding: CGFloat) {
view.translatesAutoresizingMaskIntoConstraints = true
let outerView = UIView()
outerView.translatesAutoresizingMaskIntoConstraints = …Issue #535
datePicker.setValue(UIColor.green, forKey: "textColor")
datePicker.setValue(false, forKey: "highlightsToday")
In iOS 14
if #available(iOS 14.0, *) {
datePicker.preferredDatePickerStyle = .wheels
datePicker.tintColor …Issue #530
Although UIImageView frame is correct, image is still cropped. Watch out for any layer.mask within view
Issue #529
It is up to you to decide how to use the indexPath parameter to identify a given decoration view. …
Issue #518
let userDefaults = UserDefaults(suiteName: suiteName)
userDefaults.removePersistentDomain(forName: suiteName)
https://developer.apple.com/documentation/foundation/userdefaults/1417339-removepersistentdomain
Calling this method is …
Issue #504
https://twitter.com/NeoNacho/status/1181245484867801088?s=20
There’s no way to have platform specific sources or targets today, so you’ll have to take a different approach. I would recommend wrapping all OS specific files in #if os and …
Issue #496
Read this Restoring Purchased Products to understand the purposes between the 2.
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 …
Issue #484
Use SwiftMonkey which adds random UITests gestures
Add to UITests target
target 'MyAppUITests' do
pod 'R.swift', '~> 5.0'
pod 'SwiftMonkey', '~> 2.1.0'
end
Issue #480
I use modulemap in my wrapper around CommonCrypto https://github.com/onmyway133/arcane, https://github.com/onmyway133/Reindeer
For those getting header not found, please take a look …
Issue #478
Dependencies used
Examples
Issue #473
Use UIScreen.didConnectNotification
NotificationCenter.default.addObserver(forName: UIScreen.didConnectNotification,
object: nil, queue: nil) { (notification) in
// Get the new screen …Issue #472
Use convenient code from Omnia
To make view height dynamic, pin UILabel to edges and center
import UIKit
final class ErrorMessageView: UIView {
let box: UIView = {
let view = UIView()
view. …Issue #471
let navigationController = UINavigationController(rootViewController: viewControllerA)
navigationController.pushViewController(viewControllerB, animated: true)
In view controller B, need to set hidesBottomBarWhenPushed in init
final class …Issue #470
Use NSTextAttachment inside NSAttributedString
extension UILabel {
func addTrailing(image: UIImage) {
let attachment = NSTextAttachment()
attachment.image = image
let attachmentString = NSAttributedString( …Issue #469
If there are lots of logics and states inside a screen, it is best to introduce parent and child container, and switch child depends on state. Each child acts as a State handler.
In less logic case, we can introduce a Scenario class that …
Issue #466
iOS
View Controller -> View Model | Logic Handler -> Data Handler -> Repo
Android
Activity -> Fragment -> View Model | Logic Handler -> Data Handler -> Repo
Issue #463
func zoom(location1: CLLocation, location2: CLLocation) {
let bounds = GMSCoordinateBounds(coordinate: location1.coordinate, coordinate: location2.coordinate)
let update = GMSCameraUpdate.fit(bounds, withPadding: 16)
mapView. …Issue #462
Using object, we don’t need to care about nil vs false like in UserDefaults, our object is the source of truth
class StoringHandler<T: Codable> {
private let key: Storage.Keys
private let storage = Deps.storage …Issue #461
With UIAlertController we can add buttons and textfields, and just that
func addAction(UIAlertAction)
func addTextField(configurationHandler: ((UITextField) -> Void)?)
To add custom content to UIAlertController, there are some …
Issue #460
extension UIView {
func findRecursively<T: UIView>(type: T.Type, match: (T) -> Bool) -> T? {
for view in subviews {
if let subview = view as? T, match(subview) {
return subview …Issue #459
Here are my notes when working with Push Notification
Register to receive push notification
registerForRemoteNotificationTypes is deprecated in iOS 8+
UIApplication.sharedApplication().registerForRemoteNotifications() …Issue #456
From WWDC 2018 What’s New in User Notifications
Instead, the notifications from your app will automatically start getting delivered.
Notifications that are delivered with provisional authorization will have a prompt like this on …
Issue #455
There are times we want to log if user can receive push notification. We may be tempted to merely use isRegisteredForRemoteNotifications but that is not enough. From a user ’s point of view, they can either receive push notification …
Issue #454
From documentation https://developer.apple.com/documentation/usernotificationsui
Customize how local and remote notifications appear on the user’s device by adding a notification content app extension to the bundle of your iOS app. Your …
Issue #452
Use UserNotifications framework
import FirebaseMessaging
import UserNotifications
final class PushHandler: NSObject {
private let center = UNUserNotificationCenter.current()
private let options: UNAuthorizationOptions = [.alert] …Issue #444
To avoid compiler error Unprintable ASCII character found in source file, from Swift 5, we can use isASCII.
Run this from the generator app that generates Swift code.
let normalized = weirdString.filter({ $0.isASCII })
For more check, see …
Issue #440
http://itunes.apple.com/[country]/app/[App–Name]/id[App-ID]?mt=8
For example https://apps.apple.com/nl/app/cutters/id1466739130
Issue #434
When calling collectionView.reloadData(), selected indexpath stays the same, but be aware that order of data may have changed
let selectedData = ...
let indexPathForSelectedData = ...
collectionView.scrollToItem(
at: …Issue #424
One confusing point here that people often do not realize is that even though the custom token itself expires after one hour, a modern client SDK authenticated …
Issue #422
To constrain views outside to elements inside UICollectionViewCell, we can use UILayoutGuide.
Need to make layout guide the same constraints as the real elements
let imageViewGuide = UILayoutGuide()
collectionView.addLayoutGuide( …Issue #421
private func maskCvcIfAny() {
guard
let view = paymentTextField.subviews.first(where: { !($0 is UIImageView) }),
let cvcField = view.subviews
.compactMap({ $0 as? UITextField })
.first(where: { $0.tag == 2 …Issue #414
Codable is awesome, but sometimes we just need to quickly get value in a deepy nested JSON. In the same way I did for Dart How to resolve deep json object in Dart, let’s make that in Swift.
See …
Issue #412
When the value of this property is true, the …
Issue #411
class ViewController: UIViewController, UICollectionViewDropDelegate, UICollectionViewDragDelegate {
// MARK: - UICollectionViewDragDelegate
func collectionView(_ collectionView: UICollectionView, …Issue #402
I want to test if a date has passed another date
let base = Date(timeIntervalSince1970: 1567756697)
XCTAssertEqual(validator.hasPassed(event: event, date: base), true)
My hasPassed is using Calendar.current
func minuteSinceMidnight(date: …Issue #395
Prefer static enum to avoid repetition and error. The Log should have methods with all required fields so the call site is as simple as possible. How to format and assign parameters is encapsulated in this Analytics.
import Foundation …Issue #387
Google Analytics is shutting down. From Firebase Analytics console, we can choose to upgrade to Google Analytics, no code change is needed.
https://support.google.com/firebase/answer/9167112?hl=en
In October 2019, we will start to sunset …
Issue #386
When it comes to right and bottom side, we should use negative values, and use lessThan, as it means less than a negative value
Issue #385
+ (BOOL)isJailbroken {
#if !(TARGET_IPHONE_SIMULATOR)
FILE *file = fopen( …Issue #377
OneSignal is an alternative for Parse for push notifications but the sdk has many extra stuff and assumptions and lots of swizzling.
We can just use Rest to make API calls. From https://github.com/onmyway133/Dust
Every official push …
Issue #376
https://github.com/onmyway133/Omnia/blob/master/Sources/Shared/Debouncer.swift
import Foundation
public class Debouncer {
private let delay: TimeInterval
private var workItem: DispatchWorkItem?
public init(delay: TimeInterval …Issue #375
final class LifecyclerHandler {
private var observer: AnyObject!
var action: (() -> Void)?
private let debouncer = Debouncer(delay: 1.0)
func setup() {
observer = NotificationCenter.default.addObserver( …Issue #374
Add accessibilityIdentifier to the parent view of GMSMapView. Setting directly onto GMSMapView has no effect
accessibilityIdentifier = "MapView"
let map = app.otherElements.matching(identifier: …Issue #373
UIButton.contentEdgeInsets does not play well with Auto Layout, we need to use intrinsicContentSize
final class InsetButton: UIButton {
required init(text: String) {
super.init(frame: .zero)
titleLabel?.textColor = . …Issue #371
Scrolling UIScrollView is used in common scenarios like steps, onboarding.
From iOS 11, UIScrollView has contentLayoutGuide and frameLayoutGuide
https://developer.apple.com/documentation/uikit/uiscrollview/2865870-contentlayoutguide …
Issue #369
Issue #368
See https://github.com/onmyway133/Omnia/blob/master/Sources/iOS/NSLayoutConstraint.swift
extension NSLayoutConstraint {
/// Disable auto resizing mask and activate constraints
///
/// - Parameter constraints: constraints to …Issue #365
import WebKit
import SafariServices
final class WebViewHandler: NSObject, WKNavigationDelegate {
var show: ((UIViewController) -> Void)?
let supportedSchemes = ["http", "https"]
func webView(_ webView: …Issue #364
AppFlowController.swift
import UIKit
import GoogleMaps
import Stripe
final class AppFlowController: UIViewController {
private lazy var window = UIWindow(frame: UIScreen.main.bounds)
func configure() {
GMSServices. …Issue #362
let tapGR = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
@objc private func handleTap(_ gr: UITapGestureRecognizer) {
didTouch?()
}
We need to use lazy instead of let for gesture to work
lazy var tapGR = …Issue #356
StripeHandler.swift
From Stripe 16.0.0 https://github.com/stripe/stripe-ios/blob/master/CHANGELOG.md#1600-2019-07-18
Migrates STPPaymentCardTextField.cardParams property type from STPCardParams to STPPaymentMethodCardParams
final class …Issue #353
When using STPPaymentCardTextField from stripe-ios, the default behavior is when we touch outside to dismiss keyboard, it checks and focus on number text field is it is invalid
STPPaymentCardTextField.m
- (STPFormTextField *) …Issue #350
Read Authenticate with Firebase on iOS using a Phone Number
Info.plist
<key>FirebaseAppDelegateProxyEnabled</key>
<string>NO</string>
Enable Capability -> Background …
Issue #347
Add a hidden UITextField to view hierarchy, and add UITapGestureRecognizer to activate that textField.
Use padding string with limit to the number of labels, and prefix to get exactly n characters.
DigitView.swift
import UIKit
final …Issue #346
We have FrontCard that contains number and expiration date, BackCard that contains CVC. CardView is used to contain front and back sides for flipping transition.
We leverage STPPaymentCardTextField from Stripe for working input fields, …
Issue #345
UIButton with system type has implicit animation for setTitle(_:for:)
Use this method to set the title for the button. The title you specify derives its formatting from the button’s associated label object. If you set both a title and an …
Issue #344
addSubview can trigger viewDidLayoutSubviews, so be careful to just do layout stuff in viewDidLayoutSubviews
This method establishes a strong reference to view and sets its next responder to the receiver, which is its new superview. …
Issue #343
Xcode 10.3 with iOS 13
sudo ln -s /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/13.0 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport
Xcode 10.3 with iOS 13.1 …
Issue #339
For simple cases, we don’t need to. Let’s use urlCache
The URL cache for providing cached responses to requests within the session.
The URL Loading System caches responses both in memory and on disk, …
Issue #337
Normally we just present from any UIViewController in any UINavigationController in UITabBarController and it will present over tabbar
present(detailViewController, animated: true, completion: nil)
If we have animation with …
Issue #334
NSSecureCoding has been around since iOS 6 and has had some API changes in iOS 12
A protocol that enables encoding and decoding in a manner that is robust against object substitution attacks. …
Issue #333
In a traditional pager with many pages of content, and a bottom navigation with previous and next button. Each page may have different content, and depending on each state, may block the next button.
The state of next button should state …
Issue #329
Firstly, to make UIStackView scrollable, embed it inside UIScrollView. Read How to embed UIStackView inside UIScrollView in iOS
It’s best to listen to keyboardWillChangeFrameNotification as it contains frame changes for Keyboard in …
Issue #328
Sometimes we want to validate forms with many fields, for example name, phone, email, and with different rules. If validation fails, we show error message.
We can make simple Validator and Rule
class Validator {
func validate(text: …Issue #326
Traditionally, from Swift 4.2 we need guard let self
addButton.didTouch = { [weak self] in
guard
let self = self,
let product = self.purchasedProduct()
else {
return
self.delegate?.productViewController …Issue #325
UILabel as placeholder and move itoffsetX for translation is 10%Issue #324
view.addSubview(scrollView)
scrollView.addSubview(stackView)
NSLayoutConstraint.on([
scrollView.pinEdges(view: view),
stackView.pinEdges(view: scrollView)
])
NSLayoutConstraint.on([
stackView.widthAnchor.constraint(equalTo: …Issue #318
I do UI in code, and usually separate between View and ViewController.
class ProfileView: UIView {}
class ProfileViewController: UIViewController {
override func loadView() {
self.view = ProfileView()
}
}
But in places where …
Issue #315
extension PanCollectionViewController: UIGestureRecognizerDelegate {
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
let velocity = panGR.velocity(in: panGR.view)
return abs( …Issue #313
Push user-facing notifications to the user’s device from a server, or generate them locally from your app.
A class that animates changes to views and allows the dynamic modification …
Issue #313
Push user-facing notifications to the user’s device from a server, or generate them locally from your app.
A class that animates changes to views and allows the dynamic modification …
Issue #313
Push user-facing notifications to the user’s device from a server, or generate them locally from your app.
A class that animates changes to views and allows the dynamic modification …
Issue #313
Push user-facing notifications to the user’s device from a server, or generate them locally from your app.
A class that animates changes to views and allows the dynamic modification …
Issue #311
See Omnia https://github.com/onmyway133/Omnia/blob/master/Sources/iOS/UICollectionView.swift#L30
extension HorizontalUsersViewController: UIScrollViewDelegate {
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { …Issue #309
let placemark = MKPlacemark(coordinate: coordinate, addressDictionary: nil)
let mapItem = MKMapItem(placemark: placemark)
mapItem.name = shop.name
mapItem.openInMaps(launchOptions: [:])
Issue #307
import MapKit
let formatter = MKDistanceFormatter()
formatter.unitStyle = .abbreviated
formatter.units = .metric
distanceLabel.text = formatter.string(fromDistance: distance) // 700m, 1.7km
Issue #303
Instead of setting up custom framework and Playground, we can just display that specific view as root view controller
window.rootViewController = makeTestPlayground()
func makeTestPlayground() -> UIViewController {
let content = …Issue #302
final class CarouselLayout: UICollectionViewFlowLayout {
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
guard let attributes = super. …Issue #301
Make it more composable using UIViewController subclass and ThroughView to pass hit events to underlying views.
class PanViewController: UIViewController {
var animator = UIViewPropertyAnimator(duration: 0, curve: .easeOut)
lazy …Issue #288
Use this property to specify a …
Issue #280
Original post https://medium.com/fantageek/how-to-fix-wrong-status-bar-orientation-in-ios-f044f840b9ed
When I first started iOS, it was iOS 8 at that time, I had a bug that took my nearly a day to figure out. The issue was that the status …
Issue #258
I started iOS development when iOS 7 had been announced. And I have learned a bit, through working, advice from colleagues and the iOS community.
In this article, I’d like to share a lot of good practices by taking the example of a simple …
Issue #250
UITabBarItem subclasses from UIBarItem which has imageInsets. We need both top and bottom to avoid shrinking
viewController1.tabBarItem.imageInsets = UIEdgeInsets(top: 10, left: 0, bottom: -10, right: 0)
Issue #249
Making splash screen with LaunchScreen.storyboard is now the default way to do in iOS. Testing it with UITests is a bit tricky as this screen is showed the system, and if we test that, we are just testing the system.
What we should test is …
Issue #246
Use GMSMapStyle https://developers.google.com/maps/documentation/android-sdk/styling Export styling json from https://mapstyle.withgoogle.com/
let mapStyleUrl = Bundle.main.url(forResource: "mapStyle", withExtension: "json" …Issue #245
Original post https://medium.com/fantageek/my-favourite-wwdc-2018-sessions-363d3fc9c9d5
This year I failed the lottery ticket to WWDC, and I also missed the keynote live stream because I was sailing on the …
Issue #232
From https://github.com/xhamr/paintcode-path-scale with some updates
extension CGRect {
var center: CGPoint {
return CGPoint( x: self.size.width/2.0,y: self.size.height/2.0)
}
}
extension CGPoint {
func vector(to p1: …Issue #230
CAReplicatorLayer is a layer that creates a specified number of sublayer copies with varying geometric, temporal, and color transformations
Here we use instanceTransform which applies transformation matrix around the center of the …
Issue #229
let animation = CASpringAnimation(keyPath: #keyPath(CALayer.transform))
animation.fromValue = 0
animation.valueFunction = CAValueFunction(name: CAValueFunctionName.rotateZ)
animation.timingFunction = CAMediaTimingFunction(name: …Issue #228
CAAnimation is about presentation layer, after animation completes, the view snaps back to its original state. If we want to keep the state after animation, then the wrong way is to use CAMediaTimingFillMode.forward and …
Issue #227
final class SearchBox: UIView {
lazy var textField: UITextField = {
let textField = UITextField()
let imageView = UIImageView(image: R.image.search()!)
imageView.frame.size = CGSize(width: 20 + 8, height: 20) …Issue #226
Take screenshot
xcrun simctl io booted screenshot image.png
Record video
xcrun simctl io booted recordVideo video.mp4
Issue #225
<key>UIAppFonts</key>
<array>
<string>OpenSans-Bold.ttf</string>
<string>OpenSans-BoldItalic.ttf</string>
<string>OpenSans-ExtraBold.ttf</string>
<string> …Issue #224
let tabBarController = UITabBarController()
let navigationController1 = UINavigationController(rootViewController: viewController1)
let navigationController2 = UINavigationController(rootViewController: viewController2)
let …Issue #221
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>example.com</key>
<dict>
<key> …Issue #219
import UIKit
import Stripe
final class MainController: UIViewController {
func showPayment() {
let addCardViewController = …Issue #210
Depending on what features we want to achieve, we need to go with either AVFoundation or MediaPlayer framework. As someone who worked with many apps that involve media playback, here are some of my observations
Issue #209
Here are what I learn about reachability handling in iOS, aka checking for internet connection. Hope you will find it useful, too.
This post starts with techniques from Objective age, but many of the concepts still hold true
Issue #194
DispatchWorkItemIssue #183
func zoomInDouble(coordinate: CLLocationCoordinate2D) {
let region = mapView.region
let zoomInRegion = MKCoordinateRegion(
center: coordinate,
span: MKCoordinateSpan(
latitudeDelta: region.span. …Issue #182
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
guard let coordinate = view.annotation?.coordinate else {
return
}
if (view.annotation is MKClusterAnnotation) {
zoomInDouble( …Issue #181
final class AnnotationView: MKMarkerAnnotationView {
override init(annotation: MKAnnotation?, reuseIdentifier: …Issue #179
let rough = context.objectForKeyedSubscript("myObject")
myObject.toDictionary()
Issue #154
The most common UI element in iOS is UITableView, and the most common task is to display the UITableViewCell using the model.
Although the title specifies UITableViewCell, but the problem involves other views (UICollectionView, custom …
Issue #148
From https://github.com/devxoul/Pure/blob/master/Sources/Pure/FactoryModule.swift
public protocol FactoryModule: Module {
/// A factory for `Self`.
associatedtype Factory = Pure.Factory<Self>
/// Creates an instance of a …Issue #144
There are times we want the same UIViewController to look good when it’s presented modally or pushed from UINavigationController stack. Take a look at BarcodeScanner and the PR https://github.com/hyperoslo/BarcodeScanner/pull/82
When …
Issue #143
Today I was writing tests and get this error related to app idle
t = 23.06s Assertion Failure: <unknown>:0: Failed to scroll to visible (by AX action) Button, 0x6000003827d0, traits: 8858370049, label: 'cart', …Issue #138
Here is how to use R.swift in UITest target
Localizable.strings to UITest targettarget 'MyAppUITests' do
pod 'R.swift', '~> 4.0'
end
$(FRAMEWORK_SEARCH_PATHS) …Issue #137
Use a custom NavigationController
import UIKit
class NavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
navigationBar.tintColor = .white
navigationBar.barStyle = .black …Issue #133
With dlopen we can make uses of some private frameworks. It will be fun
From iPhone X home button
#import <dlfcn.h>
// somewhere in viewDidLoad
dlopen([binaryPath cStringUsingEncoding:NSUTF8StringEncoding], RTLD_NOW);
UIView *const …Issue #124
We all know that there’s a potential crash with UIVisualEffectView on iOS 11. The fix is to not add sub views directly to UIVisualEffectView, but to its contentView. So we should change
effectView.addSubview(button)
to
effectView. …Issue #119
This is about collection update, how to provide correct IndexPath and a simple diffing algorithm
Issue #113
This is a follow up from my post Learning from Open Source: Using Playground on how to actually add a playground to your production project.
The idea is simple: create a framework so that Playground can access the code. This demo an iOS …
Issue #110
Medium version https://medium.com/@onmyway133/url-routing-with-compass-d59c0061e7e2
Apps often have many screens, and UIViewController works well as the basis for a screen, together with presentation and navigation APIs. Things are fine …
Issue #106
Every new architecture that comes out, either iOS or Android, makes me very excited. I’m always looking for ways to structure apps in a better way. But after some times, I see that we’re too creative in creating architecture, …
Issue #99
I’ve been searching for efficient ways to diff collections, here are some interesting papers that I find
Myers
Issue #98
The safeAreaLayoutGuide was introduced in iOS 11. And it is advised to stop using topLayoutGuide bottomLayoutGuide as these are deprecated.
To use safeAreaLayoutGuide, you need to do iOS version check
if #available(iOS 11.0, *) { …Issue #97
The Coordinator pattern can be useful to manage dependencies and handle navigation for your view controllers. It can be seen from BackchannelSDK-iOS, take a look at BAKCreateProfileCoordinator for example
@implementation …Issue #96
Another cool thing about ios-oss is how it manages dependencies. Usually you have a lot of dependencies, and it’s good to keep them in one place, and inject it to the objects that need.
The Environment is simply a struct that holds …
Issue #94
One thing I like about kickstarter-ios is how they use Playground to quickly protoyping views.
We use Swift Playgrounds for iterative development and styling. Most major screens in the app get a corresponding playground where we can see a …
Issue #92
Today I was upgrading Keychain to swift 4, and take this opportunity to fix the test. The tests pass on macOS, but on iOS, I get -25300 error for
var status = SecItemCopyMatching(query as CFDictionary, nil)
It is because there is no …
Issue #85
That’s the question I hear often when people are introduced to a new framework. It’s a valid concern. But it seems to me that they ask this just for fun. To my surprise, most people just don’t care, and the frameworks with …
Issue #64
Note: This applies to Firebase 4.0.4
Go to Member Center -> Certificates -> Production
You can now use 1 certificate for both sandbox and production environment

Issue #59
TL;DR: Don’t use nativeScale and nativeBounds, unless you’re doing some very low level stuff
From …
Issue #56



Issue #45
You should mock a location to ensure reliable test
Go to Xcode -> File -> New -> GPX File

It looks like
<?xml version="1.0"?>
<gpx version="1.1" creator="Xcode" …Issue #36
Usually in an app, we have these flows: onboarding, login, main. And we usually set OnboardingController, LoginController and MainController as the root view controller respectively depending on the state.
I find it useful to have the …
Issue #35
Auto Layout is awesome. Just declare the constraints and the views are resized accordingly to their parent ’s bounds changes. But sometimes it does not look good, because we have fixed values for padding, width, height, and even fixed …
Issue #33
I see that my answer to the question What’s the meaning of Base SDK, iOS deployment target, Target, and Project in xcode gets lots of views, so I think I need to elaborate more about it
Good read
Issue #32
iOS 9 introduces new ways for your app to work better, backed by your websites
If the app is already installed on a user’s device, the banner intelligently changes its action, …
Issue #24
There is Lighter View Controllers, and there is Lighter AppDelegate, too
Since working with iOS, I really like the delegate pattern, in which it helps us defer the decision to another party.
The iOS application delegates its event to …
Issue #23
Returns whether the constraints impacting the layout of the view incompletely specify the location of the view.
This method randomly changes the frame of a view with an ambiguous layout between …
Issue #22
In the beginning, people use frame and Autoresizing Mask, then they use Auto Layout, then iOS 9 encourages them to use NSLayoutAnchor, UILayoutGuide and UIStackView
For more convenient Auto Layout, check How to make Auto Layout more …
Issue #20
The other day I was doing refresh control, and I saw this Swift Protocols with Default Implementations as UI Mixins
extension Refreshable where Self: UIViewController
{
/// Install the refresh control on the table view
func …Issue #19
We need to care about security nowadays, here are some links I find useful to read more about this matter
Issue #997
An interesting feature in iOS 26 is the ability to create morph “Liquid Glass” effects, where views with the .glassEffect() modifier can fluidly morph into one another. This is achieved using GlassEffectContainer and the …
Issue #996
When creating widgets for iOS, especially those that need user input to be useful, one common challenge is guiding the user to configure them. Before iOS 18, a user would add a widget, but then would have to know to long-press it and …
Issue #995
With iOS 18, SwiftUI introduces matchedTransitionSource and navigationtransition as a powerful new way to create zoom animations between views. This allows you to smoothly transition from a small view to a larger, more detailed view, …
Issue #994
With iOS 18, Apple introduced a powerful new tool for creating beautiful, dynamic backgrounds: MeshGradient. Forget simple two-color gradients; mesh gradients let you blend a whole grid of colors together smoothly, creating stunning, …
Issue #992
In the past, making your screen update when data changed in UIKit meant writing extra code, either with didSet, Combine or some other callbacks. Now, it’s automatic.
With the latest iOS 26 updates, UIKit can automatically watch your …
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 …
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: …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. …
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 …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
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 …Issue #956
import Foundation
import SwiftUI
import AppKit
struct AttributedTextView: NSViewRepresentable {
@Binding var attributedText: NSAttributedString
var isEditable: Bool = true
final class Coordinator: NSObject { …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 …
Issue #951
Create a custom NSView that handles mouseDragged to beginDraggingSession
struct DraggingSourceViewWrapper: NSViewRepresentable {
let fileUrls: [URL]
let onEnd: () -> Void
func makeNSView(context: Context) -> …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( …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 …
Issue #944
SwiftUI in iOS 16 supports Layout protocol to arrange subviews
We need to implement 2 methods
Issue #943
In this tutorial, we’ll learn how to use Swift Charts to visualize ranking data.
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 …
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: …Issue #930
Declare AppShortcutsProvider, note that appShortcuts uses @AppShortcutsBuilder syntax
import AppIntents
struct OurShortcutsProvider: AppShortcutsProvider {
static var shortcutTileColor: ShortcutTileColor = .lightBlue …Issue #929
We can use ButtonStyleConfiguration to detect isPressed state
struct RecordButton: View {
var body: some View {
Button {
} label: {
Image(systemSymbol: .micFill)
}
.buttonStyle( …Issue #924
Note
the navigation split view coordinates with the List in its first …
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)
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
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. …Issue #919
WWDC23 introduces lots of new additions to SwiftUI, notably Metal shader support with these modifiers
Issue #899
Use NSTitlebarAccessoryViewController
var titleBarAccessoryVC: NSTitlebarAccessoryViewController {
let vc = NSTitlebarAccessoryViewController()
let view = HStack {
Spacer()
Button {
} label: { …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 …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 { …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 …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. …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 { …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 …
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
Issue #889



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

Section("Hashtags") { …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 …
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 …
Issue #878
Note that
id is needed, although Book already conforms to Identifiableselection needs a default valueclass BookViewModel: ObservableObject {
@Published var books: [Book] = []
@Published var selectedBooks: Set<Book …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 🤯
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 …Issue #858
isDetailLink(false).introspectNavigationController { nav in
self.nav = nav
}
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 = …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 { …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) -> …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. …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 { …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, …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 …
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 ? "$\( …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 …Issue #842
Declare EnvironmentKey and read safeAreaInsets from key window in connectedScenes
struct SafeAreaInsetsKey: EnvironmentKey {
static var defaultValue: EdgeInsets {
UIApplication.shared.keyWindow?.safeAreaInsets.swiftUIInsets ?? …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 …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 }, …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 { …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) { …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( …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 …
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: …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 …
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 { …Issue #828
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 …Issue #826
Use isActive binding
@State private var goesToDetail: Bool = false
NavigationLink(
destination: DetailView(viewModel: viewModel),
isActive: $goesToDetail) {
Button(action: { goesToDetail = true }) {
Text("Next" …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 …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 …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 {
@ …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) }) …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: …Issue #820
Use NSDataDetector to detect links, and NSMutableAttributedString to mark link range. Then we enumerateAttributes and build our Text
func attribute(string: String) -> Text {
guard let detector = try? NSDataDetector(types: …Issue #818
There’s a lot to do to imitate iOS ContextMenu look and feel
For now here’s a rough implementation of a custom context menu where we …
Issue #817
Thanks to resultBuilder and container type in Swift, the following are possible in SwiftUI
struct ChartView {
var body: some View {
computation
}
@ViewBuilder
var computation: some View {
let …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
import SwiftUI
struct CustomMenu<Content: View>: View {
@ViewBuilder …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 …
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 …
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 …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>( …Issue #808
Wrap ASAuthorizationAppleIDButton inside UIViewRepresentable
import SwiftUI
import UIKit
import AuthenticationServices
struct SignInWithAppleButton: View {
@Environment(\.colorScheme)
private var …Issue #798
swiftgen.yml
strings:
inputs: PastePal/Resources/Localizable/en.lproj
outputs:
- templatePath: swiftgen-swiftui-template.stencil
output: PastePal/Resources/Strings.swift
Template from …
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 { …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 …
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 …
Issue #789
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 …
Issue #785
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 …
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 …
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, …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()
} …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
Every cell has …
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 …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 …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 …
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 …
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) …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 …
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
} …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 { …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 …Issue #761
Explicitly specify id
ScrollView {
ScrollViewReader { proxy in
LazyVStack(spacing: 10) {
ForEach(items) { item in
Cell(item: item)
.id(item.id)
}
}
. …Issue #756
extension NavigationLink {
func fixOverlap() -> AnyView {
if UIDevice.current.userInterfaceIdiom == .phone {
return self.isDetailLink(false).erase()
} else {
return self.erase()
} …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, …
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, …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> …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")
. …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)
. …Issue #736
struct MyWebView: NSViewRepresentable {
let url: URL
@Binding
var isLoading: Bool
func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}
func makeNSView(context: Context) -> WKWebView { …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 …
Issue #734
In SwiftUI there are fixed frame and flexible frame modifiers.
Use this method to specify a fixed size for a view’s width, height, or both. If you only …
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: …Issue #730
Use NSTextField with maximumNumberOfLines
import AppKit
import SwiftUI
struct AttributedText: NSViewRepresentable {
let attributedString: NSAttributedString
init(_ attributedString: NSAttributedString) {
self. …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: …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(@ …Issue #722
With Xcode 12, we can fire up Instrument to profile our app. Select SwiftUI template
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
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 …
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 …Issue #717
Try to use predefined system colors in Human Interface Guidelines for macOS
Here we use this color unemphasizedSelectedTextBackgroundColor for button background
HStack(spacing: 1) {
makeUnderListButton(action: {}, icon: .plus) …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( …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 …
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, …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 …
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). …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()
} …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 …Issue #689
func applicationDidFinishLaunching(_ aNotification: Notification) {
// extend to title bar
let contentView = ContentView()
// .padding(.top, 24) // can padding to give some space
.edgesIgnoringSafeArea(.top)
// …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 …
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 …
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
@ …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 …
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 …Issue #680
For List in SwiftUI for macOS, it has default background color because of the enclosing NSScrollView via NSTableView that List uses under the hood. Using listRowBackground also gives no effect
The solution is to use a library like …
Issue #679
While redesigning UI for my app Push Hero, I ended up with an accordion style to toggle section.
It worked great so far, but after 1 collapsing, all image and text views have reduced opacity. This does not happen for other elements like …
Issue #678
Use enumerated to get index so we can assign to item in list. Here is how I show list of device tokens in my app Push Hero
private var textViews: some View {
let withIndex = input.deviceTokens.enumerated().map({ $0 })
let binding: …Issue #677
The quick way to add new properties without breaking current saved Codable is to declare them as optional. For example if you use EasyStash library to save and load Codable models.
import SwiftUI
struct Input: Codable {
var bundleId: …Issue #676
I’ve used the default SwiftUI to achieve the 2 tab views in SwiftUI. It adds a default box around the content and also opinionated paddings. For now on light mode on macOS, the unselected tab has wrong colors.
The way to solve this …
Issue #675
Use wrappedValue to get the underlying value that Binding contains
extension View {
func addOverlay(shows: Binding<Bool>) -> some View {
HStack {
self
Spacer()
}
.overlay( …Issue #674
Specify minWidth to ensure miminum width, and use .layoutPriority(1) for the most important pane.
import SwiftUI
struct MainView: View {
@EnvironmentObject var store: Store
var body: some View {
HSplitView { …Issue #656
Lately I’ve been challenging myself to declare switch statement in SwiftUI, or in a more generalized way, execute any anonymous function that can return a View
Note that this approach does not work yet, as …
Issue #633
Use autoclosure and AnyView
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
public extension View {
func applyIf<T: View>(_ condition: @autoclosure () -> Bool, apply: (Self) -> T) -> AnyView {
if …Issue #630
For SwiftUI app using NSPopover, to show context popover menu, we can ask for windows array, get the _NSPopoverWindow and calculate the position. Note that origin of macOS screen is bottom left
(lldb) po NSApp.windows
▿ 2 elements
- 0 : …Issue #626
SwiftUI does not trigger onAppear and onDisappear like we expect. We can use NSView to trigger
import SwiftUI
struct AppearAware: NSViewRepresentable {
var onAppear: () -> Void
func makeNSView(context: …Issue #625
For some strange reasons, content inside ForEach does not update with changes in Core Data NSManagedObject. The workaround is to introduce salt, like UUID just to make state change
struct NoteRow: View {
let note: Note
let id: UUID …Issue #623
Listen to context changes notification and change SwiftUI View state
let changes = [NSDeletedObjectsKey: ids]
NSManagedObjectContext.mergeChanges(
fromRemoteContextSave: changes,
into: [context]
)
try context.save()
struct …Issue #622
Read Implementing Batch Deletes
If the entities that are being deleted are not loaded into memory, there is no need to update your application after the NSBatchDeleteRequest has been executed. However, if you are deleting objects in the …
Issue #621
Make subview that accepts FetchRequest. Trigger search by setting property
struct SideView: View {
@Environment(\.managedObjectContext)
var context
@State var search: Search?
var body: some View {
VStack(alignment …Issue #620
For NSWindow having levelother than .normal, need to override key and main property to allow TextField to be focusable
class FocusWindow: NSWindow {
override var canBecomeKey: Bool { true }
override var canBecomeMain: Bool { …Issue #618
Create custom Binding
List {
ForEach(self.items) { (item: item) in
ItemRowView(item: item)
.popover(isPresented: self.makeIsPresented(item: item)) {
ItemDetailView(item: item)
}
}
} …Issue #615
List {
ForEach(books) { (book: Book) in
BookRow(book: book)
}
}
.listStyle(SidebarListStyle())
Issue #614
struct MyTabView: View {
@EnvironmentObject
var preferenceManager: PreferenceManager
var body: some View {
VOrH(isVertical: preferenceManager.preference.position.isVertical) {
OneTabView(image: …Issue #613
struct VOrH<Content>: View where Content: View {
let isVertical: Bool
let content: () -> Content
init(isVertical: Bool, @ViewBuilder content: @escaping () -> Content) {
self.isVertical = isVertical …Issue #612
Use runModal
This method runs a modal event loop for the specified window synchronously. It displays the specified window, makes it key, starts the run loop, and processes events for that window. (You do not need to show the window …
Issue #610
Set NSVisualEffectView as contentView of NSWindow, and our main view as subview of it. Remember to set frame or autoresizing mask as non-direct content view does not get full size as the window
let mainView = MainView()
.environment(\. …Issue #605
I use custom TextView in a master detail application.
import SwiftUI
struct TextView: NSViewRepresentable {
@Binding var text: String
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeNSView …Issue #604
I see that the modifier needs to do something on the content, otherwise it is not getting called! This logs on the modifier, when the View is created. A View won’t be recreated unless necessary
struct LogModifier: ViewModifier { …Issue #602
ForEach(store.blogs.enumerated().map({ $0 }), id: \.element.id) { index, blog in
}
```
##
Issue #599
Specify tag
enum Authentication: Int, Codable {
case key
case certificate
}
TabView(selection: $authentication) {
KeyAuthenticationView()
.tabItem {
Text("🔑 Key")
}
.tag( …Issue #598
It’s hard to see any iOS app which don’t use UITableView or UICollectionView, as they are the basic and important foundation to represent data. UICollectionView is very basic to use, yet a bit tedious for common use cases, but …
Issue #597
TextView(font: R.font.text!, lineCount: nil, text: $text, isFocus: $isFocus)
.padding(8)
.background(R.color.inputBackground)
.cornerRadius(10)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(isFocus ? R.color. …Issue #594
In some case, we should not use base type like UTType.text but to be more specific like UTType.utf8PlainText
import UniformTypeIdentifiers
var dropTypes: [UTType] {
[
.fileURL,
.url,
.utf8PlainText,
. …Issue #592
Hard to customize
Picker(selection: Binding<Bool>.constant(true), label: EmptyView()) {
Text("Production").tag(0)
Text("Sandbox").tag(1)
}.pickerStyle(RadioGroupPickerStyle())
Issue #590
Use custom NSTextField as it is hard to customize TextFieldStyle
import SwiftUI
struct MaterialTextField: View {
let placeholder: String
@Binding var text: String
@State var isFocus: Bool = false
var body: some View { …Issue #533
struct ContentView: View {
@Environment(\.locale) var locale: Locale
var body: some View {
VStack {
Text(LocalizedStringKey("hello"))
.font(.largeTitle)
Text(flag(from: …Issue #517
Use ScrollView -> VStack -> ForEach -> Content
struct SearchScreen: View {
@State var searchObjects: [SearchObject] = [
SearchObject(name: "By name", search: { CountryManager.shared.search(byName: $0) }), …Issue #516
Suppose we have an array of SearchObject, and user can enter search query into text property.
class SearchObject: ObservableObject {
let name: String
let search: (String) -> [Country]
var text: String = ""
init( …Issue #515
Use enumerated and id: \.element.name
struct CountriesView: View {
let countries: [Country]
var body: some View {
let withIndex = countries.enumerated().map({ $0 })
return List(withIndex, id: \.element.name) { …Issue #513
A publisher that emits before the object has changed
Use workaround DispatchQueue to wait another run loop to access newValue
.onReceive(store.objectWillChange, perform: {
DispatchQueue.main.async {
self.reload()
}
}) …Issue #511
struct CountriesView: View {
let groups: [Group]
init(countries: [Country]) {
self.groups = CountryManager.shared.groups(countries: countries)
}
var body: some View {
List {
ForEach(groups) { …Issue #508
We need to use frame(minWidth: 0, maxWidth: .infinity, alignment: .leading). Note that order is important, and padding should be first, and background after frame to apply color to the entire frame
struct BooksScreen: View {
@ …Issue #507
View extends to the bottom, but not to the notch. We need to add .edgesIgnoringSafeArea(.top) to our TabView to tell TabView to extend all the way to the top.
Note that if we use edgesIgnoringSafeArea(.all) then TabView ’s bar will …
Issue #505
Make sure all String are passed into Text, not Optional<String>
VStack {
Text(data.title)
Text(data.description!)
Text(data.text!)
}
Issue #502
Mutation is used to mutate state synchronously. Action is like intent, either from app or from user action. Action maps to Mutation in form of Publisher to work with async action, similar to redux-observable
AnyReducer is a type erasure …
Issue #488
The dollar is not a prefix, it seems to be a generated code for property wrapper, and each kind of property wrapper can determine which value it return via this dollar sign
State and ObservedObject are popular property wrappers in SwiftUI …
Issue #487
In case we have to modify state when another state is known, we can encapsulate all those states in ObservableObject and use onReceive to check the state we want to act on.
See code Avengers
If we were to modify state from within body …
Issue #486
import SwiftUI
struct ActivityIndicator: UIViewRepresentable {
@Binding var isAnimating: Bool
let style: UIActivityIndicatorView.Style
func makeUIView(context: UIViewRepresentableContext<ActivityIndicator>) -> …Issue #485
The easiest way to show image picker in iOS is to use UIImagePickerController, and we can bridge that to SwiftUI via UIViewControllerRepresentable
We conform to UIViewControllerRepresentable and make a …
Issue #483
Every item in list must be uniquely identifiable
List {
ForEach(books, id: \.bookId) { book in
NavigationLink(destination:
BookView(book: book)
.navigationBarTitle(book.name)
) { …Issue #482
lineLimit does not seem to work, use fixedSize instead
Fixes this view at its ideal size.
A view that fixes this view at its ideal size in the dimensions given in fixedDimensions.
extension Text {
func styleText() -> some View { …Issue #468
From onAppeear
Adds an action to perform when the view appears.
In theory, this should be triggered every time this view appears. But in practice, it is only called when it is pushed on navigation stack, not when we return to it.
So if …
Issue #467
Declare top dependencies in ExtensionDelegate
class ExtensionDelegate: NSObject, WKExtensionDelegate {
let storeContainer = StoreContainer()
func applicationDidEnterBackground() {
storeContainer.save()
}
}
Reference …
Issue #450
Following the signatures of ScrollView and Group, we can create our own container
public struct ScrollView<Content> : View where Content : View {
/// The content of the scroll view.
public var content: Content
}
extension …Issue #449
WatchKit does not have Web component, despite the fact that we can view web content
A workaround is to show url as QR code
import SwiftUI
struct QRCodeView: View {
let …Issue #448
Use ObservableObject and onReceive to receive event. URLSession.dataTask reports in background queue, so need to .receive(on: RunLoop.main) to receive events on main queue.
For better dependency injection, need to use ImageLoader from …
Issue #447
NavigationView is not available on WatchKit, but we can just use NavigationLink
List(services.map({ AnyService($0) })) { anyService in
NavigationLink(destination:
ItemsView(service: anyService.service)
. …Issue #446
Suppose we have Service protocol, and want to use in List
protocol Service {
var name: String { get }
}
struct MainView: View {
let services = [
Car()
Plane()
]
var body: some View {
List(services) …Issue #1006
When building macOS apps, you often need images that fill their container while keeping their aspect ratio - like cover photos or thumbnails. NSImageView doesn’t do this well out of the box. Here’s how to build a custom …
Issue #1002
I recently set up self-hosted runners on EC2 Mac instances for iOS builds. Here are my notes on what actually works—plus all the gotchas I hit along the way.
For complete official instructions, see GitHub’s guide on adding …
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: …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.
.copyIssue #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
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
}
}
Issue #956
import Foundation
import SwiftUI
import AppKit
struct AttributedTextView: NSViewRepresentable {
@Binding var attributedText: NSAttributedString
var isEditable: Bool = true
final class Coordinator: NSObject { …Issue #951
Create a custom NSView that handles mouseDragged to beginDraggingSession
struct DraggingSourceViewWrapper: NSViewRepresentable {
let fileUrls: [URL]
let onEnd: () -> Void
func makeNSView(context: Context) -> …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. …Issue #913
Use QuickLookThumbnailing framework
import AppKit
import QuickLookThumbnailing
actor QuicklookService {
static let shared = QuicklookService()
private let generator = QLThumbnailGenerator.shared
func image( …Issue #903
let image = NSImage(contentsOf: url)
let imageView = NSImageView(image: image)
image.animates = true
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 …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 …
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 …
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 …
Issue #848
Hold a weak reference to NSWindow, and let system window server manages its lifetime
weak var window = NSWindow()
window.isReleasedWhenClosed = true
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) }) …Issue #806
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 …
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. …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 …
Issue #789
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 …
Issue #785
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 …
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
Every cell has …
Issue #778
For now using GroupBox has these issues in 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() { …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 { …Issue #762
To install, use CocoaPods
platform …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( …Issue #758
extension NSToolbarItem.Identifier {
static let searchItem: NSToolbarItem.Identifier = NSToolbarItem.Identifier("SearchItem")
}
let searchItem = NSSearchToolbarItem(itemIdentifier: .searchItem)
extension AppDelegate: …Issue #757
Library/LoginItemshelper_dir="$BUILT_PRODUCTS_DIR/$CONTENTS_FOLDER_PATH …Issue #753
This takes a while
xcrun altool -t osx -f PastePal.dmg --primary …Issue #750
Recently when distributing staging releases of my app PastePal via GitHub release or Google Drive, people had hard time opening it
The displayed error is
You do not have permission to open the application
The more verbose error when …
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, …
Issue #743
• = Apple logo • ⌘ = Command • ⇧ = Shift • ⌫ = Backspace/Delete • ⇪ = Caps lock • ⌥ = Option/Alt • ⌃ = Control • ⎋ = Escape • ←↑→↓ = Arrow Keys • ↩ = Return
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: …Issue #730
Use NSTextField with maximumNumberOfLines
import AppKit
import SwiftUI
struct AttributedText: NSViewRepresentable {
let attributedString: NSAttributedString
init(_ attributedString: NSAttributedString) {
self. …Issue #729
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
@IBAction func copy(_ sender: Any) {
print("copy", sender)
}
@IBAction func paste(_ sender: Any) {
print("paste", sender) …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: …Issue #721
For setFrame to take effect
mainWindow.setFrame(rect, display: true)
we can remove auto save frame flag
mainWindow.setFrameAutosaveName("MyApp.MainWindow")
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 …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 …
Issue #717
Try to use predefined system colors in Human Interface Guidelines for macOS
Here we use this color unemphasizedSelectedTextBackgroundColor for button background
HStack(spacing: 1) {
makeUnderListButton(action: {}, icon: .plus) …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( …Issue #713
To setup toolbar, we need to implement NSToolbarDelegate that provides toolbar items. This delegate is responsible for many things
toolbarDefaultItemIdentifiersitemForItemIdentifier …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 …
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 …
Issue #703
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 …
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). …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 = …Issue #689
func applicationDidFinishLaunching(_ aNotification: Notification) {
// extend to title bar
let contentView = ContentView()
// .padding(.top, 24) // can padding to give some space
.edgesIgnoringSafeArea(.top)
// …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 …Issue #680
For List in SwiftUI for macOS, it has default background color because of the enclosing NSScrollView via NSTableView that List uses under the hood. Using listRowBackground also gives no effect
The solution is to use a library like …
Issue #679
While redesigning UI for my app Push Hero, I ended up with an accordion style to toggle section.
It worked great so far, but after 1 collapsing, all image and text views have reduced opacity. This does not happen for other elements like …
Issue #677
The quick way to add new properties without breaking current saved Codable is to declare them as optional. For example if you use EasyStash library to save and load Codable models.
import SwiftUI
struct Input: Codable {
var bundleId: …Issue #676
I’ve used the default SwiftUI to achieve the 2 tab views in SwiftUI. It adds a default box around the content and also opinionated paddings. For now on light mode on macOS, the unselected tab has wrong colors.
The way to solve this …
Issue #674
Specify minWidth to ensure miminum width, and use .layoutPriority(1) for the most important pane.
import SwiftUI
struct MainView: View {
@EnvironmentObject var store: Store
var body: some View {
HSplitView { …Issue #636
Normally we can just wrap NSTextField
struct SearchTextField: NSViewRepresentable {
@Binding var text: String
var hint: String
var onCommit: (String) -> Void
func makeNSView(context: NSViewRepresentableContext< …Issue #635
textField.delegate = self
NSTextFieldDelegate
func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
if (commandSelector == #selector(NSResponder.insertNewline(_:))) {
// …Issue #630
For SwiftUI app using NSPopover, to show context popover menu, we can ask for windows array, get the _NSPopoverWindow and calculate the position. Note that origin of macOS screen is bottom left
(lldb) po NSApp.windows
▿ 2 elements
- 0 : …Issue #627
Algorithm from https://www.w3.org/WAI/ER/WD-AERT/#color-contrast
extension NSColor {
var isLight: Bool {
guard
let components = cgColor.components,
components.count >= 3
else { return false } …Issue #626
SwiftUI does not trigger onAppear and onDisappear like we expect. We can use NSView to trigger
import SwiftUI
struct AppearAware: NSViewRepresentable {
var onAppear: () -> Void
func makeNSView(context: …Issue #625
For some strange reasons, content inside ForEach does not update with changes in Core Data NSManagedObject. The workaround is to introduce salt, like UUID just to make state change
struct NoteRow: View {
let note: Note
let id: UUID …Issue #624
By default the approaches above grant you access while the app remains open. When you quit the app, any folder access you had is lost.
To gain persistent access to a folder even on subsequent launches, we’ll have to take advantage of a …
Issue #620
For NSWindow having levelother than .normal, need to override key and main property to allow TextField to be focusable
class FocusWindow: NSWindow {
override var canBecomeKey: Bool { true }
override var canBecomeMain: Bool { …Issue #617
On macOS 11, we can use .help modifier to add tooltip
Button()
.help("Click here to open settings")
If you support macOS 10.15, then create empty NSView and use as overlay. Need to updateNSView in case we toggle the state of …
Issue #615
List {
ForEach(books) { (book: Book) in
BookRow(book: book)
}
}
.listStyle(SidebarListStyle())
Issue #612
Use runModal
This method runs a modal event loop for the specified window synchronously. It displays the specified window, makes it key, starts the run loop, and processes events for that window. (You do not need to show the window …
Issue #610
Set NSVisualEffectView as contentView of NSWindow, and our main view as subview of it. Remember to set frame or autoresizing mask as non-direct content view does not get full size as the window
let mainView = MainView()
.environment(\. …Issue #609
Use animator proxy and animate parameter
var rect = window.frame
rect.frame.origin.x = 1000
NSAnimationContext.runAnimationGroup({ context in
context.timingFunction = CAMediaTimingFunction(name: .easeIn)
window.animator().setFrame( …Issue #608
An NSRunningApplication instance for the current application.
NSRunningApplication.current
The running app instance for the app that receives key events.
NSWorkspace.shared.frontmostApplication
Issue #601
On Xcode 11, applicationWillTerminate is not called because of default automatic termination on in Info.plist. Removing NSSupportsSuddenTermination to trigger will terminate notification
func applicationWillTerminate(_ notification: …Issue #593
#if canImport(Combine) is not enough, need to specify in Other Linker Flags
OTHER_LDFLAGS = -weak_framework Combine
Issue #590
Use custom NSTextField as it is hard to customize TextFieldStyle
import SwiftUI
struct MaterialTextField: View {
let placeholder: String
@Binding var text: String
@State var isFocus: Bool = false
var body: some View { …Issue #589
import SwiftUI
struct MyTextField: View {
@Binding
var text: String
let placeholder: String
@State
private var isFocus: Bool = false
var body: some View {
FocusTextField(text: $text, …Issue #589
class FocusAwareTextField: NSTextField {
var onFocusChange: (Bool) -> Void = { _ in }
override func becomeFirstResponder() -> Bool {
let textView = window?.fieldEditor(true, for: nil) as? …Issue #588
class FocusAwareTextField: NSTextField {
var onFocus: () -> Void = {}
var onUnfocus: () -> Void = {}
override func becomeFirstResponder() -> Bool {
onFocus()
let textView = window?.fieldEditor(true, …Issue #587
From https://github.com/twostraws/ControlRoom/blob/main/ControlRoom/NSViewWrappers/TextView.swift
import SwiftUI
/// A wrapper around NSTextView so we can get multiline text editing in SwiftUI.
struct TextView: …Issue #585
Follow the new Firebase Crashlytics guide Get started with Firebase Crashlytics using the Firebase Crashlytics SDK
Specify FirebaseCore for community managed macOS version of Firebase
platform :osx, …Issue #579
Use same action, or we can roll our own implementation
An NSButton configured as a radio button (with the -buttonType set to NSRadioButton), will now operate in a radio button group for applications linked on 10.8 and later. To have the …
Issue #573
There are 2 Applications folder
Issue #520
Remove quarantine
xattr -d com.apple.quarantine /Applications/Flipper.app
Issue #504
https://twitter.com/NeoNacho/status/1181245484867801088?s=20
There’s no way to have platform specific sources or targets today, so you’ll have to take a different approach. I would recommend wrapping all OS specific files in #if os and …
Issue #443
let textField = NSTextField()
textField.focusRingType = .none
let textView = NSTextView()
textView.insertionPointColor = R.color.caret
textView.isRichText = false
textView.importsGraphics = false
textView.isEditable = true
textView. …Issue #442
On macOS, coordinate origin is bottom left
let window = NSWindow(contentRect: rect, styleMask: .borderless, backing: .buffered, defer: false)
window.center()
let frame = window.frame
window.setFrameOrigin(CGPoint(x: frame.origin.x, y: 100 …Issue #439
We need to provide NSLocalizedDescriptionKey inside user info dictionary, otherwise the outputt string may not be what we want.
Issue #438
In Storyboard, NSTextField has an Action option that specify whether Send on Send on Enter only` should be the default behaviour.

In code, NSTextFieldDelegate notifies whenever text field value changes, and target action …
Issue #437
Use Omnia for itemId extension
HeaderCell.swift
final class HeaderCell: NSView, NSCollectionViewSectionHeaderView {
let label: NSTextField = withObject(NSTextField(labelWithString: "")) {
$0.textColor = R.color. …Issue #436
Open Script Editor, use log command and look for 4 tabs in bottom panel Result, Messages, Events and Replies
log "hello world"
Issue #435
Use NSMenu and popUp
func showQuitMenu() {
let menu = NSMenu()
let aboutItem = NSMenuItem(
title: "About",
action: #selector(onAboutTouched(_:)),
keyEquivalent: ""
)
let quitItem = …Issue #433
style and isOn propertylet checkButton = NSButton(checkboxWithTitle: "", target: nil, action: nil)
checkButton.stylePlain(title: "Autosave", color: R.color.text, font: R.font.text)
checkButton. …Issue #432
Read Container Directories and File System Access
When you adopt App Sandbox, your application has access to the following locations:
The app container directory. Upon first launch, the operating system creates a special directory for …
Issue #429
Use https://github.com/markedjs/marked
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Marked in the browser</title>
</head>
<body>
<div id="content" …Issue #428
Need to set target
let item = NSMenuItem(
title: title,
action: #selector(onMenuItemClicked(_:)),
keyEquivalent: ""
)
item.target = self
Sometimes, need to check autoenablesItems
Indicates whether the menu …
Issue #427
Use ClickedCollectionView to detect clicked index for context menu.
Embed NSCollectionView inside NSScrollView to enable scrolling
import AppKit
public class CollectionViewHandler<Item: Equatable, Cell: …Issue #414
Codable is awesome, but sometimes we just need to quickly get value in a deepy nested JSON. In the same way I did for Dart How to resolve deep json object in Dart, let’s make that in Swift.
See …
Issue #410
import AppKit
import Anchors
class DraggingView: NSView {
var didDrag: ((FileInfo) -> Void)?
let highlightView = NSView()
override init(frame frameRect: NSRect) {
super.init(frame: frameRect) …Issue #409
let stepper = NSStepper()
let textField = NSTextField(wrappingLabelWithString: "\(myLocalCount)")
stepper.integerValue = myLocalCount
stepper.minValue = 5
stepper.maxValue = 24
stepper.valueWraps = false
stepper.target = self …Issue #408
Podfile
pod 'MASShortcut'
let shortcut = MASShortcut(keyCode: kVK_ANSI_K, modifierFlags: [.command, .shift])
MASShortcutMonitor.shared()?.register(shortcut, withAction: {
self.showPopover(sender: self.statusItem.button)
})
Issue #407
https://developer.apple.com/documentation/appkit/nsworkspace/1524399-selectfile
In macOS 10.5 and later, this method does not follow symlinks when selecting the file. If the fullPath parameter contains any symlinks, this method selects …
Issue #406
let progressIndicator = NSProgressIndicator()
progressIndicator.isIndeterminate = true
progressIndicator.style = .spinning
progressIndicator.startAnimation(nil)
Issue #405
Enable Read/Write for User Selected File under Sandbox to avoid bridge absent error
func showSave(
name: String,
window: NSWindow
) async -> URL? {
let panel = NSSavePanel()
panel.directoryURL = FileManager.default. …Issue #404
let animation = CAKeyframeAnimation(keyPath: "position.y")
animation.values = [50, 20, 50]
animation.keyTimes = [0.0, 0.5, 1.0]
animation.duration = 2
animation.repeatCount = Float.greatestFiniteMagnitude
animation.autoreverses = …Issue #403
The application sends this message to your delegate when the application’s last window is closed. It sends this …
Issue #401
Find identity
security find-identity
Sign with entitlements and identity. For macOS, use 3rd Party Mac Developer Application
codesign -f -s "3rd Party Mac Developer Application: Khoa Pham (123DK123F2)" --entitlements …Issue #339
For simple cases, we don’t need to. Let’s use urlCache
The URL cache for providing cached responses to requests within the session.
The URL Loading System caches responses both in memory and on disk, …
Issue #336
Use NSPopUpButton
var pullsDown: Bool
A Boolean value indicating whether the button displays a pull-down or pop-up menu.
func addItem(withTitle: String)
Adds an item with the specified title to the end of the menu.
Should disable …
Issue #334
NSSecureCoding has been around since iOS 6 and has had some API changes in iOS 12
A protocol that enables encoding and decoding in a manner that is robust against object substitution attacks. …
Issue #332
From moveItem(at:to:)
Moves an item from one location to another in the collection view.
After rearranging items in your data source object, use this method to synchronize those changes with the collection view. Calling this method lets …
Issue #331
From NSSegmentedControl
The features of a segmented control include the following: A segment can have an image, text (label), menu, tooltip, and tag. A segmented control can contain images or text, but not both.
let languageMenu = NSMenu( …Issue #330
When adding NSTextView in xib, we see it is embedded under NSClipView. But if we try to use NSClipView to replicate what’s in the xib, it does not scroll.
To make it work, we can follow Putting an NSTextView Object in an NSScrollView …
Issue #328
Sometimes we want to validate forms with many fields, for example name, phone, email, and with different rules. If validation fails, we show error message.
We can make simple Validator and Rule
class Validator {
func validate(text: …Issue #323
Use proxy animator()
let indexPath = IndexPath(item: index, section: 0)
collectionView.animator().deleteItems(at: Set(arrayLiteral: indexPath))
let indexPath = IndexPath(item: 0, section: 0)
collectionView.animator().insertItems(at: Set( …Issue #322
lazy var gr = NSClickGestureRecognizer(target: self, action: #selector(onPress(_:)))
gr.buttonMask = 0x2
gr.numberOfClicksRequired = 1
view.addGestureRecognizer(gr)
Issue #321
class ClickedCollectionView: NSCollectionView {
var clickedIndex: Int?
override func menu(for event: NSEvent) -> NSMenu? {
clickedIndex = nil
let point = convert(event. …Issue #320
NSTextAttachmentCellProtocolRich Text and GraphicsIssue #319
ATSApplicationFontsPath …
Issue #312
class ClosableWindow: NSWindow {
override func close() {
self.orderOut(NSApp)
}
}
let window = ClosableWindow(
contentRect: rect,
styleMask: [.titled, .closable],
backing: .buffered,
defer: false
}
window. …Issue #297
let button = NSButton()
button.wantsLayer = true
button.isBordered = false
button.setButtonType(.momentaryChange)
button.attributedTitle = NSAttributedString(
string: "Click me",
attributes: [
NSAttributedString.Key …Issue #296
Original answer https://stackoverflow.com/a/54793979/1418457
In your NSCollectionViewItem subclass, override isSelected and change background color of the layer. Test in macOS 10.14 and Swift 4.2
class Cell: NSCollectionViewItem { …Issue #274
Original post https://hackernoon.com/20-recommended-utility-apps-for-macos-in-2018-ea494b4db72b
Depending on the need, we have different apps on the mac. As someone who worked mostly with development, below are my indispensable apps. They …
Issue #245
Original post https://medium.com/fantageek/my-favourite-wwdc-2018-sessions-363d3fc9c9d5
This year I failed the lottery ticket to WWDC, and I also missed the keynote live stream because I was sailing on the …
Issue #243
From https://developer.apple.com/documentation/coregraphics/1455137-cgwindowlistcopywindowinfo
Generates and returns information about the selected windows in the current user session.
struct MyWindowInfo {
let frame: CGRect
let …Issue #242
let window = NSWindow(contentRect: mainScreen.frame, styleMask: .borderless, backing: .buffered, defer: false)
window.level = .floating
window.contentView = NSView()
window.makeKeyAndOrderFront(NSApp)
NSApp.activate(ignoringOtherApps: true …Issue #238
“App” is damaged and can’t be opened. You should move it to the Trash.
👉 Disable gate keeper
sudo spctl --master-disable
spctl --status
Current workaround is to remove Launch At Login handling code.
Issue #233
Shake
let midX = box.layer?.position.x ?? 0
let midY = box.layer?.position.y ?? 0
let animation = CABasicAnimation(keyPath: "position")
animation.duration = 0.06
animation.repeatCount = 4 …Issue #223
let script =
"""
tell application "XcodeWay"
activate
end tell
"""
let command = "osascript -e '\(script)'"
let process = Process()
process.launchPath …Issue #217
https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes
The command line tools will search the SDK for system headers by default. However, some software may fail to build correctly against the SDK and require …
Issue #213
Use Runloop
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { [weak self] _ in
let date = Date()
self?.updateStopItem(seconds: finishDate.timeIntervalSince1970 - date.timeIntervalSince1970)
}) …Issue #205
https://developer.apple.com/documentation/servicemanagement/1501557-smloginitemsetenabled
SMLoginItemSetEnabled
Enable a helper application located in the main application bundle’s “Contents/Library/LoginItems” …
Issue #203
https://developer.apple.com/news/?id=04102019a
With the public release of macOS 10.14.5, we require that all developers creating a Developer ID certificate for the first time notarize their apps, and that all …
Issue #201
Go to both app and extension target, under Capabilities, enable AppGroup
Specify $(TeamIdentifierPrefix)group.com.onmyway133.MyApp
$(TeamIdentifierPrefix) will expand to something like T78DK947F3., with .
Then using is like a …
Issue #200
let home = NSSearchPathForDirectoriesInDomains(.applicationScriptsDirectory, .userDomainMask, true).first!
let path = home.appending(".XcodeWayExtensions/XcodeWayScript.scpt")
let exists = FileManager.default.fileExists(atPath: …Issue #178
Install ffmpeg, which installs ffprobe
brew install ffmpeg
Find location of installed ffmpeg
which ffmpeg
Add all executables to project
Get error
unable to obtain file audio codec with ffprobe
Run in verbose mode
ffmpeg -v
Get
[debug] …
Issue #177
This is useful to refer to another executable in a running executable in Process
Bundle.main.path(forResource: "ffmpeg", ofType: "")!
Issue #176
Enable executable
chmod +x executable
Add executable file to target
Use Process with correct launchPad
import Foundation
protocol TaskDelegate: class {
func task(task: Task, didOutput string: String)
func taskDidComplete(task: Task)
} …Issue #175
let process = Process()
process.launchPath = "/bin/pwd"
process.arguments = []
Should be the same as FileManager.default.currentDirectoryPath
Issue #174
Disable vibrancy mode of NSPopover
let popover = NSPopover()
popover.appearance = NSAppearance(named: NSAppearance.Name.aqua)
Issue #173
You might need to flip NSClipView
import AppKit
import Anchors
import Omnia
final class ScrollableStackView: NSView {
final class FlippedClipView: NSClipView {
override var isFlipped: Bool {
return true
} …Issue #171
var views: NSArray?
NSNib(nibNamed: NSNib.Name("ProfileView"), bundle: nil)?.instantiate(withOwner: nil, topLevelObjects: &views)
let profileView = views!.compactMap({ $0 as? ProfileView }).first!
Issue #140
I need to generate QR code in https://github.com/onmyway133/AddressGenerator. Fortunately with CoreImage filter, it is very easy. Code is in Swift 4
import AppKit
final class QRCodeGenerator {
func generate(string: String, size: CGSize) …Issue #131
Here’s how to create NSCollectionView programatically. We need to embed it inside NScrollView for scrolling to work. Code is in Swift 4
let layout = NSCollectionViewFlowLayout()
layout.minimumLineSpacing = 4 …Issue #94
One thing I like about kickstarter-ios is how they use Playground to quickly protoyping views.
We use Swift Playgrounds for iterative development and styling. Most major screens in the app get a corresponding playground where we can see a …
Issue #91
I’m familiar with the whole app structure that Xcode gives me when I’m creating new macOS project, together with Storyboard. The other day I was reading touch-bar-simulator and see how it declares app using only code. See this …
Issue #86
Today I met a strange problem. After I enter my password, the progress bar runs to the end, and it is stuck there forever. No matter how many times I try to restart.
I finally need to go to Recovery mode by pressing Cmd+R at start up. I …
Issue #34
In an iOS project, we often see this in AppDelegate
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions …Issue #23
Returns whether the constraints impacting the layout of the view incompletely specify the location of the view.
This method randomly changes the frame of a view with an ambiguous layout between …
Issue #6
I like writing with markdown, it gives me comfortable experience with complete control over what I want to write.
I recommend vmd which renders exactly as GitHub. vmd is for rendering only, you need an editor to write, I use Sublime Text …
Issue #999
We want to take a timezone like "Europe/Oslo" and figure out what its offset is compared to UTC. During winter, Oslo is +01:00 (one hour ahead), and during summer it’s +02:00 (daylight saving time).
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 …
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 …
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 …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 …
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 …
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 …
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 …
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 = …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: …Issue #950
Inspired by shadcn
Combine
import { clsx, type ClassValue } from "clsx" …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 …
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 …Issue #751
Declare data/package.json to make it into node module
{
"name": "data",
"version": "0.1.0",
"private": true,
"homepage": ".",
"main": "main.js"
} …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 …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 ( …Issue #669
Specify params as array [year, id], not object {year, id}
const { year, id } = props
useEffect(() => {
const loadData = async () => {
try {
} catch (error) {
console. …Issue #664
Use moment-timezone https://momentjs.com/timezone/docs/
npm install moment-timezone
// public/index.html
<script src="moment.js"></script>
<script src="moment-timezone-with-data.js"></script>
Need …
Issue #661
Use Bulma css
<input
class="input is-rounded"
type="text"
placeholder="Say something"
value={value}
onChange={(e) => { onValueChange(e.target.value) }}
onKeyDown={(e) => {
if …Issue #661
Use Bulma css
<input
class="input is-rounded"
type="text"
placeholder="Say something"
value={value}
onChange={(e) => { onValueChange(e.target.value) }}
onKeyDown={(e) => {
if …Issue #659
Use useLocation https://reacttraining.com/react-router/web/guides/scroll-restoration
import React, { useEffect } from 'react';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useLocation,
withRouter
} …Issue #658
Declare routes, use exact to match exact path as finding route is from top to bottom. For dynamic route, I find that we need to use render and pass the props manually.
Declare Router as the rooter with Header, Content and Footer. Inside …
Issue #657
Add library folder src/library
src
library
res.js
screens
Home
index.js
package.json
Declare package.json in library folder
{
"name": "library",
"version": "0.0.1" …Issue #648
In a similar fashion to plain old javascript, note that href needs to have valid hash tag, like #features
<a
href='#features'
onClick={() => {
const options = {
behavior: 'smooth'
} …Issue #643
Use material icons
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
div#filter-container {
display: flex;
align-items: center;
justify-content: center;
margin-top: …Issue #641
Create a new page
hexo new page mydemo
Remove index.md and create index.html, you can reference external css and js in this index.html. Hexo has hexo new page mydemo --slug but it does not support page hierarchy
Specify no layout so it is …
Issue #640
async function useCache(
collectionName: string,
key: string,
response: functions.Response<any>,
fetch: () => Promise<any>
): Promise<any> {
const existing = await db.collection(collectionName). …Issue #552
type Components = {
day: number,
month: number,
year: number
}
export default class DateFormatter {
// 2018-11-11T00:00:00
static ISOStringWithoutTimeZone = (date: Date): string => {
const components = DateFormatter. …Issue #492
Suppose we have a base Localizable.strings
"open" = "Open";
"closed" = "Closed";
After sending that file for translations, we get translated versions.
"open" = "Åpen";
"closed" = …Issue #476
React Native comes with a default React library, and most CocoaPods libraries for React Native has React as a dependency pod, which causes the conflict
Issue #430
npm install electron-builder@latest --save-dev
package.json
{
"name": …Issue #423
Add 4 A records
A @ 185.199.110.153
A @ 185.199.111.153
A @ 185.199.108.153
A @ 185.199.109.153
and 1 CNAME record
CNAME www learntalks.github.io
learntalks.comIssue #420
const normalized = string
.replace(/\//g, '')
.replace(/\"/g, '')
.replace(/\(/g, '')
.replace(/\)/g, '')
Issue #419
function write(json) {
const data = JSON.stringify(json)
const year = json.date.getFullYear()
const directory = `collected/${slugify(className)}/${year}`
fs.mkdirSync(directory, { recursive: true })
fs.writeFileSync( …Issue #418
Path for user users/nsspain/videos
Path for showcase https://developer.vimeo.com/api/reference/albums#get_album
Path for Channels, Groups and Portfolios
const Vimeo = require('vimeo').Vimeo
const vimeoClient = new Vimeo( …Issue #417
class Youtube {
async getVideos(playlistId, pageToken) {
const options = {
key: clientKey,
part: 'id,contentDetails,snippet',
playlistId: playlistId,
maxResult: 100, …Issue #416
// @flow
const toPromise = (f: (any) => void) => {
return new Promise<any>((resolve, reject) => {
try {
f((result) => {
resolve(result)
})
} catch (e) {
reject(e)
}
})
}
const …Issue #415
https://stackoverflow.com/questions/44391448/electron-require-is-not-defined
function createWindow () {
win = new BrowserWindow({
title: 'MyApp',
width: 600,
height: 500, …Issue #400
Issue #399
App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Main from './Main'
class App extends …Issue #398
Dependencies
const Rx = require('rxjs/Rx')
const Fetch = require('node-fetch') …Issue #393
https://developer.github.com/v4/explorer/
query {
repository(owner: "onmyway133", name: "blog") {
issues(orderBy: {field: UPDATED_AT, direction: ASC}, last: 100) {
edges {
cursor
node { …Issue #392
It’s been a long journey since https://github.com/onmyway133/blog/issues/1, next step is to keep GitHub issues as source, and mirror those to a static site.
Use 2 repos
Issue #391
People who make fun of Javascript probably don’t understand implicit type coersion and when to use triple equal. Javascript is very unexpected, but when we work with this language, we need to be aware.
- Coercion–Automatically …
Issue #390
An object ’s property can be null or undefined.
Accessing step by step is tedious
props.user &&
props.user.posts &&
props.user.posts[0] &&
props.user.posts[0].comments
Dynamic parsing path is too clever and …
Issue #389
Prefer flow over TypeScript for simplicity
Javascript primitive types number and string are too general and do not express the domain objects. Because lack of type alias in Javascript, we can use flow
export type Centimeter = number
export …Issue #352
For a normal electron app created with npm init, we can use all features of ES6, but not the JSX syntax for React. We can use just Babel to transpile JSX, as used in IconGenerator
.babelrc
{
"plugins": [ …Issue #342
Install electron as dev npm install electron --save-dev
Update electron-packager npm install electron-packager@latest --save-dev
Use no space in app name
Follow …
Issue #327
In terms of tests, we usually have files for unit test, UI test, integeration test and mock.
Out of sight, out of mind.
Unit tests are for checking specific functions and classes, it’s more convenient to browse them side by side …
Issue #279
Original post https://medium.com/fantageek/what-is-create-react-native-app-9f3bc5a6c2a3
As someone who comes to React Native from iOS and Android background, I like React and Javascript as much as I like Swift and Kotlin. React Native is …
Issue #271
Original post https://hackernoon.com/how-to-make-tag-selection-view-in-react-native-b6f8b0adc891
Besides React style programming, Yoga is another cool feature of React Native. It is a cross-platform layout engine which implements Flexbox …
Issue #270
As you know, in the Pragmatic Programmer, section Your Knowledge Portfolio, it is said that
Learn at least one new language every year. Different languages solve the same problems in different ways. By learning several different …
Issue #268
React Native was designed to be “learn once, write anywhere,” and it is usually used to build cross platform apps for iOS and Android. And for each app that we build, there are times we need to reuse the same code, build and tweak it a bit …
Issue #266
Original post https://medium.freecodecamp.org/get-to-know-different-javascript-environments-in-react-native-4951c15d61f5
React Native can be very easy to get started with, and then at some point problems occur and we need to dive deep …
Issue #264
Original post https://medium.com/react-native-training/react-native-bridging-how-to-make-linear-gradient-view-83c3805373b7
React Native lets us build mobile apps using only Javascript. It works by providing a common interface that talks …
Issue #263
Original post https://medium.com/react-native-training/how-to-dismiss-keyboard-with-react-navigation-in-react-native-apps-4b987bbfdc48
Showing and dismiss keyboard seems like a trivial thing to do in mobile apps, but it can be tricky in …
Issue #256
Original post https://medium.freecodecamp.org/how-to-structure-your-project-and-manage-static-resources-in-react-native-6f4cfc947d92
React and React Native are just frameworks, and they do not dictate how we should structure our projects. …
Issue #254
Original post https://stackoverflow.com/a/54108708/1418457
Make our own convenient OverlayContainer. The trick is to use absolute with 100% size
// @flow
import React from 'react'
import { View, StyleSheet } from …Issue #252
Read more https://medium.com/flawless-app-stories/how-to-make-auto-layout-more-convenient-in-ios-df3b42fed37f
This is a script to remove Cartography, and use plain NSLayoutAnchor syntax. Use Constraint.on() from Sugar. It will …
Issue #251
function sort() {
const string =
`
- Favorite WWDC 2017 sessions https://github.com/onmyway133/blog/issues/56
- Favorite WWDC 2018 sessions https://github.com/onmyway133/blog/issues/245
- How to do clustering with Google Maps in iOS …Issue #192
Read https://www.apollographql.com/docs/react/features/error-handling How to catch actual error https://github.com/apollographql/apollo-client/issues/4016 🤔
import { Observable } from 'apollo-link'
import ApolloClient from …Issue #185
You may encounter curry in everyday code without knowing it. Here is a bit of my reflections on curry and how to apply it in Javascript and Swift.
In Haskell, all function officially takes only 1 parameter. …
Issue #179
let rough = context.objectForKeyedSubscript("myObject")
myObject.toDictionary()
Issue #62
Issue #991
When building apps in SwiftUI or React, we often need to store values that change — like a counter, user input, or a list of items.
To do this:
useState.@State and @StateObject.But here’s something cool: …
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 …
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 …
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 …
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 …
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:
The first …
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 …
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 = …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.
From client, we can get session from 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 …
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 = …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 …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 …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 …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: …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 …Issue #751
Declare data/package.json to make it into node module
{
"name": "data",
"version": "0.1.0",
"private": true,
"homepage": ".",
"main": "main.js"
} …Issue #700
In index.css
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica …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 ( …Issue #669
Specify params as array [year, id], not object {year, id}
const { year, id } = props
useEffect(() => {
const loadData = async () => {
try {
} catch (error) {
console. …Issue #665
Usually in header we have logo that takes user back to the home page
// index.js
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from 'react-router-dom'
<Router>
<Switch>
<Route …Issue #664
Use moment-timezone https://momentjs.com/timezone/docs/
npm install moment-timezone
// public/index.html
<script src="moment.js"></script>
<script src="moment-timezone-with-data.js"></script>
Need …
Issue #663
/** @jsx jsx */
import { css, jsx } from '@emotion/core'
import React from 'react';
import videojs from 'video.js'
export default class VideoPlayer extends React.Component {
componentDidMount() {
// …Issue #662
Use spread operator
import React, { Component, useState, useEffect } from 'react';
const [state, setState] = useState({
message: '',
chats: [],
sending: false
})
setState(prevState => ({ …Issue #661
Use Bulma css
<input
class="input is-rounded"
type="text"
placeholder="Say something"
value={value}
onChange={(e) => { onValueChange(e.target.value) }}
onKeyDown={(e) => {
if …Issue #661
Use Bulma css
<input
class="input is-rounded"
type="text"
placeholder="Say something"
value={value}
onChange={(e) => { onValueChange(e.target.value) }}
onKeyDown={(e) => {
if …Issue #659
Use useLocation https://reacttraining.com/react-router/web/guides/scroll-restoration
import React, { useEffect } from 'react';
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useLocation,
withRouter
} …Issue #658
Declare routes, use exact to match exact path as finding route is from top to bottom. For dynamic route, I find that we need to use render and pass the props manually.
Declare Router as the rooter with Header, Content and Footer. Inside …
Issue #657
Add library folder src/library
src
library
res.js
screens
Home
index.js
package.json
Declare package.json in library folder
{
"name": "library",
"version": "0.0.1" …Issue #655
Declare state and setState
export default function Showcase(props) {
const factory = props.factory
const [state, setState] = useState(
{
factory,
selectedFilter: { name: '' }
}
) …Issue #654
Use shelljs to execute shell commands, and fs to read and write. In public/index.html specify some placeholder and we will replace those in our script
const fs = require('fs');
const shell = require('shelljs')
let …Issue #654
A good landing page is one of the most crucial part of a successful launch. Recently I started creating landing pages for my apps, I was lazy that I ended creating a white label React app as a landing template and then write a script to …
Issue #653
Use https://github.com/biati-digital/glightbox
Configure css. Specify class='glightbox for html elements
<link rel="stylesheet" href="css/blueimp-gallery.min.css" />
Install package
npm install glightbox
import …Issue #652
Use https://github.com/michalsnik/aos
Add link to head
<head>
<link rel="stylesheet" href="https://unpkg.com/aos@next/dist/aos.css" />
</head>
Jus before closing body tag
<script src= …Issue #649
Check flag then define css
const Picture = (feature) => {
const shadowCss = feature.shadow ? css`
border-radius: 5px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
` : css`` …Issue #648
In a similar fashion to plain old javascript, note that href needs to have valid hash tag, like #features
<a
href='#features'
onClick={() => {
const options = {
behavior: 'smooth'
} …Issue #647
emotion can be used in framework agnostic or with React. To use with React, follow https://emotion.sh/docs/introduction#react
npm i @emotion/core
Note that you must have /** @jsx jsx */ at the top of the file, and the unused jsx in import …
Issue #352
For a normal electron app created with npm init, we can use all features of ES6, but not the JSX syntax for React. We can use just Babel to transpile JSX, as used in IconGenerator
.babelrc
{
"plugins": [ …Issue #192
Read https://www.apollographql.com/docs/react/features/error-handling How to catch actual error https://github.com/apollographql/apollo-client/issues/4016 🤔
import { Observable } from 'apollo-link'
import ApolloClient from …Issue #190
render() {
<Button color="inherit" onClick={this.onImagePress} >Image</Button>
<input ref="fileInput" type="file" id="myFile" multiple accept="image/*" style={{display: …Issue #555
Synthetic properties generated by Kotlin Android Extensions plugin needs a view for Fragment/Activity to be set before hand.
In your case, for Fragment, you need to use view.btn_K in onViewCreated
override fun onCreateView(inflater: …
Issue #497
Synthetic properties generated by Kotlin Android Extensions plugin needs a view for Fragment/Activity to be set before hand.
In your case, for Fragment, you need to use view.btn_K in onViewCreated
override fun onCreateView(inflater: …
Issue #472
Use convenient code from Omnia
To make view height dynamic, pin UILabel to edges and center
import UIKit
final class ErrorMessageView: UIView {
let box: UIView = {
let view = UIView()
view. …Issue #466
iOS
View Controller -> View Model | Logic Handler -> Data Handler -> Repo
Android
Activity -> Fragment -> View Model | Logic Handler -> Data Handler -> Repo
Issue #431
build.gradle
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath …Issue #397
We recommend that, rather than disabling the preview window, you follow the common Material Design patterns. You can use the activity’s windowBackground theme attribute to provide a simple custom drawable for the starting activity. …
Issue #396
Use app:headerLayout
<com.google.android.material.navigation.NavigationView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/navigationView" …Issue #383
Right click res -> New -> Android Resource Directory, select anim and name it anim
Right click res/anim -> New -> Android Resource file, name it bounce
<?xml version="1.0" encoding="utf-8"?>
<set …Issue #382
import android.content.Context
fun Int.toDp(context: Context?): Int {
if (context != null) {
val scale = context.resources.displayMetrics.density
return (this.toFloat() * scale + 0.5f).toInt()
} else { …Issue #381
From API < 17, there is ViewCompat.generateViewId() For API 17, there is View.generateViewId()
Note that to use ConstraintSet, all views under ConstraintLayout inside xml must have unique id
val imageView = ImageView(context)
imageView. …Issue #380
https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts
Android 8.0 (API level 26) and Android Support Library 26 introduce support for APIs to request fonts from a provider application instead of …
Issue #379
interface Api {
@GET("topstories.json?print=pretty")
suspend fun getTopStories(): List<Int>
@GET("item/{id}.json?print=pretty")
suspend fun getStory(@Path("id") id: Int): Item
}
class Repo { …Issue #378
After having a generic RecyclerView, if we want to show multiple kinds of data in Fragment, we can use generic.
We may be tempted to use interface or protocol, but should prefer generic.
class FeedFragment() : Fragment() {
override fun …Issue #370
Define response model
import com.squareup.moshi.Json
data class Response(
@field:Json(name="data") val data: ResponseData
)
data class ResponseData(
@field:Json(name="posts") val posts: Posts
)
data class Posts( …Issue #367
https://api.github.com/search/repositories?sort=stars&order=desc&q=language:javascript,java,swift,kotlin&q=created:>2019-08-21
interface Api {
@GET("https://api.github.com/search/repositories")
suspend fun …Issue #366
Code uses Retrofit 2.6.0 which has Coroutine support
app/build.gradle
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha01"
implementation "com.squareup.moshi:moshi:$Version.moshi"
implementation …Issue #363
https://medium.com/androiddevelopers/viewmodels-a-simple-example-ed5ac416317e
Rotating a device is one of a few configuration changes that an app can go through during its lifetime, including keyboard …
Issue #359
app/build.gradle
implementation "org.koin:koin-core:$Version.koin"
implementation "org.koin:koin-androidx-scope:$Version.koin"
implementation "org.koin:koin-androidx-viewmodel:$Version.koin"
MyApplication.kt
import …Issue #358
app/build.gradle
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha01"
import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData
import kotlinx.coroutines.Dispatchers
class MainViewModel : ViewModel …Issue #357
generic/Adapter.kt
package com.onmyway133.generic
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
abstract class Adapter<T>(var items: …Issue #351
From Gradle tips and recipes, Configure project-wide properties
For projects that include multiple modules, it might be useful to define properties at the project level and share them across all modules. You can do this by adding extra …
Issue #349

build.gradle
dependencies {
classpath 'android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0-alpha05'
}
app/build.gradle
apply plugin: 'androidx.navigation.safeargs'
dependencies {
def navigationVersion …Issue #338
Gradle uses Groovy and it has ext, also known as ExtraPropertiesExtension
Additional, ad-hoc, properties for Gradle domain objects.
Extra properties extensions allow new properties to be added to existing domain objects. They act like …
Issue #285
settings.gradle.kts
include(":app")
build.gradle.kts
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.kotlin
import org.gradle.kotlin.dsl.*
import …Issue #273
Original post https://hackernoon.com/using-bitrise-ci-for-android-apps-fa9c48e301d8
CI, short for Continuous Integration, is a good practice to move fast and confidently where code is integrated into shared repository many times a day. …
Issue #257
Checkstyle is a development tool to help programmers write Java code that adheres to a coding standard. It automates the process of checking …
Issue #188
Get error com.google.android.gms.common.api.ApiException: 10 with google_sign_in package.
Read https://developers.google.com/android/guides/client-auth
Certain Google Play services (such as Google Sign-in and App Invites) require you to …
Issue #184
Get error javax.net.ssl.SSLPeerUnverifiedException: No peer certificate in Android API 16 to API 19
Read about HTTPS and SSL https://developer.android.com/training/articles/security-ssl Check backend TLS …
Issue #152
This is the part 2 of the tutorial. If you forget, here is the link to part 1.
Link to Github
In the first part, we learn about the idea, the structure of the project and how MainActivity uses the MainLayout. Now we learn how to actually …
Issue #151
This post was from long time ago when I did Android
I can’t deny that Facebook is so amazing, they made trends and people want to follow. That is the case of the sliding menu.
Searching many threads on SO, like these create android …
Issue #123
From https://kotlinlang.org/docs/reference/coroutines.html
To continue the analogy, await() can be a suspending function (hence also callable from within an async {} block) that suspends a coroutine until some …
Issue #109
People advise against storing keys inside build.gradles. We should store them on 1Password and populate our gradle.properties, so don’t track this file in git. Here is .gitignore file
*.iml
/build
/gradle.properties …Issue #108
There’s always need for communication, right 😉 Suppose we have OnboardingActivity that has several OnboardingFragment. Each Fragment has a startButton telling that the onboarding flow has finished, and only the last Fragment shows …
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. …
Issue #555
Synthetic properties generated by Kotlin Android Extensions plugin needs a view for Fragment/Activity to be set before hand.
In your case, for Fragment, you need to use view.btn_K in onViewCreated
override fun onCreateView(inflater: …
Issue #497
Synthetic properties generated by Kotlin Android Extensions plugin needs a view for Fragment/Activity to be set before hand.
In your case, for Fragment, you need to use view.btn_K in onViewCreated
override fun onCreateView(inflater: …
Issue #431
build.gradle
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath …Issue #388
https://kotlinlang.org/docs/reference/coroutines/flow.html
Using List
result type we can only return all the values at once. To represent the stream of values that are being asynchronously computed we can use Flow type …
Issue #383
Right click res -> New -> Android Resource Directory, select anim and name it anim
Right click res/anim -> New -> Android Resource file, name it bounce
<?xml version="1.0" encoding="utf-8"?>
<set …Issue #382
import android.content.Context
fun Int.toDp(context: Context?): Int {
if (context != null) {
val scale = context.resources.displayMetrics.density
return (this.toFloat() * scale + 0.5f).toInt()
} else { …Issue #381
From API < 17, there is ViewCompat.generateViewId() For API 17, there is View.generateViewId()
Note that to use ConstraintSet, all views under ConstraintLayout inside xml must have unique id
val imageView = ImageView(context)
imageView. …Issue #380
https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts
Android 8.0 (API level 26) and Android Support Library 26 introduce support for APIs to request fonts from a provider application instead of …
Issue #379
interface Api {
@GET("topstories.json?print=pretty")
suspend fun getTopStories(): List<Int>
@GET("item/{id}.json?print=pretty")
suspend fun getStory(@Path("id") id: Int): Item
}
class Repo { …Issue #378
After having a generic RecyclerView, if we want to show multiple kinds of data in Fragment, we can use generic.
We may be tempted to use interface or protocol, but should prefer generic.
class FeedFragment() : Fragment() {
override fun …Issue #370
Define response model
import com.squareup.moshi.Json
data class Response(
@field:Json(name="data") val data: ResponseData
)
data class ResponseData(
@field:Json(name="posts") val posts: Posts
)
data class Posts( …Issue #367
https://api.github.com/search/repositories?sort=stars&order=desc&q=language:javascript,java,swift,kotlin&q=created:>2019-08-21
interface Api {
@GET("https://api.github.com/search/repositories")
suspend fun …Issue #366
Code uses Retrofit 2.6.0 which has Coroutine support
app/build.gradle
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha01"
implementation "com.squareup.moshi:moshi:$Version.moshi"
implementation …Issue #359
app/build.gradle
implementation "org.koin:koin-core:$Version.koin"
implementation "org.koin:koin-androidx-scope:$Version.koin"
implementation "org.koin:koin-androidx-viewmodel:$Version.koin"
MyApplication.kt
import …Issue #358
app/build.gradle
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-alpha01"
import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData
import kotlinx.coroutines.Dispatchers
class MainViewModel : ViewModel …Issue #357
generic/Adapter.kt
package com.onmyway133.generic
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
abstract class Adapter<T>(var items: …Issue #349

build.gradle
dependencies {
classpath 'android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0-alpha05'
}
app/build.gradle
apply plugin: 'androidx.navigation.safeargs'
dependencies {
def navigationVersion …Issue #327
In terms of tests, we usually have files for unit test, UI test, integeration test and mock.
Out of sight, out of mind.
Unit tests are for checking specific functions and classes, it’s more convenient to browse them side by side …
Issue #285
settings.gradle.kts
include(":app")
build.gradle.kts
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.dependencies
import org.gradle.kotlin.dsl.kotlin
import org.gradle.kotlin.dsl.*
import …Issue #270
As you know, in the Pragmatic Programmer, section Your Knowledge Portfolio, it is said that
Learn at least one new language every year. Different languages solve the same problems in different ways. By learning several different …
Issue #147
Each language and platform has its own coding style guide. This goes true when it comes to abbreviations. I’ve had some debates about whether to use JSON or Json, URL or Url, HTTP or Http.
I personally prefer camelCase, so I’m …
Issue #139
From https://kotlinlang.org/docs/reference/lambdas.html
class HTML {
fun body() { ... }
}
fun html(init: HTML.() -> Unit): HTML {
val html = HTML() // create the receiver object
html.init() // pass the receiver …Issue #135
override fun adapt(call: Call<T>): …Issue #123
From https://kotlinlang.org/docs/reference/coroutines.html
To continue the analogy, await() can be a suspending function (hence also callable from within an async {} block) that suspends a coroutine until some …
Issue #114
Picture worths thousand words. Code worths thousand pictures. I don’t understand much until I take a look at Standard.kt in Kotlin standard library.
/**
* Calls the specified function [block] with `this` value as its receiver and …Issue #108
There’s always need for communication, right 😉 Suppose we have OnboardingActivity that has several OnboardingFragment. Each Fragment has a startButton telling that the onboarding flow has finished, and only the last Fragment shows …
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 …
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 …
Issue #638
Use commandDefinitions in XCSourceEditorExtension.
import Foundation
import XcodeKit
class SourceEditorExtension: NSObject, XCSourceEditorExtension {
func extensionDidFinishLaunching() {
}
var commandDefinitions: [[ …Issue #638
Use commandDefinitions in XCSourceEditorExtension.
import Foundation
import XcodeKit
class SourceEditorExtension: NSObject, XCSourceEditorExtension {
func extensionDidFinishLaunching() {
}
var commandDefinitions: [[ …Issue #601
On Xcode 11, applicationWillTerminate is not called because of default automatic termination on in Info.plist. Removing NSSupportsSuddenTermination to trigger will terminate notification
func applicationWillTerminate(_ notification: …Issue #572
After migrating a few pods to use SPM, some libraries fail to load. This is because the workspace now uses both SPM and cocoapods
code signature in … not valid for use in process using Library Validation: mapped file has no Team ID …
Issue #557
Use ProcessInfo to access environment variables.
ProcessInfo().environment["username"]
Duplicate main shared scheme TestApp to TestAppWithCredentials, but don’t share this TestAppWithCredentials scheme
Issue #545
Xcode 10 Localization catalog and XclocReader
Xcode 11 localized screenshots
Issue #544
man xcodebuild
XCODEBUILD(1) BSD General Commands Manual XCODEBUILD(1)
NAME
xcodebuild -- build Xcode projects and workspaces
SYNOPSIS
xcodebuild [-project name.xcodeproj] [[-target …Issue #543
Workspace has its own DerivedData folder
DerivedData
ModuleCache.noindex
workspace_name
Build
Products
Debug-iphonesimulator
Cat
Dog
Dog2
Index
Info.plist
Logs …Issue #541
A scheme, either for app or test, consists of actions
Used when Cmd+R. The executable specifies which app target to run
Used when Cmd+U. The tests specifies which test target to run
Test target recognises app …
Issue #540
-testLanguage language
Specifies ISO 639-1 language during testing. This overrides the setting for the test action of a
scheme in a workspace.
-testRegion region
Specifies ISO 3166-1 …Issue #539
extension XCTestCase {
func takeScreenshot(name: String) {
let screenshot = XCUIScreen.main.screenshot()
let attach = XCTAttachment(screenshot: screenshot)
attach.lifetime = .keepAlways …Issue #499
It turns on all the features that are necessary to build your library in such a way that it can be distributed
What does this error actually mean? Well, when the …
Issue #499
It turns on all the features that are necessary to build your library in such a way that it can be distributed
What does this error actually mean? Well, when the …
Issue #478
Dependencies used
Examples
Issue #343
Xcode 10.3 with iOS 13
sudo ln -s /Applications/Xcode-beta.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport/13.0 /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport
Xcode 10.3 with iOS 13.1 …
Issue #267
Original post https://medium.freecodecamp.org/how-to-convert-your-xcode-plugins-to-xcode-extensions-ac90f32ae0e3
Xcode is an indispensable IDE for iOS and macOS developers. From the early days, the ability to build and install custom …
Issue #237
Go to test target, under Host Application, select another app target, and select the preferred app target again
Issue #215
https://developer.apple.com/library/archive/qa/qa1915/_index.html
Xcode 7 and Xcode 8 allow you to select the free personal team provided with your Apple ID for signing your app. This team allows you to build apps for your personal use on …
Issue #207
Error
Message: "xcodebuild: error: invalid option '-teamID'
Use =
xcodebuild teamID=T78DK947F3
Does not work 😢
https://pewpewthespells.com/blog/migrating_code_signing.html
xcodebuild DEVELOPMENT_TEAM= …Issue #204
Compiling for OS X 10.11, but module 'MyApp' has a minimum deployment target of OS X 10.12: …Issue #201
Go to both app and extension target, under Capabilities, enable AppGroup
Specify $(TeamIdentifierPrefix)group.com.onmyway133.MyApp
$(TeamIdentifierPrefix) will expand to something like T78DK947F3., with .
Then using is like a …
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 …
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 …
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 …Issue #646
Pass DispatchQueue and call queue.sync to sync all async works before asserting
Use DispatchQueueType and in mock, call the work immediately
import Foundation
public protocol DispatchQueueType {
func …Issue #644
import XCTest
extension XCTestCase {
/// Asynchronously assertion
func XCTAssertWait(
timeout: TimeInterval = 1,
_ expression: @escaping () -> Void,
_: String = "",
file _: StaticString = …Issue #628
extension XCUIElementQuery: Sequence {
public typealias Iterator = AnyIterator<XCUIElement>
public func makeIterator() -> Iterator {
var index = UInt(0)
return AnyIterator {
guard index < …Issue #583
In UITests, we can use press from XCUIElement to test drag and drop
let fromCat = app.buttons["cat1"].firstMatch
let toCat = app.buttons["cat2"]
let fromCoordinate = fromCat.coordinate(withNormalizedOffset: CGVector(dx: 0, …Issue #576
See Spek
https://developer.apple.com/documentation/xctest/xctestcase/1496271-testinvocations
Returns an array of invocations representing each test method in the test case.
Because …
Issue #537
In xcodebuild, specify launch arguments.
You can specify this under Launch Arguments in Run action of the app scheme or UITest scheme
-AppleLanguages (jp) -AppleLocale (jp_JP)
(lldb) po ProcessInfo().arguments
▿ …Issue #484
Use SwiftMonkey which adds random UITests gestures
Add to UITests target
target 'MyAppUITests' do
pod 'R.swift', '~> 5.0'
pod 'SwiftMonkey', '~> 2.1.0'
end
Issue #478
Dependencies used
Examples
Issue #402
I want to test if a date has passed another date
let base = Date(timeIntervalSince1970: 1567756697)
XCTAssertEqual(validator.hasPassed(event: event, date: base), true)
My hasPassed is using Calendar.current
func minuteSinceMidnight(date: …Issue #327
In terms of tests, we usually have files for unit test, UI test, integeration test and mock.
Out of sight, out of mind.
Unit tests are for checking specific functions and classes, it’s more convenient to browse them side by side …
Issue #249
Making splash screen with LaunchScreen.storyboard is now the default way to do in iOS. Testing it with UITests is a bit tricky as this screen is showed the system, and if we test that, we are just testing the system.
What we should test is …
Issue #143
Today I was writing tests and get this error related to app idle
t = 23.06s Assertion Failure: <unknown>:0: Failed to scroll to visible (by AX action) Button, 0x6000003827d0, traits: 8858370049, label: 'cart', …Issue #48
Continue my post https://github.com/onmyway133/blog/issues/45. When you work with features, like map view, you mostly need permissions, and in UITests you need to test for system alerts.
This is the code. Note that …
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 …
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.
From client, we can get session from 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 …
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 = …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 …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 …
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 …Issue #935
I prefer UI Component that works with Nextjs and Tailwind CSS
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 …Issue #801
Read
npm install bulma sass
In styles/index.scss
@import '~bulma/bulma';
In _app.tsx
import '../styles/index.scss'
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 …
Issue #668
Use Firebase JS SDK
Go to Certificates, …
Issue #645
npm init
npm install webpack webpack-cli --save-dev
vim webpack.config.js
module.exports = {
entry: "./index.js",
mode: 'production',
output: {
filename: "./index.js"
}
}
To …
Issue #641
Create a new page
hexo new page mydemo
Remove index.md and create index.html, you can reference external css and js in this index.html. Hexo has hexo new page mydemo --slug but it does not support page hierarchy
Specify no layout so it is …
Issue #423
Add 4 A records
A @ 185.199.110.153
A @ 185.199.111.153
A @ 185.199.108.153
A @ 185.199.109.153
and 1 CNAME record
CNAME www learntalks.github.io
learntalks.comIssue #32
iOS 9 introduces new ways for your app to work better, backed by your websites
If the app is already installed on a user’s device, the banner intelligently changes its action, …
Issue #521
#import <React/RCTBridgeModule.h>
@interface RNSurveyManager : NSObject <RCTBridgeModule>
@end
#import "RNSurveyManager.h"
#import <React/RCTLog.h>
#import <SurveyMonkeyiOSSDK/SurveyMonkeyiOSSDK.h> …Issue #476
React Native comes with a default React library, and most CocoaPods libraries for React Native has React as a dependency pod, which causes the conflict
Issue #279
Original post https://medium.com/fantageek/what-is-create-react-native-app-9f3bc5a6c2a3
As someone who comes to React Native from iOS and Android background, I like React and Javascript as much as I like Swift and Kotlin. React Native is …
Issue #277
Original post https://codeburst.io/using-bitrise-ci-for-react-native-apps-b9e7b2722fe5
After trying Travis, CircleCI and BuddyBuild, I now choose Bitrise for my mobile applications. The many cool steps and workflows make Bitrise an ideal …
Issue #271
Original post https://hackernoon.com/how-to-make-tag-selection-view-in-react-native-b6f8b0adc891
Besides React style programming, Yoga is another cool feature of React Native. It is a cross-platform layout engine which implements Flexbox …
Issue #268
React Native was designed to be “learn once, write anywhere,” and it is usually used to build cross platform apps for iOS and Android. And for each app that we build, there are times we need to reuse the same code, build and tweak it a bit …
Issue #266
Original post https://medium.freecodecamp.org/get-to-know-different-javascript-environments-in-react-native-4951c15d61f5
React Native can be very easy to get started with, and then at some point problems occur and we need to dive deep …
Issue #264
Original post https://medium.com/react-native-training/react-native-bridging-how-to-make-linear-gradient-view-83c3805373b7
React Native lets us build mobile apps using only Javascript. It works by providing a common interface that talks …
Issue #263
Original post https://medium.com/react-native-training/how-to-dismiss-keyboard-with-react-navigation-in-react-native-apps-4b987bbfdc48
Showing and dismiss keyboard seems like a trivial thing to do in mobile apps, but it can be tricky in …
Issue #260
Original post https://medium.com/react-native-training/firebase-sdk-with-firestore-for-react-native-apps-in-2018-aa89a67d6934
At Firebase Dev Summit 2017, Google introduced Firestore as fully-managed NoSQL document database for mobile and …
Issue #259
React Native uses Yoga to achieve Flexbox style layout, which helps us set up layout in a …
Issue #256
Original post https://medium.freecodecamp.org/how-to-structure-your-project-and-manage-static-resources-in-react-native-6f4cfc947d92
React and React Native are just frameworks, and they do not dictate how we should structure our projects. …
Issue #254
Original post https://stackoverflow.com/a/54108708/1418457
Make our own convenient OverlayContainer. The trick is to use absolute with 100% size
// @flow
import React from 'react'
import { View, StyleSheet } from …Issue #100
For now, I still believe in native. Here are some interesting links
Issue #287
When digging into the world of TCP, I get many terminologies I don’t know any misconceptions. But with the help of those geeks on SO, the problems were demystified. Now it’s time to sum up and share with others :D
Issue #283
Original post https://medium.com/fantageek/dealing-with-css-responsiveness-in-wordpress-5ad24b088b8b
During the alpha test of LearnTalks, some of my friends reported that the screen is completely blank in search page, and this happened in …
Issue #281
A good theme and font can increase your development happiness a lot. Ever since using Atom, I liked its One Dark theme. The background and text colors are just elegant and pleasant to the eyes.
Original designed for Atom, …
Issue #274
Original post https://hackernoon.com/20-recommended-utility-apps-for-macos-in-2018-ea494b4db72b
Depending on the need, we have different apps on the mac. As someone who worked mostly with development, below are my indispensable apps. They …
Issue #269
Original post https://medium.com/swlh/introducing-learn-talks-awesome-conference-and-meetup-talks-e97c8cf7e0f
Product Hunt https://www.producthunt.com/posts/learn-talks
Hi, it’s Khoa here. I’m so glad to finally launch LearnTalks, in …
Issue #157
This post was from long time ago when I did pjsip
A jitter buffer temporarily stores arriving packets in order to minimize delay variations. If packets arrive too late then they are discarded. A jitter buffer may be mis-configured and be …
Issue #155
As you have probably observed in your studies, there is a determined method for calculating VoIP packet sizes. The packet size depends on many different variables, so there is no great answer for an “average” packet size …
Issue #153
Bad people can use Netcut to limit other ’s internet access in same network
Netcut uses attacking technique called ARP Spoofing.
ARP (Address Resolution Protocol) is a link layer procotol, it is used for …
Issue #146
To be written …
Old math equations become useful today 😍
v = 1 - x
Issue #115
According to HTML and URLs
URLs in general are case-sensitive (with the exception of machine names). There may be URLs, or parts of URLs, where case doesn’t matter, but identifying these may not be easy. …
Issue #112
I’m very fascinated when people use assembly to perform investigation, that’s just mind blowing 💥 . Here are some of the favorite use cases
Issue #105
Are you willing to take vaccines you don’t know about?
I like open source. I ’ve made some and contributed to some. I also use other people ’s open source libraries and learn a lot from them 😇
Open source can help us …
Issue #86
Today I met a strange problem. After I enter my password, the progress bar runs to the end, and it is stuck there forever. No matter how many times I try to restart.
I finally need to go to Recovery mode by pressing Cmd+R at start up. I …
Issue #84
Dear SDK developers,
Issue #740
How to gain product ideas?
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
Build any …
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
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 …
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 …
Issue #77
My question
What if there is no inheritance, so that everybody has the same start, does that make life fairer?
Issue #76
I use Twitter a lot, mostly to follow people I like. They tweet cool things about tech and life. I learned a lot.
Please don’t show me the evil sides of the world ~ Michael Learn To Rock - How Many Hours
But there’s also bad …
Issue #42
We will never know how life will go
Issue #31
I’m very happy to be on open source movement, and it ’ll be great to hear about what people have achieved
Issue #9
The other day I was watching Inside Sweden’s Silicon Valley, and he mentions Law of Jante
It is pretty much this
Issue #8
Some say these are from the book Dumbing Down America of Charles Sykes, some say they are from Bill Gates ’s speech to high school students. I don’t know the origin, but they are cool enough, so I tend to share it again and again …
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 …
Issue #751
Declare data/package.json to make it into node module
{
"name": "data",
"version": "0.1.0",
"private": true,
"homepage": ".",
"main": "main.js"
} …Issue #651
Use shelljs
npm install shelljs
const shell = require('shelljs')
shell.exec(`cp -a source_path/. destination_path`)
The -a option is an improved recursive option, that preserve all file attributes, and also preserve symlinks.
The …
Issue #650
Install
npm install @babel/core
npm install @babel/cli
npm install @babel/preset-env
Configure .babelrc
{
"presets": ["@babel/preset-env"]
}
In package.json, transpile using npx babel then node dist/index.js …
Issue #492
Suppose we have a base Localizable.strings
"open" = "Open";
"closed" = "Closed";
After sending that file for translations, we get translated versions.
"open" = "Åpen";
"closed" = …Issue #430
npm install electron-builder@latest --save-dev
package.json
{
"name": …Issue #419
function write(json) {
const data = JSON.stringify(json)
const year = json.date.getFullYear()
const directory = `collected/${slugify(className)}/${year}`
fs.mkdirSync(directory, { recursive: true })
fs.writeFileSync( …Issue #418
Path for user users/nsspain/videos
Path for showcase https://developer.vimeo.com/api/reference/albums#get_album
Path for Channels, Groups and Portfolios
const Vimeo = require('vimeo').Vimeo
const vimeoClient = new Vimeo( …Issue #417
class Youtube {
async getVideos(playlistId, pageToken) {
const options = {
key: clientKey,
part: 'id,contentDetails,snippet',
playlistId: playlistId,
maxResult: 100, …Issue #399
App.js
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import Main from './Main'
class App extends …Issue #398
Dependencies
const Rx = require('rxjs/Rx')
const Fetch = require('node-fetch') …Issue #252
Read more https://medium.com/flawless-app-stories/how-to-make-auto-layout-more-convenient-in-ios-df3b42fed37f
This is a script to remove Cartography, and use plain NSLayoutAnchor syntax. Use Constraint.on() from Sugar. It will …
Issue #57
I like node.js because it has many cool packages. I wish the same goes for macOS. Fortunately, the below solutions provide a way to package node.js modules and use them inside macOS applications. It can be slow, but you save time by using …
Issue #577
objc[45250]: Class AVAssetDownloadTask is implemented in both /Applications/Xcode.app/Contents/Developer/Platforms/ …Issue #511
struct CountriesView: View {
let groups: [Group]
init(countries: [Country]) {
self.groups = CountryManager.shared.groups(countries: countries)
}
var body: some View {
List {
ForEach(groups) { …Issue #504
https://twitter.com/NeoNacho/status/1181245484867801088?s=20
There’s no way to have platform specific sources or targets today, so you’ll have to take a different approach. I would recommend wrapping all OS specific files in #if os and …
Issue #482
lineLimit does not seem to work, use fixedSize instead
Fixes this view at its ideal size.
A view that fixes this view at its ideal size in the dimensions given in fixedDimensions.
extension Text {
func styleText() -> some View { …Issue #474
Go to Project -> Swift Packages, add package. For example https://github.com/onmyway133/EasyStash
Select your WatchKit Extension target, under Frameworks, Libraries and Embedded Content add the library
If we use CocoaPods, …
Issue #468
From onAppeear
Adds an action to perform when the view appears.
In theory, this should be triggered every time this view appears. But in practice, it is only called when it is pushed on navigation stack, not when we return to it.
So if …
Issue #467
Declare top dependencies in ExtensionDelegate
class ExtensionDelegate: NSObject, WKExtensionDelegate {
let storeContainer = StoreContainer()
func applicationDidEnterBackground() {
storeContainer.save()
}
}
Reference …
Issue #457
From Creating Independent watchOS Apps
The root target is a stub, and acts as a wrapper for your project, so that you can submit it to the App Store. The other two are identical to the targets found in a traditional watchOS project. They …
Issue #449
WatchKit does not have Web component, despite the fact that we can view web content
A workaround is to show url as QR code
import SwiftUI
struct QRCodeView: View {
let …Issue #448
Use ObservableObject and onReceive to receive event. URLSession.dataTask reports in background queue, so need to .receive(on: RunLoop.main) to receive events on main queue.
For better dependency injection, need to use ImageLoader from …
Issue #447
NavigationView is not available on WatchKit, but we can just use NavigationLink
List(services.map({ AnyService($0) })) { anyService in
NavigationLink(destination:
ItemsView(service: anyService.service)
. …Issue #918
Interesting SwiftUI Q&A during WWDC23
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 …
Issue #916
WWDC23 brings new additions to SwiftUI
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 …
Issue #905
Protect mutable state with Swift actors
Actor reentrancy
Imagine we have two different concurrent tasks trying to fetch the same image at the same time. The first sees that there is no cache entry, proceeds to start downloading the …
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
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 …
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
Issue #889



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

Section("Hashtags") { …Issue #888
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 …
Issue #56



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
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 …
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 …
Issue #734
In SwiftUI there are fixed frame and flexible frame modifiers.
Use this method to specify a fixed size for a view’s width, height, or both. If you only …
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 …
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) …
Issue #305

This year I’m lucky enough to get the ticket to WWDC and I couldn’t be more satisfied. 5 conference days full of awesomeness, talks, labs and networking, all make WWDC special and memorial conference for every attendee.
As …
Issue #268
React Native was designed to be “learn once, write anywhere,” and it is usually used to build cross platform apps for iOS and Android. And for each app that we build, there are times we need to reuse the same code, build and tweak it a bit …
Issue #258
I started iOS development when iOS 7 had been announced. And I have learned a bit, through working, advice from colleagues and the iOS community.
In this article, I’d like to share a lot of good practices by taking the example of a simple …
Issue #499
It turns on all the features that are necessary to build your library in such a way that it can be distributed
What does this error actually mean? Well, when the …
Issue #499
It turns on all the features that are necessary to build your library in such a way that it can be distributed
What does this error actually mean? Well, when the …
Issue #313
Push user-facing notifications to the user’s device from a server, or generate them locally from your app.
A class that animates changes to views and allows the dynamic modification …
Issue #313
Push user-facing notifications to the user’s device from a server, or generate them locally from your app.
A class that animates changes to views and allows the dynamic modification …
Issue #284
Before working with Windows Phone and iOS, my life involved researching VoIP. That was to build a C library for voice over IP functionality for a very popular app, and that was how I got started in open source.
The library I was working …
Issue #274
Original post https://hackernoon.com/20-recommended-utility-apps-for-macos-in-2018-ea494b4db72b
Depending on the need, we have different apps on the mac. As someone who worked mostly with development, below are my indispensable apps. They …
Issue #239
Do you know that questions about git get the most views on StackOverflow? I’ve searched a lot on Google how to execute certain actions with git, and this actually slowed me down a lot. There are some actions that we tend to use a lot, so …
Issue #563
The new Transporter app for macOS makes it easy to upload your binary to App Store Connect. To get started, download Transporter from the Mac App Store, and simply drag and …
Issue #549
public class Sequence: Task {
public func run(workflow: Workflow, completion: @escaping TaskCompletion) {
let semaphore = DispatchSemaphore(value: 0)
runFirst(tasks: tasks, workflow: workflow, completion: …Issue #544
man xcodebuild
XCODEBUILD(1) BSD General Commands Manual XCODEBUILD(1)
NAME
xcodebuild -- build Xcode projects and workspaces
SYNOPSIS
xcodebuild [-project name.xcodeproj] [[-target …Issue #540
-testLanguage language
Specifies ISO 639-1 language during testing. This overrides the setting for the test action of a
scheme in a workspace.
-testRegion region
Specifies ISO 3166-1 …Issue #534
Workaround
/Users/khoa/.rbenv/shims/bundler install
Issue #514
ssh-keygen -t rsa -C "onmyway133@gmail.com" -f "id_rsa_github"
ssh-keygen -t rsa -C "onmyway133bitbucket@gmail.com" -f "id_rsa_bitbucket"
pbcopy < ~/.ssh/id_rsa_github.pub
pbcopy < …Issue #512
git clone https://github.com/zsh-users/zsh-autosuggestions …Issue #238
“App” is damaged and can’t be opened. You should move it to the Trash.
👉 Disable gate keeper
sudo spctl --master-disable
spctl --status
Current workaround is to remove Launch At Login handling code.
Issue #950
Inspired by shadcn
Combine
import { clsx, type ClassValue } from "clsx" …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 …
Issue #649
Check flag then define css
const Picture = (feature) => {
const shadowCss = feature.shadow ? css`
border-radius: 5px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
` : css`` …Issue #643
Use material icons
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
div#filter-container {
display: flex;
align-items: center;
justify-content: center;
margin-top: …Issue #642
Specify container with flex-wrap and justify-content, and item with float: left
div.cards {
display: flex;
justify-content: center;
flex-direction: row;
flex-wrap: wrap;
margin-top: 10%;
}
div.card {
overflow: hidden;
float: …Issue #494
Remove max-width from source/css/style.styl
.outer
clearfix()
// max-width: (column-width + gutter-width) * columns + gutter-width
margin: 40px auto
padding: 0 gutter-width …Issue #208
During the alpha test of LearnTalks, some of my friends reported that the screen is completely blank in the search page, and this happened in mobile only. This article is how I identify the problem and found a workaround for the issue, it …
Issue #668
Use Firebase JS SDK
Go to Certificates, …
Issue #667
Edit package.json
"engines": {
"node": "10"
},
Go to settings/serviceaccounts/adminsdk, download secret key in form of json and place it in lib/config.json
const serviceAccount = require( …Issue #585
Follow the new Firebase Crashlytics guide Get started with Firebase Crashlytics using the Firebase Crashlytics SDK
Specify FirebaseCore for community managed macOS version of Firebase
platform :osx, …Issue #493
Declare in Podfile
pod 'Firebase/Core'
pod 'Firebase/RemoteConfig'
Use RemoteConfigHandler to encapsulate logic. We introduce Key with CaseIterable and defaultValue of type NSNumber to manage default values.
import Firebase …Issue #490
Vision Edge is part of MLKit, but for custom images training
https://console.firebase.google.com/u/0/project/avengers-ad2ce/ml/
Model Avengers_dataset_2019114133437 is training and may …
Issue #260
Original post https://medium.com/react-native-training/firebase-sdk-with-firestore-for-react-native-apps-in-2018-aa89a67d6934
At Firebase Dev Summit 2017, Google introduced Firestore as fully-managed NoSQL document database for mobile and …
Issue #1003
When you build iOS applications on a self-hosted Mac runner, your CI/CD pipeline is likely to encounter a frustrating issue:
Could not find 'bundler' (2.6.9) required by your Gemfile.lock
Your machine has bundler installed. You …
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, …
Issue #514
ssh-keygen -t rsa -C "onmyway133@gmail.com" -f "id_rsa_github"
ssh-keygen -t rsa -C "onmyway133bitbucket@gmail.com" -f "id_rsa_bitbucket"
pbcopy < ~/.ssh/id_rsa_github.pub
pbcopy < …Issue #481
docs folder
Issue #248
Visit https://github.com/onmyway133/onmyway133.github.io
https://github.blog/2017-11-29-use-any-theme-with-github-pages/
Starting today, you can use any of the hundreds of community-curated themes on GitHub.com. To build your site with …
Issue #118
GitHub identifies users by email, so you can totally commit using someone ’s email. This is how to configure in SourceTree

Issue #117
GitHub is so awesome. It is where people around the world collaborate with each other. It is more awesome to show more about you in your GitHub profile. How about a badge? a welcome text? It is doable with organization. GitHub takes time …
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
Issue #785
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 …
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 …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 …
Issue #623
Listen to context changes notification and change SwiftUI View state
let changes = [NSDeletedObjectsKey: ids]
NSManagedObjectContext.mergeChanges(
fromRemoteContextSave: changes,
into: [context]
)
try context.save()
struct …Issue #622
Read Implementing Batch Deletes
If the entities that are being deleted are not loaded into memory, there is no need to update your application after the NSBatchDeleteRequest has been executed. However, if you are deleting objects in the …
Issue #1005
GitLab CI/CD pipelines create artifacts that take up a lot of storage space. While GitLab has a UI to delete them, doing this for thousands of artifacts one page at a time is slow and boring.
In this article, we’ll build a script …
Issue #1004
We set expire_in: 1h in our CI test jobs, but old artifacts from days ago were still there. Something wasn’t working right.
After some research, we found this is a known bug in older GitLab versions. If you’re on GitLab 16.7 …
Issue #277
Original post https://codeburst.io/using-bitrise-ci-for-react-native-apps-b9e7b2722fe5
After trying Travis, CircleCI and BuddyBuild, I now choose Bitrise for my mobile applications. The many cool steps and workflows make Bitrise an ideal …
Issue #149
We’re using BuddyBuild as our CI. Today one of our dependencies gets a sweat update https://github.com/hyperoslo/BarcodeScanner/releases/tag/4.1.1. So we pod update BarcodeScanner in one of our projects that depends on it. All is …
Issue #593
#if canImport(Combine) is not enough, need to specify in Other Linker Flags
OTHER_LDFLAGS = -weak_framework Combine
Issue #527
import Foundation
import Combine
public typealias TaskCompletion = (Result<(), Error>) -> Void
public protocol Task: AnyObject {
var name: String { get }
func run(workflow: Workflow, completion: TaskCompletion)
}
public …Issue #513
A publisher that emits before the object has changed
Use workaround DispatchQueue to wait another run loop to access newValue
.onReceive(store.objectWillChange, perform: {
DispatchQueue.main.async {
self.reload()
}
}) …Issue #506
When a function expects AnyPublisher<[Book], Error> but in mock, we have Just
func getBooks() -> AnyPublisher<[Book], Error> {
return Just([
Book(id: "1", name: "Book 1"),
Book(id: …Issue #451
For some services, we need to deal with separated APIs for getting ids and getting detail based on id.
To chain requests, we can use flatMap and Sequence, then collect to wait and get all elements in a single publish
Transforms …
Issue #871
Use libraries
import web3
import web3keystore
import KeychainAccess
private final class KeyStorage: EthereumKeyStorageProtocol {
enum Key: String { …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: …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 …
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 …
Issue #430
npm install electron-builder@latest --save-dev
package.json
{
"name": …Issue #415
https://stackoverflow.com/questions/44391448/electron-require-is-not-defined
function createWindow () {
win = new BrowserWindow({
title: 'MyApp',
width: 600,
height: 500, …Issue #352
For a normal electron app created with npm init, we can use all features of ES6, but not the JSX syntax for React. We can use just Babel to transpile JSX, as used in IconGenerator
.babelrc
{
"plugins": [ …Issue #342
Install electron as dev npm install electron --save-dev
Update electron-packager npm install electron-packager@latest --save-dev
Use no space in app name
Follow …
Issue #66
.iconseticonutil -c icns "Icon.iconset". Note that icon names must be first letter lowsercased, and use _ instead of -
main.js, specify iconwin = new BrowserWindow({
width: 800, …Issue #575
Check for example _runtime(_ObjC) or os(macOS if you plan to use platform specific feature …
Issue #572
After migrating a few pods to use SPM, some libraries fail to load. This is because the workspace now uses both SPM and cocoapods
code signature in … not valid for use in process using Library Validation: mapped file has no Team ID …
Issue #525
Example Puma

Puma.xcodeproj as a sub project of our test projectLink Binary with Libraries, select Puma framework …Issue #523
In Puma I want to make build tools for iOS and Android, which should share some common infrastructure. So we can organize dependencies like.
Puma -> PumaAndroid, PumaiOS -> PumaCore -> xcbeautify, Files, Colorizer
// …Issue #504
https://twitter.com/NeoNacho/status/1181245484867801088?s=20
There’s no way to have platform specific sources or targets today, so you’ll have to take a different approach. I would recommend wrapping all OS specific files in #if os and …
Issue #476
React Native comes with a default React library, and most CocoaPods libraries for React Native has React as a dependency pod, which causes the conflict
Issue #196
CocoaPods will build and compile our frameworks every time whenever you are doing the clean build or run pod install or pod update for the project.
Issue #170

I’m using cocoapods 1.6.0.beta.2 in a React Native apps and it has been working fine. The pods that I need is Firebase and FacebookSDK. Today after pod install, I got error
NoMethodError - undefined method `real_path' for …Issue #149
We’re using BuddyBuild as our CI. Today one of our dependencies gets a sweat update https://github.com/hyperoslo/BarcodeScanner/releases/tag/4.1.1. So we pod update BarcodeScanner in one of our projects that depends on it. All is …
Issue #293
Answer https://stackoverflow.com/a/55119208/1418457
This is useful to throttle TextField change event. You can make Debouncer class using Timer
import 'package:flutter/foundation.dart';
import 'dart:async';
class …Issue #188
Get error com.google.android.gms.common.api.ApiException: 10 with google_sign_in package.
Read https://developers.google.com/android/guides/client-auth
Certain Google Play services (such as Google Sign-in and App Invites) require you to …
Issue #187
If you use Flutter, then you can access it via people.googleapis.com endpoint, code uses google_sign_in library
import 'package:google_sign_in/google_sign_in.dart';
Future<String> getPhotoUrl(GoogleSignInAccount account, …Issue #293
Answer https://stackoverflow.com/a/55119208/1418457
This is useful to throttle TextField change event. You can make Debouncer class using Timer
import 'package:flutter/foundation.dart';
import 'dart:async';
class …Issue #188
Get error com.google.android.gms.common.api.ApiException: 10 with google_sign_in package.
Read https://developers.google.com/android/guides/client-auth
Certain Google Play services (such as Google Sign-in and App Invites) require you to …
Issue #187
If you use Flutter, then you can access it via people.googleapis.com endpoint, code uses google_sign_in library
import 'package:google_sign_in/google_sign_in.dart';
Future<String> getPhotoUrl(GoogleSignInAccount account, …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 …
Issue #531
{
"expand_merge_commits_by_default": true,
"translate_tabs_to_spaces": true
}
git config core.hooksPath ~/.git-templates/hooks
Only hooksPath gets run. …
Issue #514
ssh-keygen -t rsa -C "onmyway133@gmail.com" -f "id_rsa_github"
ssh-keygen -t rsa -C "onmyway133bitbucket@gmail.com" -f "id_rsa_bitbucket"
pbcopy < ~/.ssh/id_rsa_github.pub
pbcopy < …Issue #239
Do you know that questions about git get the most views on StackOverflow? I’ve searched a lot on Google how to execute certain actions with git, and this actually slowed me down a lot. There are some actions that we tend to use a lot, so …
Issue #369
Issue #259
React Native uses Yoga to achieve Flexbox style layout, which helps us set up layout in a …
Issue #22
In the beginning, people use frame and Autoresizing Mask, then they use Auto Layout, then iOS 9 encourages them to use NSLayoutAnchor, UILayoutGuide and UIStackView
For more convenient Auto Layout, check How to make Auto Layout more …
Issue #246
Use GMSMapStyle https://developers.google.com/maps/documentation/android-sdk/styling Export styling json from https://mapstyle.withgoogle.com/
let mapStyleUrl = Bundle.main.url(forResource: "mapStyle", withExtension: "json" …Issue #183
func zoomInDouble(coordinate: CLLocationCoordinate2D) {
let region = mapView.region
let zoomInRegion = MKCoordinateRegion(
center: coordinate,
span: MKCoordinateSpan(
latitudeDelta: region.span. …Issue #182
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
guard let coordinate = view.annotation?.coordinate else {
return
}
if (view.annotation is MKClusterAnnotation) {
zoomInDouble( …Issue #181
final class AnnotationView: MKMarkerAnnotationView {
override init(annotation: MKAnnotation?, reuseIdentifier: …Issue #304
If you do VoIP applications, especially with open sources like pjsip, you may encounter kamalio and rtpproxy to serve SIP requests. Due to limitation of NAT traversals, rtpproxy is needed to work around NAT. All SIP handshake requests go …
Issue #284
Before working with Windows Phone and iOS, my life involved researching VoIP. That was to build a C library for voice over IP functionality for a very popular app, and that was how I got started in open source.
The library I was working …
Issue #157
This post was from long time ago when I did pjsip
A jitter buffer temporarily stores arriving packets in order to minimize delay variations. If packets arrive too late then they are discarded. A jitter buffer may be mis-configured and be …
Issue #155
As you have probably observed in your studies, there is a determined method for calculating VoIP packet sizes. The packet size depends on many different variables, so there is no great answer for an “average” packet size …
Issue #223
let script =
"""
tell application "XcodeWay"
activate
end tell
"""
let command = "osascript -e '\(script)'"
let process = Process()
process.launchPath …Issue #89
Today I find that AppleScript allows us to import Foundation, with that we have lots of power, including NSString. See my script
use scripting additions
use framework "Foundation"
property NSString : a reference to current …Issue #88
I ’ve been using Apple Script to for my Finder extension FinderGo. Because of sandboxing, all scripts must lie inside Application Scripts folder.
Today, I was rewriting my Xcode extension XcodeWay. Before Xcode 8, we could use Xcode …
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( …Issue #13
There is time we have models that have some kind of inheritance, like Dog, Cat, Mouse can be Animal. We can use composition to imitate inheritance, we just need to make sure it has unique primary key
These are pretty much basic …
Issue #4
Realm is great. But without primary key, it will duplicate the record, like https://github.com/realm/realm-java/issues/2730, http://stackoverflow.com/questions/32322460/should-i-define-the-primary-key-for-each-entity-in-realm, … So to …
Issue #218
Recorderclass …Issue #214
extension Result {
func to(subject: PublishSubject<Success>) {
switch self {
case .success(let value):
subject.onNext(value)
case .failure(let error):
subject.onError(error) …Issue #120
Original post https://medium.com/flawless-app-stories/a-taste-of-mvvm-and-reactive-paradigm-5288a819cca1
I like Swift, like many other object oriented programming languages. Swift allows you to …
Issue #740
How to gain product ideas?
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
Build any …
Issue #739
New program reduces App Store commission to 15 percent for small businesses earning up to $1 million per year
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
Issue #1008
Model Context Protocol (MCP) allows Claude Code to connect to external tools, databases, and services. See the official MCP documentation for more details.
MCP servers have three scope levels that …
Issue #1000
I’ve been using Claude Code daily for months. Here are my notes
Claude Code has built-in thinking modes that allocate more compute for complex problems:
Issue #490
Vision Edge is part of MLKit, but for custom images training
https://console.firebase.google.com/u/0/project/avengers-ad2ce/ml/
Model Avengers_dataset_2019114133437 is training and may …
Issue #489
https://console.cloud.google.com/storage
https://console.cloud.google.com/vision
Issue #220
package main
import (
"net/http"
"log"
)
func handleGreeting(w http.ResponseWriter, r *http.Request) {
messages, ok := r.URL.Query()["message"]
if !ok || len(messages[0]) < 1 { …Issue #199
import (
"net/http"
"encoding/json"
"io/ioutil"
"fmt"
)
type MyJsonObject struct {
Id string `json:"id"` …Issue #489
https://console.cloud.google.com/storage
https://console.cloud.google.com/vision
Issue #209
Here are what I learn about reachability handling in iOS, aka checking for internet connection. Hope you will find it useful, too.
This post starts with techniques from Objective age, but many of the concepts still hold true
Issue #164
From my own blog post https://github.com/Fantageek/fantageek.github.io/blob/source/source/_posts/2014-06-27-understanding-weak-self-and-strong-self.markdown
Blocks are wonderful. To avoid retain cycle you often see the weakSelf - …
Issue #492
Suppose we have a base Localizable.strings
"open" = "Open";
"closed" = "Closed";
After sending that file for translations, we get translated versions.
"open" = "Åpen";
"closed" = …Issue #252
Read more https://medium.com/flawless-app-stories/how-to-make-auto-layout-more-convenient-in-ios-df3b42fed37f
This is a script to remove Cartography, and use plain NSLayoutAnchor syntax. Use Constraint.on() from Sugar. It will …
Issue #99
I’ve been searching for efficient ways to diff collections, here are some interesting papers that I find
Myers
Issue #1002
I recently set up self-hosted runners on EC2 Mac instances for iOS builds. Here are my notes on what actually works—plus all the gotchas I hit along the way.
For complete official instructions, see GitHub’s guide on adding …
Issue #504
https://twitter.com/NeoNacho/status/1181245484867801088?s=20
There’s no way to have platform specific sources or targets today, so you’ll have to take a different approach. I would recommend wrapping all OS specific files in #if os and …
Issue #1008
Model Context Protocol (MCP) allows Claude Code to connect to external tools, databases, and services. See the official MCP documentation for more details.
MCP servers have three scope levels that …
Issue #275
Original post https://codeburst.io/making-unity-games-in-pure-c-2b1723cdc71f
As an iOS engineers, I ditched Storyboard to avoid all possible hassles and write UI components in pure Swift code. I did XAML in Visual Studio for Windows Phone …
Issue #246
Use GMSMapStyle https://developers.google.com/maps/documentation/android-sdk/styling Export styling json from https://mapstyle.withgoogle.com/
let mapStyleUrl = Bundle.main.url(forResource: "mapStyle", withExtension: "json" …Issue #222
For more mature networking, visit https://github.com/onmyway133/Miami
final class NetworkClient {
let session: URLSession
let baseUrl: URL
init(session: URLSession = .shared, baseUrl: URL) {
self.session = session …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 …
Issue #4
Realm is great. But without primary key, it will duplicate the record, like https://github.com/realm/realm-java/issues/2730, http://stackoverflow.com/questions/32322460/should-i-define-the-primary-key-for-each-entity-in-realm, … So to …
Issue #519
brew install watchman
git clone https://github.com/facebook/flipper.git
cd flipper
yarn
yarn start
Issue #275
Original post https://codeburst.io/making-unity-games-in-pure-c-2b1723cdc71f
As an iOS engineers, I ditched Storyboard to avoid all possible hassles and write UI components in pure Swift code. I did XAML in Visual Studio for Windows Phone …