I run a functional programming weekly meeting called "FP Club" at The New York Times. We started 2020 by diving into SwiftUI. These are their stories.
🏝 SwiftUI Club is on hiatus until further notice. 🏖 Let’s all take a break from video meetings. 📹
2020-06-16
We continued implementing NYT’s Tiles in SwiftUI. We refactored to make the SwiftUI body
struct easier to understand, so we could see what we needed to change. EmojiTiles 3.zip (Xcode 11.4+)
2020-05-26
We continued implementing NYT’s Tiles in SwiftUI. After much trial, we got matching tiles to clear their emoji! We learned the hard way how to compare two tiles in the .onTap
. EmojiTiles 2.zip (Xcode 11.4+)
2020-05-12
We started implementing NYT’s Tiles in SwiftUI. We got as far as a static grid of emoji in squares. EmojiTiles.zip (Xcode 11.4+)
2020-05-05
We programmed as a group to build a slider component. We got a nub on a bar attached to an @Binding
value. We moved the nub with DragGesture().onChanged
. We hit snags in positioning, which we solved with a GeometryReader
. Project: Eric the Slider.zip
2020-04-28
We programmed as a group to build a radio button component. One person drove, and other people took turns navigating. We got more experience with @State
and @Binding
, and breaking out views into smaller components. We reused the BindingProvider
from the previous project to change a binding value in preview. We hit a small snag with getting our view to update when breaking out RadioItem
into its own component. Project: RadioButton.zip
2020-04-21
We broke into small groups to build a UISwitch replacement. We got experience with @State
vs @Binding
, saw how Circle
’s frame works, saw .onTapGesture { … }
, and learned to not name your project a SwiftUI reserved word! Project: SwitchUI.zip.
2020-04-14
Zev showed us his Mini in SwiftUI project. Very cool! We talked about one advantage of SwiftUI layout versus Auto-Layout: composition/encapsulation. There’s no spooky action at a distance. That’s because Auto-Layout constraints for all views are in the linear solver all at once. We also talked about GeometryReader, combining HStack & Spacer, and netsplit.com.
2020-03-31
We looked at a challenge from Swift Over Coffee, which asked listeners to build the Apple Watch "breathe" animation in 1 hour. We worked through Paul Hudson's submission to see how it worked, then experimented with animation code on our own.
Paul Hudson's submission
//
// Gasp – a quick clone of the watchOS Breathe UI, for Swift Over Coffee
// https://github.com/twostraws/SwiftOverCoffee
//
import SwiftUI
struct ContentView: View {
@State private var flowerOut = false
var body: some View {
ZStack {
Color.black.edgesIgnoringSafeArea(.all)
ZStack {
ForEach(0..<6) {
Circle()
.foregroundColor(Color(red: 0.6, green: 0.9, blue: 0.8))
.frame(width: 200, height: 200)
.offset(x: self.flowerOut ? 100 : 0)
.rotationEffect(.degrees(Double($0) * 60))
.blendMode(.hardLight)
}
}
.rotationEffect(.degrees(flowerOut ? 120 : 0))
.scaleEffect(flowerOut ? 1 : 0.25)
.animation(Animation.easeInOut(duration: 4).delay(0.75).repeatForever(autoreverses: true))
.onAppear() {
self.flowerOut.toggle()
}
}
}
}
Our first animation test
import SwiftUI
struct AnimatedView: View {
@State var far: Bool = false
var body: some View {
VStack {
HStack(spacing: self.far ? 100 : 10) {
Text("Hello,")
Text("World")
.rotation3DEffect(.degrees(self.far ? 180 : 0), axis: (x: 1, y: 1, z: 0))
}
.animation(Animation.easeInOut(duration: 2).repeatForever(autoreverses: true))
Button(action: {
self.far.toggle()
}) {
Text("Change stuff")
}
}
.onAppear() {
self.far.toggle()
}
}
}
struct AnimatedView_Previews: PreviewProvider {
static var previews: some View {
AnimatedView()
}
}
Our nearly-working SwiftUI loading spinner. Need to figure out why it doesn't loop correctly
import SwiftUI
struct Spinner: View {
@State private var someBool = false
var body: some View {
ZStack {
ForEach(0..<12) {
Capsule()
.foregroundColor(self.someBool ? Color.blue : Color.red)
.frame(width: 10, height: 30)
.offset(x: 0, y: 40)
.rotationEffect(.degrees(Double($0) * 30))
.animation(Animation.easeOut(duration: 0.2)
.delay(1.0 / 12 * Double($0))
.repeatForever(autoreverses: false)
)
}
}
.onAppear() {
self.someBool.toggle()
}
}
}
struct Spinner_Previews: PreviewProvider {
static var previews: some View {
Spinner()
}
}
2020-03-24
We worked through Apple’s third tutorial on SwiftUI: Handling User Input. We basically learned how to pass around a brute-force state: @EnvironmentObject
. Cool, but how should a larger app handle state, handle limiting what each view needs to know about?
2020-03-17
We worked through Apple’s second tutorial on SwiftUI: Building Lists and Navigation. It was kinda boring, but only because this is the third or fourth time we’ve done lists! We also saw how to change previews within in PreviewProvider.
2020-03-10
We worked through Apple’s first tutorial in their series of SwiftUI intro tutorials that launched at WWDC. We also looked at Paul Hudson’s SwiftUI by Example, but it seemed too "bottom-up," in the sense that it had detailed information on each component, but lacked a more holistic view of how to build more complete things.
We also mentioned:
- Paul Hudson’s 100 Days of SwiftUI, a series of medium-complexity tutorials that build on each other to teach you how to make a few simple apps and games.
UIViewPreviewProvider
, an open-source repo that lets you use SwiftUI previews while developing non-SwiftUI apps.- An NSHipster Post on a similar idea of using SwiftUI previews in non-SwiftUI development, but with a different approach. Somewhere between these two lies a nice and usable system ;)
2020-03-03
Having ended the iDine project, Paul Hudson wanted to walk us through the Xcode project template and some view modifiers. We followed here through and including here.
2020-02-25
We followed here through here. We learned about alerts, editing tables, and got a few "challenges" from Paul. iDine 2020-02-25.zip
2020-02-18
Starting here we learned about creating TabViews, using @State bindings, Form views, two-way bindings, and formatted string interpolation. We ended at the end of here. iDine 2020-02-18.zip
2020-02-11
Starting here we learned about view styling, ZStack and some of SwiftUI data pipeline: environment objects and @Published
. We ended at the end of here: iDine 2020-02-11.zip.
2020-02-04
Switched to Paul Hudson’s SwiftUI by Example book, since it seems more appropriate for our novice SwiftUI level :) We did the first three pages of Building a complete project.
2020-01-28
Welcome all the new people!
We watched and discussed the first episode of Point-Free’s SwiftUI series. Follow along at home to get some SwiftUI under your fingers, or take a look at the playground: 2020-01-28 - Point-Free #65 StateManagement.playground.zip.
2020-01-14
We did the first couple exercises in Point-Free episode 65.
2020-01-07
New year, new huge topic!
We watched and discussed the first episode of Point-Free’s SwiftUI series from last July. We’ll do the exercises for homework and talk about them next time.
2020-01-07
First session of the new! We watched and discussed the first episode of Point-Free’s SwiftUI series from last July. We’ll do the exercises for homework and talk about them next time.
2019-12-03
Coordinating local & network data fetching. Kevin brought up the "repository pattern." Logan brought up composable caching, as in Brandon Kase’s talk.
2019-11-19
Property-based testing. We watched and discussed Brian Gesiak - Functional Testing
2019-11-12
An exercise in API design. More specifically, can we make the PURR library easier to test/override? We talked about different ways change it and their pros & cons. 2019-11-12 API discussion.txt
2019-09-25
After some time off, we get back with pullbacks. Pullback.playground.zip
2019-08-13
Once more with monoid: structs! 👩🏽⚖️ Trying out constructing legal requirements. 👨🏼⚖️ Monoid+.playground.
- Also, at the very end Eric suggested it should be possible to compose monoids. I submit to you, Monoid zip.playground
2019-08-06
Extended the “reduce” conversation to “monoid”, a useful concept for talking about making one thing out of many things, or, “Out of many, one." Monoid.playground.zip
2019-07-31
Intuition for reduce
Intuition for reduce.playground.zip
2019-07-23
More algebraic data types: functions are exponential! Math:Swift.txt, ADT - Function.playground.zip
2019-07-16
Skipped for Maker Week.
2019-07-09
Watched Point-Free’s episode on algebraic data types.
2019-07-02
We explore a couple uses in code of curry
--partially applying functions. curry in code.playground.zip We also said a few:
- In a factory pattern
- Recording a user’s plays, then scores
- Passing a token to an SDK
- Any async sequence, like user input that’s designed as two steps
- Calling
map
2019-06-23
Methods are functions in disguise. Plus, “currying”. Methods are functions; currying.playground.zip
2019-06-18
We asked: what’s a problem we’ve had recently? or what’s been on our minds? Some things said:
- News: e.g. SectionFrontVC with “FollowingChannel”
- News: UI getting weird when logging out because the UI also wants some different data because you’ve logged out
- Crossword: LbzFlowController’s use of reduce → We talked about the “diamond problem” for Observables. (Combine has the same behavior.) Observable diamond.playground.zip; Combine diamond.playground.zip
2019-06-11
What were our favorite things out of WWDC? What’s up with this new Combine
library?
2019-05-28
Functor laws, some in Haskell and in Swift. Functor.playground.zip
2019-05-21
We discovered Functor. Haskell/Functor, PointFree.co: map
2019-05-17
We talked in groups to relate Array.map and Observable.map. We came up with three ideas:
- Array elements are known instantly, map is called once and the closure is called instantly. (eager) OTOH, Observable elements are not known in advance, the Observable instance keeps the closure and applies is lazily. (lazy, JIT)
- Their types are similar:
Array.map -> Array
&Observable.map -> Observable
- Both preserve the order & count of the input.
2019-05-10
Reactive programming. What do “map” and “merge” mean for Observable?
2019-04-30
“zip” on Optional & Result! zip for Optional & Result.playground.zip
2019-04-23
All about implementing different “zip” functions ourselves. “How do you get to Carnegie Hall?” implementing zip.playground.zip
2019-04-16
Last week was “zip” for Array. On the 16th we extended “zip” to Optional. One concept, two types? What does it mean?? zip for Optional.playground.zip
2019-04-09
What’s the deal with Swift.zip
and PointFreeCo.zip(with:)
? Let’s show how they’re related and why they’re both called "zip". zip.playground.zip
2019-04-02
Read through What the heck is polymorphism? with some examples in Swift: what the heck is polymorphism.playground.zip. Jim drew the subtyping relationships.
2019-03-26
Reviewed the ROP composition riddle from last week. Solution in FP-20190326.playground.zip
2019-03-19
ROP examples in Swift. Big thanks to Jim for the translation. FP-20190319 redacted.playground.zip
2019-03-12
“Railway Oriented Programming” with Scott Wlaschin. video, site & slides. The day’s playground: FP-20190312.playground.zip
2019-03-05
What would the "Environment" style dependency injection look like in Crossword? Jim guided us through the very first bits. Point-Free ep16 & ep18.
2019-02-26
Jim tied together Swift sugar and functions & ideas we’ve been talking about. Definitely review the playground! FP-20190226.playground.zip
2019-02-19
map, flatMap, compose, etc. Review because it helps :)
2019-02-12
Newsreader team wrapping up the ‘Home’ project, so this time was Crossword people looking at Crossword examples.
2019-01-15
Brian Green joins up! Diagrammed map
with colors, which seemed to help a lot. We’re slowly starting to see how it’s not just another way to write a for-loop. More to come.
2019-01-08
Izza joins us! Refresher day. Diagrammed compose
and diagrammed map
on Array & Optional. Map.playground.zip
2018-12-11
"Phantom type" and Pavel diagrammed compose
--aka >>>
--and map
. Compose.playground.zip
2018-12-04
Showed examples of >>>
and |>
. Talked about flip
and curry
. See >>>
and a curried map
in CrosswordFoundation/API/JSON.swift
2018-11-27
Casual discussion of pointfree.co and tech things. Also, a real life stack overflow! See HomeConverterThread
in ios-newsreader/commits/d34db33f
2018-11-13
Function composition: motivate it, then do it. FP 2018-11-13.playground.zip
2018-10-30
Danny, Kayla, and Veronique join us! Back to basics: referential transparency, total/partial, pure/impure. Partial.playground.zip
2018-10-23
Type algebra
2018-10-16
Applying Applicative
to iOS News’s Rules.Result
2018-10-09
Rediscovering map and flatMap in callbacks; https://vimeo.com/292702159; Oct 2 & 9 Playgrounds.zip
2018-10-02
Applicative
2018-09-25
Composition ideas in code, passing Bool vs fn, functor laws
2018-09-18
Globals in NYTSwiftFoundation and in News.app
2018-09-11
Jim’s styling ruleset DSL
2018-09-04
DSL practice (pointfree.co #27)
2018-08-28
watched "I See What You Mean" by Peter Alvaro (youtube.com)
2018-08-21
Expression problem; Expression Problem 2.playground.zip
2018-08-13
Profunctor the idea and an example: Logan’s type-safe key-value store idea, StoreQuery
2018-08-07
Lambda calculus, Lambda cube, polymorphism (subtyping, ad hoc), type operators (kinds), dependent types
2018-07-31
Contrafunctor and Profunctor
2018-07-17
Discuss flatMap and Kleisli composition >=>; Kleisli.aquarium.zip; Kleisli.playground.zip
2018-07-10
Drew map and flatMap, discussed “functional”
2018-07-03
(Skipped. Early out before July 4.)
2018-06-26
overall motivation. what is FP? map, bimap, flatMap
2018-06-19
split & bimap, A??.flatMap(id) -> A?
2018-06-12
curry; apply |>
and <|
; compose >>>
and <<<
2018-06-05
fish operator >=>
glug glug
2018-05-14
reviewed examples from Crossword and Newsreader of the more "functional" style
2018-05-08
motivate and diagram map
and flatMap
(Jim R and Craig H are new)
2018-05-01
(Skipped. Logan was out.)
2018-04-24
semigroup, monoid
2018-04-17
reiterate map and flatMap by diagram, the algebra of types.
2018-04-10
anatomy, theory, and motivation of map and flatMap
2018-04-03
referential transparency, total/partial, (non-)surjective, fn composition, map, and hinting at the map typeclass