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 use SurveyMonkey in React Native

Issue #521 #import <React/RCTBridgeModule.h> @interface RNSurveyManager : NSObject <RCTBridgeModule> @end #import "RNSurveyManager.h" #import <React/RCTLog.h> #import <SurveyMonkeyiOSSDK/SurveyMonkeyiOSSDK.h> @interface RNSurveyManager()<SMFeedbackDelegate> @property (nonatomic, strong) SMFeedbackViewController * feedbackController; @end @implementation RNSurveyManager - (instancetype)init { self = [super init]; if (self) { self.feedbackController = [[SMFeedbackViewController alloc] initWithSurvey:@"VV8X5QA"]; self.feedbackController.delegate = self; } return self; } + (BOOL)requiresMainQueueSetup { return YES; } - (dispatch_queue_t)methodQueue { return dispatch_get_main_queue(); } RCT_EXPORT_MODULE(SurveyManager); - (void)respondentDidEndSurvey:(SMRespondent *)respondent error:(NSError *)error { NSLog(@"respondent %@ error %@", respondent, error); } RCT_EXPORT_METHOD(show:(RCTResponseSenderBlock)callback) { [UIApplication....

November 29, 2019 ยท 1 min ยท Khoa Pham

How to allow unnotarized app to run on macOS Catalina

Issue #520 Remove quarantine xattr -d com.apple.quarantine /Applications/Flipper.app

November 28, 2019 ยท 1 min ยท Khoa Pham

How to use flipper

Issue #519 Run the app https://github.com/facebook/flipper https://facebook.github.io/watchman/docs/install.html#installing-on-os-x-via-homebrew brew install watchman git clone https://github.com/facebook/flipper.git cd flipper yarn yarn start

November 27, 2019 ยท 1 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 use ForEach with ScrollView in SwiftUI

Issue #517 Use ScrollView -> VStack -> ForEach -> Content struct SearchScreen: View { @State var searchObjects: [SearchObject] = [ SearchObject(name: "By name", search: { CountryManager.shared.search(byName: $0) }), SearchObject(name: "By calling code", search: { CountryManager.shared.search(byCallingCode: $0) }), SearchObject(name: "By domain", search: { CountryManager.shared.search(byDomain: $0) }), SearchObject(name: "By language", search: { CountryManager.shared.search(byLanguage: $0) }) ] var body: some View { ScrollView { VStack(alignment: .leading) { ForEach(searchObjects.enumerated().map({ $0 }), id: \.element.name, content: { index, searchObject in VStack(alignment: ....

November 22, 2019 ยท 1 min ยท Khoa Pham

How to modify data inside array in SwiftUI

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(name: String, search: @escaping (String) -> [Country]) { self.name = name self.search = search } } Although SearchObject is class, when we use ForEach, the changes to passed object wonโ€™t be reflected in our array and there is no reload trigger, we need to point to object in array directly, like...

November 22, 2019 ยท 1 min ยท Khoa Pham

How to use index in SwiftUI list

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) { index, country in NavigationLink( destination: CountryView(country: country), label: { VStack(alignment: .leading) { Text(country.name) .styleMultiline() } .paddingVertically() } ) } } }

November 22, 2019 ยท 1 min ยท Khoa Pham

How to setup multiple git accounts for GitHub and Bitbucket

Issue #514 Generate SSH keys 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 < ~/.ssh/id_rsa_bitbucket.pub ssh-add -D ssh-add id_rsa_github ssh-add id_rsa_bitbucket vim ~/.ssh/config #Github (personal) Host gh HostName github.com User git IdentityFile ~/.ssh/id_rsa_github #Bitbucket (work) Host bb HostName bitbucket.org User git IdentityFile ~/.ssh/id_rsa_bitbucket Config git config --global user.email "onmyway133@gmail.com" git config --local user.email "onmyway133bitbucket@gmail.com" Read more https://medium.com/avocoders/github-and-bitbucket-accounts-in-a-same-pc-5f8c67fd89d2 https://www.atlassian.com/git/tutorials/setting-up-a-repository/git-config Updated at 2020-10-04 06:52:07

November 22, 2019 ยท 1 min ยท Khoa Pham

How to use objectWillChange in Combine

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() } }) func reload() { self.isFavorite = store.isFavorite(country: country) } Read more https://forums.swift.org/t/combine-observableobject-in-uikit/28433 https://twitter.com/luka_bernardi/status/1155944329363349504

November 21, 2019 ยท 1 min ยท Khoa Pham

How to enable z and zsh-autosuggestions on zsh

Issue #512 https://github.com/zsh-users/zsh-autosuggestions/blob/master/INSTALL.md https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins/z git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions vim ~/.zsh.rc /plugins plugins=( git z zsh-autosuggestions ) source ~/.zshrc

November 19, 2019 ยท 1 min ยท Khoa Pham

How to show list with section in SwiftUI

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) { group in Section( header: Text(group.initial) .foregroundColor(Color.yellow) .styleTitle(), content: { ForEach(group.countries) { country in CountryRow(country: country) } } ) } } } }

November 16, 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 make full width list row in SwiftUI

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 { @ObservedObject var viewModel: BooksViewModel var body: some View { List { ForEach(viewModel.books) { book in RowView(vault: book) } } .listStyle(GroupedListStyle()) } } private struct RowView: View { let book: Book var body: some View { VStack(alignment: ....

November 14, 2019 ยท 1 min ยท Khoa Pham