How to do copy paste delete in Swift for macOS

Issue #729 @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { @IBAction func copy(_ sender: Any) { print("copy", sender) } @IBAction func paste(_ sender: Any) { print("paste", sender) } } For delete, we can listen to keyDown in NSWindow class MyWindow: NSWindow { override func keyDown(with event: NSEvent) { super.keyDown(with: event) guard let deleteScalar = UnicodeScalar(NSDeleteCharacter), event.charactersIgnoringModifiers == String(deleteScalar) else { return } NotificationCenter.default.post(Notification(name: .didKeyboardDeleteItem)) } }

December 30, 2020 路 1 min 路 Khoa Pham

How to make simple NSItemProvider in Swift

Issue #728 NSItemProvider(object: StringProvider(string: string)) class StringProvider: NSObject, NSItemProviderWriting { let string: String init(string: String) { self.string = string super.init() } static var writableTypeIdentifiersForItemProvider: [String] { return [(kUTTypeData) as String] } func loadData( withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping (Data?, Error?) -> Void ) -> Progress? { let data = string.data(using: .utf8) completionHandler(data, nil) return Progress(totalUnitCount: 100) } }

December 30, 2020 路 1 min 路 Khoa Pham

How to use hashtag raw string in Swift

Issue #727 Use # in Swift 5 to specify raw string, for example regular expression #"^#?(?:[0-9a-fA-F]{3}){1,2}$"# Read more https://www.hackingwithswift.com/articles/162/how-to-use-raw-strings-in-swift

December 27, 2020 路 1 min 路 Khoa Pham

How to make UserDefaults property wrapper

Issue #726 @propertyWrapper struct UserDefault<Value> { let key: String let defaultValue: Value let container: UserDefaults = .standard var wrappedValue: Value { get { return container.object(forKey: key) as? Value ?? defaultValue } set { container.set(newValue, forKey: key) } } } Then we can use it as property and provide default value final class KeepHistoryService { @UserDefault(key: "keepHistoryCheckDate", defaultValue: nil) var checkDate: Date?

December 26, 2020 路 1 min 路 Khoa Pham

How to use Set to check for bool in Swift

Issue #725 When you want to check for existence using Bool, consider using Set over Dictionary with Bool, as Set guarantee uniqueness. If using Dictionary instead, the value for key is Optional<Bool> where we have to check for both optional and true false within. struct Book: Hashable { let id: UUID let name: String } let book1 = Book(id: UUID(), name: "1") let book2 = Book(id: UUID(), name: "2") func useDictionary() { var hasChecked: [Book: Bool] = [:] hasChecked[book1] = true print(hasChecked[book1] == Optional<Bool>(true)) print(hasChecked[book2] == Optional<Bool>....

December 26, 2020 路 1 min 路 Khoa Pham

How to make visual effect blur in SwiftUI for macOS

Issue #724 We can use .blur modifier, but with VisualEffectView gives us more options for material and blending mode. public struct VisualEffectView: NSViewRepresentable { let material: NSVisualEffectView.Material let blendingMode: NSVisualEffectView.BlendingMode public init( material: NSVisualEffectView.Material = .contentBackground, blendingMode: NSVisualEffectView.BlendingMode = .withinWindow ) { self.material = material self.blendingMode = blendingMode } public func makeNSView(context: Context) -> NSVisualEffectView { let visualEffectView = NSVisualEffectView() visualEffectView.material = material visualEffectView.blendingMode = blendingMode visualEffectView.state = NSVisualEffectView.State.active return visualEffectView } public func updateNSView(_ visualEffectView: NSVisualEffectView, context: Context) { visualEffectView....

December 26, 2020 路 1 min 路 Khoa Pham

How to make simple HUD in SwiftUI

Issue #723 Use @ViewBuilder to build dynamic content for our HUD. For blur effect, here I use NSVisualEffectView, but we can use .blur modifier also struct HUD<Content>: View where Content: View { let content: () -> Content init(@ViewBuilder content: @escaping () -> Content) { self.content = content } var body: some View { content() .frame(width: 80, height: 80) .background( VisualEffectView(material: .hudWindow) .clipShape(RoundedRectangle(cornerRadius: 12)) .shadow(color: Color.black.opacity(0.22), radius: 12, x: 0, y: 5) ) } } Then we can make some wrappers for information and progress HUD...

December 26, 2020 路 1 min 路 Khoa Pham

How to force set frame explicitly for NSWindow

Issue #721 For setFrame to take effect mainWindow.setFrame(rect, display: true) we can remove auto save frame flag mainWindow.setFrameAutosaveName("MyApp.MainWindow")

December 25, 2020 路 1 min 路 Khoa Pham

How to rotate NSStatusItem

Issue #720 NSStatusItem is backed by NSButton, we can animate this inner button. We need to specify position and anchorPoint for button鈥檚 layer so it rotates around its center point guard let button = statusItem.button else { return } let animation = CABasicAnimation(keyPath: "transform.rotation.z") animation.fromValue = 0 animation.toValue = CGFloat.pi * 2 animation.duration = 0.25 animation.repeatCount = 1 button.layer?.position = NSPoint(x: NSMidX(button.frame), y: NSMidY(button.frame)) button.layer?.anchorPoint = NSPoint(x: 0.5, y: 0.5) button....

December 23, 2020 路 1 min 路 Khoa Pham

How to make sharing menu in SwiftUI for macOS

Issue #718 Use NSSharingService.sharingServices(forItems:) with an array of one empty string gives a list of sharing items. There we show image and title of each menu item. We should cache sharing items as that can cause performance issue import SwiftUI import AppKit import EasySwiftUI extension NSSharingService { private static let items = NSSharingService.sharingServices(forItems: [""]) static func submenu(text: String) -> some View { return Menu( content: { ForEach(items, id: \.title) { item in Button(action: { item....

December 23, 2020 路 1 min 路 Khoa Pham

How to do didSet for State and Binding in SwiftUI

Issue #714 Below is an example of a parent ContentView with State and a child Sidebar with a Binding. The didSet is only called for the property that is changed. When we click Button in ContentView, that changes State property, so only the didSet in ContentView is called When we click Button in Sidebar, that changes Binding property, so only the didSet in Sidebar is called enum Tag: String { case all case settings } struct ContentView: View { @State private var tag: Tag = ....

December 16, 2020 路 2 min 路 Khoa Pham

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 路 Khoa Pham

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 路 Khoa Pham

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 路 Khoa Pham

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 路 Khoa Pham

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 路 Khoa Pham

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 路 Khoa Pham

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 路 Khoa Pham

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 路 Khoa Pham

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 路 Khoa Pham