How to add toolbar programatically in macOS

Issue #713 To setup toolbar, we need to implement NSToolbarDelegate that provides toolbar items. This delegate is responsible for many things Set visible and allowed items with toolbarDefaultItemIdentifiers Provide item with itemForItemIdentifier Being notified with toolbarWillAddItem and toolbarDidRemoveItem window.toolbarStyle = .unifiedCompact let toolbar = NSToolbar(identifier: "Toolbar") toolbar.displayMode = .iconAndLabel toolbar.delegate = (NSApp.delegate as! AppDelegate) toolbar.insertItem(withItemIdentifier: .add, at: 0) toolbar.insertItem(withItemIdentifier: .settings, at: 1) window.toolbar = toolbar extension NSToolbarItem.Identifier { static let add = NSToolbarItem....

December 15, 2020 · 1 min · 202 words · Khoa

How to declare network Error with enum in Swift

Issue #712 Describe all possible paths in your program with enum. This is great to track down bugs and to not miss representing potential cases in UI. Errors can come from app layer, backend layer to network issues. Enum is handy in both UIKit and SwiftUI enum NetworkError: Swift.Error { enum RequestError { case invalidRequest(URLRequest) case encodingError(Swift.EncodingError) case other(NSError) } enum ServerError { case decodingError(Swift.DecodingError) case noInternetConnection case timeout case internalServerError case other(statusCode: Int, response: HTTPURLResponse) } case requestError(RequestError) case serverError(ServerError) } and note that Foundation has NSError with a bunch of well defined error code ready to use....

December 14, 2020 · 2 min · 249 words · Khoa

How to programatically select row in List in SwiftUI

Issue #711 List has a selection parameter where we can pass selection binding. As we can see here selection is of type optional Binding<Set<SelectionValue>>? where SelectionValue is any thing conforming to Hasable @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) public struct List<SelectionValue, Content> : View where SelectionValue : Hashable, Content : View { @available(watchOS, unavailable) public init(selection: Binding<Set<SelectionValue>>?, @ViewBuilder content: () -> Content) So we can programatically control selection by tagging row with our own Tag...

December 13, 2020 · 1 min · 113 words · Khoa

How to mock UNNotificationResponse in unit tests

Issue #708 The best way to test is to not have to mock at all. The second best way is to have your own abstraction over the things you would like to test, either it is in form of protocol or some function injection. But in case you want a quick way to test things, and want to test as real as possible, then for some cases we can be creative to mock the real objects....

December 7, 2020 · 3 min · 507 words · Khoa

How to support right click menu to NSStatusItem

Issue #707 The trick is to set the button oinside of statusItem to send actions on both leftMouseUp and rightMouseUp. Another thing to note is we use popUpMenu on NSStatusItem, although it is marked as deprecated on macOS 10.14. We can set menu but that overrides left click. import Omnia private let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength) private let statusItemMenuHandler = MenuHandler() func setupStatusMenu() { if let button = statusItem.button { button....

December 7, 2020 · 1 min · 131 words · Khoa

How to convert struct to Core Data NSManagedObject

Issue #706 Use Mirror and set key value as NSManagedObject subclasses from NSObject import CoreData final class ManagedObjectConverter { func convert<M>(m: M, context: NSManagedObjectContext) throws -> NSManagedObject { let entityName = String(describing: m) guard let entityDescription = NSEntityDescription.entity( forEntityName: entityName, in: context ) else { throw AppError.parsing } let managedObject = NSManagedObject( entity: entityDescription, insertInto: context ) let mirror = Mirror(reflecting: m) guard mirror.displayStyle == .struct else { throw AppError.parsing } for case let (label?...

December 7, 2020 · 1 min · 91 words · Khoa

How to declare Error in Swift

Issue #704 We used to declare enum that conforms to Error, but any type like struct or class can conform to Error as well. enum NetworkError: Error { case failToCreateRequest case failToParseResponse case failToReachServe } struct DetailError: Error { let networkError: Error let createdAt: Date let tag: String } final class TrackError: Error { let trackId: String let detailError: DetailError let trackSession: String init(trackId: String, detailError: DetailError, trackSession: String) { self....

December 5, 2020 · 1 min · 103 words · Khoa

How to convert from paid to free with IAP

Issue #703 What is receipt Read When to refresh a receipt vs restore purchases in iOS? From iOS 7, every app downloaded from the store has a receipt (for downloading/buying the app) at appStoreReceiptURL. When users purchases something via In App Purchase, the content at appStoreReceiptURL is updated with purchases information. Most of the cases, you just need to refresh the receipt (at appStoreReceiptURL) so that you know which transactions users have made....

November 30, 2020 · 9 min · 1834 words · Khoa

How to search using regular expression in Xcode

Issue #698 Xcode has powerful search. We can constrain search to be scoped in workspace, project or some folders. We can also constrain case sensitivity. Another cool thing that people tend to overlook is, besides searching based on text, we can search based on references, definitions, call hierarchy, and 🎉 regular expressions. Searching for regular expression gives us extra power when it comes to limit our search based on some criteria....

November 17, 2020 · 2 min · 352 words · Khoa

How to write to temporary file in Swift

Issue #697 Use temporaryDirectory from FileManager and String.write func writeTempFile(books: [Book]) -> URL { let url = FileManager.default.temporaryDirectory .appendingPathComponent(UUID().uuidString) .appendingPathExtension("txt") let string = books .map({ "book '\($0.url.path)'" }) .joined(separator: "\n") try? string.write(to: url, atomically: true, encoding: .utf8) return url }

November 15, 2020 · 1 min · 40 words · Khoa

How to use functions with default arguments in Swift

Issue #696 Which methods do you think are used here import Cocoa struct Robot { let a: Int let b: Int let c: Int init(a: Int = 1, c: Int = 3) { self.a = a self.b = 0 self.c = c print("Init with a=\(a) and c=\(c)") } init(a: Int = 1, b: Int = 2, c: Int = 3) { self.a = a self.b = b self.c = c print("Init with a\(a), b=\(b) and c=\(c)") } } let r1 = Robot(c: 10) let r2 = Robot(a: 5, c: 10) let r3 = Robot(a: 5, b: 7, c: 10) let r4 = Robot(a: 5) let r5 = Robot(b: 5) The log is...

November 14, 2020 · 1 min · 139 words · Khoa

How to check IAP Transaction error

Issue #695 Inspect SKPaymentTransaction for error. In Swift, any Error can be safely bridged into NSError there you can check errorDomain and code private func handleFailure(_ transaction: SKPaymentTransaction) { guard let error = transaction.error else { return } let nsError = error as NSError guard nsError.domain == SKError.errorDomain else { return } switch nsError.code { case SKError.clientInvalid.rawValue, SKError.paymentNotAllowed.rawValue: showAlert(text: "You are not allowed to make payment.") case SKError.paymentCancelled.rawValue: showAlert(text: "Payment has been cancelled....

November 14, 2020 · 1 min · 86 words · Khoa

How to use nested ObservableObject in SwiftUI

Issue #694 I usually structure my app to have 1 main ObservableObject called Store with multiple properties in it. final class Store: ObservableObject { @Published var pricingPlan: PricingPlan() @Published var preferences: Preferences() } struct Preferences { var opensAtLogin: Bool = true } final class PricingPlan: ObservableObject { @Published var isPro: Bool = true } SwiftUI for now does not work with nested ObservableObject, so if I pass Store to PricingView, changes in PricingPlan does not trigger view update in PricingView....

November 14, 2020 · 1 min · 212 words · Khoa

How to check dark mode in AppKit for macOS apps

Issue #693 AppKit app has its theme information stored in UserDefaults key AppleInterfaceStyle, if is dark, it contains String Dark. Another way is to detect appearance via NSView struct R { static let dark = DarkTheme() static let light = LightTheme() static var theme: Theme { let isDark = UserDefaults.standard.string(forKey: "AppleInterfaceStyle") == "Dark" return isDark ? dark : light } } Another way is to rely on appearance on NSView. You can quickly check via NSApp....

November 10, 2020 · 2 min · 216 words · Khoa

How to avoid multiple match elements in UITests from iOS 13

Issue #691 Supposed we want to present a ViewController, and there exist both UIToolbar in both the presenting and presented view controllers. From iOS 13, the model style is not full screen and interactive. From UITests perspective there are 2 UIToolbar, we need to specify the correct one to avoid multiple match errors let editButton = app.toolbars["EditArticle.Toolbar"].buttons["Edit"] Updated at 2020-11-04 10:02:29

November 4, 2020 · 1 min · 61 words · Khoa

How to use accessibility container in UITests

Issue #690 Use accessibilityElements to specify containment for contentView and buttons. You can use Accessibility Inspector from Xcode to verify. class ArticleCell: UICollectionViewCell { let authorLabel: UILabel let dateLabel: UILabel let viewLabel: UILabel let deleteButton: UIButton private func setupAccessibility() { contentView.isAccessibilityElement = true contentView.accessibilityLabel = "This article is written by Nobita on Dec 4th 2020" viewLabel.isAccessibilityElement = true // Default is false viewLabel.accessibilityTraits.insert(.button) // Treat UILabel as button to VoiceOver accessibilityElements = [contentView, viewLabel, deleteButton] isAccessibilityElement = false } } This works OK under Voice Over and Accessibility Inspector....

November 4, 2020 · 1 min · 134 words · Khoa

How to make full size content view in SwiftUI for macOS

Issue #689 func applicationDidFinishLaunching(_ aNotification: Notification) { // extend to title bar let contentView = ContentView() // .padding(.top, 24) // can padding to give some space .edgesIgnoringSafeArea(.top) // specify fullSizeContentView window = NSWindow( contentRect: NSRect(x: 0, y: 0, width: 800, height: 600), styleMask: [.titled, .closable, .miniaturizable, .texturedBackground, .resizable, .fullSizeContentView], backing: .buffered, defer: false ) window.center() window.setFrameAutosaveName("My App") // window.title = ... // no title // window.toolbar = NSToolbar() // use toolbar if wanted....

November 3, 2020 · 1 min · 135 words · Khoa

How to override styles in SwiftUI

Issue #688 In the app I’m working on Elegant Converter, I usually like preset theme with a custom background color and a matching foreground color. Thanks to SwiftUI style cascading, I can just declare in root MainView and it will be inherited down the view hierachy. struct MainView: View { var body: some View { HSplitView { ListView() RightView() } .foregroundColor(R.color.text) .background(R.color.background) } } This works great regardless of system light or dark mode, but in light mode it does not look good, as my designed theme is similar to dark mode....

October 31, 2020 · 2 min · 215 words · Khoa

When to use function vs property in Swift

Issue #687 Although I do Swift, I often follow Kotlin guideline https://kotlinlang.org/docs/reference/coding-conventions.html#functions-vs-properties In some cases functions with no arguments might be interchangeable with read-only properties. Although the semantics are similar, there are some stylistic conventions on when to prefer one to another. Prefer a property over a function when the underlying algorithm: does not throw is cheap to calculate (or cached on the first run) returns the same result over invocations if the object state hasn’t changed Updated at 2020-10-27 09:56:38

October 27, 2020 · 1 min · 81 words · Khoa

How to use CoreData safely

Issue #686 I now use Core Data more often now. Here is how I usually use it, for example in Push Hero From iOS 10 and macOS 10.12, NSPersistentContainer that simplifies Core Data setup quite a lot. I usually use 1 NSPersistentContainer and its viewContext together with newBackgroundContext attached to that NSPersistentContainer In Core Data, each context has a queue, except for viewContext using the DispatchQueue.main, and each NSManagedObject retrieved from 1 context is supposed to use within that context queue only, except for objectId property....

October 25, 2020 · 2 min · 299 words · Khoa