How to use UICollectionViewLayout
Issue #546 Using the Flow Layout Customizing Collection View Cell Insertion Animations
Issue #546 Using the Flow Layout Customizing Collection View Cell Insertion Animations
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....
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) } } }
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
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...
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) }) )
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....
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...
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() } }
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: [ ....
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....
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
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 }
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...
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....
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....
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....
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....
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 } }
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...