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

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

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

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

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

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

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

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

How to override styles in SwiftUI

Issue #688 In the app I鈥檓 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 路 Khoa Pham

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鈥檛 changed Updated at 2020-10-27 09:56:38

October 27, 2020 路 1 min 路 Khoa Pham

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

How to pass ObservedObject as parameter in SwiftUI

Issue #685 Since we have custom init in ChildView to manually set a State, we need to pass ObservedObject. In the ParentView, use underscore _ to access property wrapper type. struct ChildView: View { @ObservedObject var store: Store @State private var selectedTask: AnyTask init(store: ObservedObject<Store>) { _selectedTask = State(initialValue: tasks.first!) _store = store } } struct ParentView: View { @ObservedObject var store: Store var body: some View { ChildView(store: _store) }

October 24, 2020 路 1 min 路 Khoa Pham

How to do equal width in SwiftUI

Issue #684 In SwiftUI, specifying maxWidth as .infinity means taking the whole available width of the container. If many children ask for max width, then they will be divided equally. This is similar to weight in LinearLayout in Android or css flex-grow property. The same applies in vertical direct also. struct ContentView: View { var body: some View { HStack(spacing: 0) { VStack { Spacer() } .frame(maxWidth: .infinity) .background(Color.red) VStack { Spacer() } ....

October 23, 2020 路 1 min 路 Khoa Pham

How to test push notifications in simulator and production iOS apps

Issue #682 After has recently reminded about his updating APNs provider API which makes me realised a lot has changed about push notifications, both in terms of client and provider approach. The HTTP/2-based Apple Push Notification service (APNs) provider API lets you take advantage of great features, such as authentication with a JSON Web Token, improved error messaging, and per-notification feedback. If you send push notifications with the legacy binary protocol, we strongly recommend upgrading to the APNs provider API....

October 11, 2020 路 12 min 路 Khoa Pham

How to style multiline Text in SwiftUI for macOS

Issue #681 Only need to specify fixedSize on text to preserve ideal height. The maximum number of lines is 1 if the value is less than 1. If the value is nil, the text uses as many lines as required. The default is nil. Text(longText) .lineLimit(nil) // No need .fixedSize(horizontal: false, vertical: true) If the Text is inside a row in a List, fixedSize causes the row to be in middle of the List, workaround is to use ScrollView and vertical StackView....

October 7, 2020 路 1 min 路 Khoa Pham

How to clear List background color in SwiftUI for macOS

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 SwiftUI-Introspect import Introspect extension List { func removeBackground() -> some View { return introspectTableView { tableView in tableView.backgroundColor = .clear tableView.enclosingScrollView!.drawsBackground = false } } } then List { ForEach(items) { item in // view here } } ....

October 4, 2020 路 1 min 路 Khoa Pham

How to avoid reduced opacity when hiding view with animation in SwiftUI

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 dropdown button or text. extension View { func sectionBackground(_ title: String, _ shows: Binding<Bool>) -> some View { VStack(alignment: .leading) { HStack { Text(title.uppercased()) Spacer() if shows !...

October 1, 2020 路 1 min 路 Khoa Pham

How to dynamically add items to VStack from list in SwiftUI

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: (Int, Input.DeviceToken) -> Binding<String> = { index, token in Binding<String>( get: { token.token }, set: { self.input.deviceTokens[index].token = $0 } ) } return VStack { ForEach(withIndex, id: \....

October 1, 2020 路 1 min 路 Khoa Pham

How to unwrap Binding with Optional in SwiftUI

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: String = "" // New props var notificationId: String? This new property when using dollar syntax $input.notificationId turn into Binding with optional Binding<Strting?> which is incompatible in SwiftUI when we use Binding....

September 29, 2020 路 1 min 路 Khoa Pham

How to use Binding in function in Swift

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( HStack { Spacer() SmallButton( imageName: "downArrow", tooltip: shows.wrappedValue ? "Collapse" : "Expand", action: { shows.wrappedValue.toggle() } ) .rotationEffect(.radians(shows.wrappedValue ? .pi : 0)) } ) } }

September 25, 2020 路 1 min 路 Khoa Pham