How to use UICollectionViewLayout

Issue #546 Using the Flow Layout Customizing Collection View Cell Insertion Animations

December 17, 2019 · 1 min · Khoa Pham

How to not use protocol extension in Swift

Issue #542 With protocol extension See code Puma Build is UsesXcodeBuild is UsesCommandLine /// Any task that uses command line public protocol UsesCommandLine: AnyObject {} public extension UsesCommandLine { func runBash( workflow: Workflow, program: String, arguments: [String], processHandler: ProcessHandler = DefaultProcessHandler() ) throws { // Code } func runProcess( _ process: Process, workflow: Workflow, processHandler: ProcessHandler = DefaultProcessHandler() ) throws { // Code } } /// Any task that uses xcodebuild public protocol UsesXcodeBuild: UsesCommandLine { var xcodebuild: Xcodebuild { get set } } public extension UsesXcodeBuild { func runXcodeBuild(workflow: Workflow) throws { try runBash( workflow: workflow, program: "xcodebuild", arguments: xcodebuild....

December 15, 2019 · 1 min · Khoa Pham

How to show localized text in SwiftUI

Issue #533 struct ContentView: View { @Environment(\.locale) var locale: Locale var body: some View { VStack { Text(LocalizedStringKey("hello")) .font(.largeTitle) Text(flag(from: locale.regionCode!)) .font(.largeTitle) } } }

December 9, 2019 · 1 min · Khoa Pham

How to show flag emoji from country code in Swift

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 } Read moree Swift turn a country code into a emoji flag via unicode https://github.com/onmyway133/Smile

December 9, 2019 · 1 min · Khoa Pham

How to do lense in Swift

Issue #528 What is lense https://www.schoolofhaskell.com/school/to-infinity-and-beyond/pick-of-the-week/a-little-lens-starter-tutorial A lens is a first-class reference to a subpart of some data type. For instance, we have _1 which is the lens that “focuses on” the first element of a pair. Given a lens there are essentially three things you might want to do View the subpart Modify the whole by changing the subpart Combine this lens with another lens to look even deeper...

December 4, 2019 · 1 min · Khoa Pham

How to convert from callback to Future Publisher in 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 extension Task { func asPublisher(workflow: Workflow) -> AnyPublisher<(), Error> { return Future({ completion in self.run(workflow: workflow, completion: completion) }).eraseToAnyPublisher() } } let sequence = Publishers.Sequence<[AnyPublisher<(), Error>], Error>( sequence: tasks.map({ $0.asPublisher(workflow: self) }) )

December 2, 2019 · 1 min · Khoa Pham

How to make init with closure in Swift

Issue #526 public class Build: UsesXcodeBuild { public var arguments = [String]() public init(_ closure: (Build) -> Void = { _ in }) { closure(self) } } Use function builder public class Workflow { public var workingDirectory: String = "." public let tasks: [Task] public init(@TaskBuilder builder: () -> [Task]) { self.tasks = builder() self.tasks.forEach { task in task.workflow = self } } public init(@TaskBuilder builder: () -> Task) { self....

December 1, 2019 · 1 min · Khoa Pham

How to test a developing package with Swift Package Manager

Issue #525 Use macOS Command Line project Example Puma Create a new macOS project, select Command Line Tool Drag Puma.xcodeproj as a sub project of our test project Go to our TestPuma target, under Link Binary with Libraries, select Puma framework Puma has dependencies on PumaCore and PumaiOS, but in Xcode we only need to select Puma framework In code, we need to explicitly import PumaiOS framework if we use any of its classes...

November 30, 2019 · 2 min · Khoa Pham

How to use method from protocol extension in Swift

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 command = "\(program)\(arguments.joined(separator: " "))" Log.command(command) _ = try Process().run(command: command) } } class Build: UsesCommandLine { public func run() throws { arguments.insert("build") try (self as UsesCommandLine).run() } }

November 30, 2019 · 1 min · Khoa Pham

How to organize dependencies in Swift Package Manager

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 // swift-tools-version:5.1 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "Puma", platforms: [.macOS("10.15")], products: [ .library(name: "Puma", targets: ["Puma"]) ], dependencies: [ ....

November 30, 2019 · 1 min · Khoa Pham

How to provide configurations in Swift

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 command. Use Options struct to encapsulate parameters To avoid passing many parameters into a class, I tend to make an Options struct to encapsulate all passing parameters. I also use composition, where Build....

November 30, 2019 · 3 min · Khoa Pham

How to test UserDefaults in iOS

Issue #518 let userDefaults = UserDefaults(suiteName: suiteName) userDefaults.removePersistentDomain(forName: suiteName) https://developer.apple.com/documentation/foundation/userdefaults/1417339-removepersistentdomain Calling this method is equivalent to initializing a user defaults object with init(suiteName:) passing domainName, and calling the removeObject(forKey:) method on each of its keys. Read more https://www.swiftbysundell.com/articles/the-power-of-userdefaults-in-swift/ http://dscoder.com/defaults.html https://medium.com/swift-india/userdefaults-under-the-hood-457461c8d262

November 25, 2019 · 1 min · Khoa Pham

How to group array by property in Swift

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]) -> Group in return Group(initial: key, countries: value) }) .sorted(by: { $0.initial < $1.initial }) return groups }

November 16, 2019 · 1 min · Khoa Pham

How to map error in Combine

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: "2", name: "Book 2"), ]) .eraseToAnyPublisher() } There will be a mismatch, hence compile error Cannot convert return expression of type ‘AnyPublisher<[Book], Just.Failure>’ (aka ‘AnyPublisher<Array, Never>') to return type ‘AnyPublisher<[Book], Error>’ The reason is because Just produces Never, not Error. The workaround is to introduce Error...

November 14, 2019 · 1 min · Khoa Pham

How to make Swift Package Manager package for multiple platforms

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 just having one target. For tests, you could do something similar, one test target, but conditional tests Every files are in Sources folder, so we can use platform and version checks. For example Omnia is a Swift Package Manager that supports iOS, tvOS, watchOS, macOS and Catalyst....

November 13, 2019 · 1 min · Khoa Pham

How to use Firebase in macOS

Issue #501 Use Catalyst Add to CocoaPods platform :ios, '13.0' target 'MyApp' do use_frameworks! pod 'FirebaseCore' pod 'Firebase/Firestore' end Troubleshooting Select a team for gRPC-C++-gRPCCertificates-Cpp FIRAnalyticsConnector: building for Mac Catalyst, but linking in object file built for iOS Simulator https://stackoverflow.com/questions/57666155/firanalyticsconnector-building-for-mac-catalyst-but-linking-in-object-file-bui The problem was related to the difference between Firebase/Core and FirebaseCore. The first is a subspec of the Firebase pod that depends on FirebaseAnalytics. The second is only the FirebaseCore pod....

November 12, 2019 · 1 min · Khoa Pham

How to use Firebase RemoteConfig

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 import FirebaseRemoteConfig final class RemoteConfigHandler { let remoteConfig: RemoteConfig enum Key: String, CaseIterable { case interval = "fetch_interval" var defaultValue: NSNumber { switch self { case .periodicGetSalons: return NSNumber(value: 300) } } } init() { self.remoteConfig = RemoteConfig.remoteConfig() let settings = RemoteConfigSettings() settings....

November 5, 2019 · 1 min · Khoa Pham

How to show image picker in SwiftUI

Issue #485 The easiest way to show image picker in iOS is to use UIImagePickerController, and we can bridge that to SwiftUI via UIViewControllerRepresentable First attempt, use Environment We conform to UIViewControllerRepresentable and make a Coordinator, which is the recommended way to manage the bridging with UIViewController. There’s some built in environment property we can use, one of those is presentationMode where we can call dismiss to dismiss the modal....

November 2, 2019 · 4 min · Khoa Pham

How to use array of strings in ForEach in SwiftUI

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) ) { VStack { Text(book.name) } } } } In case of primitive, we can just provide id to conform to Identifiable extension String: Identifiable { public var id: String { return self } }

October 31, 2019 · 1 min · Khoa Pham

How to make ISO 8601 date in Swift

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, offset or GMT Separator for date and time can be space, or T There are week format for date, but it is rarely used Timezone can be a lot of spaces after Second is optional Here are some valid strings...

October 29, 2019 · 3 min · Khoa Pham