iOSCon 2017
30th - 31st March 2017 | London đ´ó §ó ˘ó Ľó Žó §ó ż
iOSCon2017 was held at CodeNode on 30 and 31st March 2017.
Below are the notes I took. These should not be considered definitive or 100% accurate to the content presented - they are more a reminder of things I found interesting and useful. Where possible I have tried to find links to the slides or presentation material.
Balance
Saul Mora - SkillsCast- Slides
- Swift only a couple of years old
- Still learning to embrace swift and how it makes sense
- Main Swift tools we have are Functions, Protocols, Objects
- Swift blends a lot of approaches - Object OP, Functional OP, Protocol OP
- Throughtbot JSON parsing library - Argo .
- Runes library for operators
- Recommendation: use standard operators and less frameworks where possible
- Makes you code simpler, less complex and more familiar
- Use
map
and flatMap
when using a Result
type
- Use Promises to solve asynchronous throwing
- Obj-C is message based
- In Swift use
forwardingTarget(for:selector)
rather than NSInvocation
- Use a message / coordinator bus to allow a frameworks to communicate via Obj-C style messages
- A coordinator objects needs to define what the next coordinator is
- Swift compiler will complain when connecting, so use
AnyObject
to allow any message to be sent.
- In Swift, singletons are easier to write and therefore easier to abuse
- Use protocols to define a singleton. Then a concrete implementation can replace the default (static) singleton value.
- KVO in Swift is horrible!
- Compose an object by wrapping another. Take the wrapped object in the
init
- Swift brings together lots of paradigms
- A general rule - use
- Functions to calcualte state
- Objects to present state (the UI)
- Protocols for communicating state
The Grant Tour of iOS Architectures
Dan Cutting - SkillsCast - Slides - Blog Post - Example Code
- Define âArchitectureâ as the internal structure within an iOS app
- Can be a divisive subject
- In âApple MVCâ, the view controller is often the root of the app
- View controllers do a lot!
- Long files are hard to understanding, testing is hard and muddles up model-view-controller
- Model-View-Presenter (MVP)
- Presenter talks to the view controller via a protocol. This makes is eraser to test.
- Model-View-View-Model (MVVM)
- MVP and MVVM are similar. In MVVM there is something like binding with the View-Model and the View-Controller. See RxSwift
- Usually all routing is done through the view controller (i.e. prepare for segue). Here the view controller needs to know about all the dependencies and the view controller is hard to reuse in a different context.
- Can use a Coordinator to combine all presenter objects. View controllers do not know about each other.
- Can use a hierarchy of coordinators.
- View-Interactor-Presenter-Entity-Routing (VIPER)
- In VIPER there are is a tonne of separation
- Based on the âclean architectureâ concept. Here UI is considered an external system.
- Inner rings cannot know about the outer rings.
- Uses the âneed to knowâ principle
- Wireframe classes are responsible for routing. They inject dependencies.
- âClean architectureâ is not complete. VIPER and VIP are 2 implementations.
- Uber have their own implementation where routing is decoupled from the UI interactions.
- Testability is important in architecture.
- There should be a place for everything.
- Can lead to philosophical disagreements, so you need a solid team.
- Architectures can leads to lots of boilerplate code.
- Lots more types and lines of code for VIP, but each type is much smaller.
- Piecemeal refactoring is OK! Start with a single view controller.
- Stop extracting when happy with test coverage. Decide where on the spectrum is right - no separation vs complete separation.
- This spectrum (roughly) maps to difference between a design pattern and an architect.
- The more you take out of a view controller the easier it is to test.
- Core Data tentacles stretch thoughtout an app and itâs architecture (i.e. fetched results controller), therefore it is hard to treat it as an external system in the âclean architectureâ sense.
Architecting Alive Apps
Jorge Ortiz Fuentes - SkillsCast - Slides
- Architecture is beneficial when an application starts to grown
- Interactors encapsulate the use cases.
- Presenters decide what to do when the view is loaded. They setup and then update a view.
- Entity Gateway is an interface to the persistence layer
- Inversion of dependencies uses an abstraction layer to decouple from a framework
- Any abstraction is better than none
- For a good abstraction:
- No reference to the framework. e.g. a Core Data wrapper cannot leak references to managed objects
- Use your own data types. e.g. your own struct over an
NSManagedObject
- Use your own communication
- Move implementation details into the abstraction type
- For a complex long term project, abstractions are very helpful. Decide them as you go.
Generics and extensions in Swift
PaweĹ BrÄ
goszewski - SkillsCast
- Can be more specific with a generic type by constraining it to a protocol
- Cannot nest a generic type inside a non-generic type. Must move it out of the non-generic type.
- Cannot have a generic function inside a generic type when the types do not match.
- Curiously Recurring Template Pattern - CRTP
- Swift 3 does not support circular generic type parameters (yet)
Introduction to Functional Reactive Programming
Eliasz Sawicki - SkillsCast - Slides
- Asynchronous data flows
- A stream of data over time. Previously used delegates, notifications etc
- Now we have
map
, filter
, reduce
to transform a stream
- rxmarbles.com
- ReactiveSwift was originally part of Reactive Cocoa
- A stream is called a âsignalâ
- A signal represents events over time
- A signal is observed
- A signal producer represents a task
- A âhot signalâ always emits a value
- A âcold signalâ only emits where this is an observer
- Bind signals to properties.
The art of building UI reuse components
Kevin Muessig - SkillsCast - Slides
- Building reusable UI should adaptable, accessible, localisable and tintable
- Making a reuse component is like making an API
- Use interface builder for these benefits:
- Less code
- Better visibility
- Easier debugging
- Integrated tool support
- Live preview
IBDesignable
to preview file in IB
IBInspectable
to expose UIView
properties for IB
NibDesignable
does all the complicated stuff for you
- Use xib files for reusable views
- Use storyboard to reusable view controller and UI flows
TDD in Xcode Playgrounds
Paul Ardeleanu - SkillsCast - Slides - Blog Post
- Playgrounds offer fast feedback loop - a good fit for TDD
- Test or GTFO!
- Use
MyTestCase.defaultTestSuite().run()
in a playground
Natural Swift
Paul Hudson
Five Principles of Functional Programming
- Functions are first-class data types
- They can be used as parameters to other functions
- Same inputs, same outputs; no side effects
- Prefer immutable data types
- Reduce how much state we track
- Benefits:
- Trivial unit tests
- Remove unexpected dependencies
- Compose complex app from simpler, smaller parts
- Protocol Oriented Programming (POP) is similar to OOP but you use composition rather than inheritance
- Can declare a protocol which simples combines other protocols to DRY up conformances
Bringing Swift enums to Objective-C with macros
Brandon Kase - SkillsCast - Slides - Sample Code
- It is possible to construct impossible object states in Obj-C, i.e. nil properties for a specific enum case
- Adding a new property can be forgotten when performing case analysis
- Swift enums help can help us, i.e. associated values
default
in switches breaks the safety of exhaustive analysis
- Macros are compiler directives to expand strings before compile time into Obj-C code
BKOneOf
macro used an Pinterest
- Macro cannot capitalise method names unfortunately đ
- Errors are complicated when using the macro
- Xcode indexes and auto completion works!
- Swift enum also known as an Algebraic Data Type or Sum Type
- Use enum when you have mutually exclusive heterogeneous data
- âRayifiedâ turns something abstract into concrete
Itâs about time
Daniel Steinberg - SkillsCast
- You day ends up filled with âstuffâ
- But you lose this time time through the week
- It takes 23 minutes to return after just 1 minute of interruption , for both the interrupter and the interrupted.
- Working more hours becomes expected.
- The French have a healthy(er) work-life balance
- Only so much work you can do and maintain a suitable pace
- We make real connections outside of work (at the pub đť)
- Writers write first for a period, then edit later. This protects these blocks as they are different activities.
- Pomodoro - either focused or relaxes
- There are moments where you are not âthereâ as you are focused on something elsewhere.
- Focus on your purpose
- What is the most important?
- Who is the most important? (Donât forget yourself)
- Dutch Auction is a metaphor to show you must schedule deliberately
- âThe Future is here, itâs just not evenly distributedâ - William Gibson
- It is valuable to say âI canât do thatâ
Composable Caching in Swift
Brandon Kase - SkillsCast - Slides
- Caches can be composed together
- Use âFuturesâ type to handle async callbacks
- Can model different layers in composition. Network â RAM â Disk
- An identity cache always misses
- An associative operator allows us to impose
- Now we have a monad!
- Transform caches so that types match between caches
- For example, a disk cache needs strings, network cache needs URLS
- This is a âvirtual cacheâ as data is always transformed to get it
- Optimise by using in flight requests
- Stops unneeded network calls
- Can use the same in flight requests for different caches
- Carlos library for this
- Can replace on disk cache with a full persistence framework, i.e. Core Data
Dependency Injection in Practice
Yoichi Tagaya - SkillsCast - Slides
Sample Code: Simple DI Container , Swinject Example, Cake Pattern
- Yoichi is the author on Swinject
- Inversion of Control allows to reuse dependencies
- Initialiser injection, property injection, method injection
- If implementation is tightly coupled to a concrete system then it is hard to test
- Loose coupling uses an abstract interface between them
- Dependency injection (DI) is managed by a container. This resolves dependencies.
- Register the dependency in the DI container
- Use
reflecting
on a string to get a unique hasahble key for any type T
- Can resolve to just a type, or the same instance of a type
- Dependency definitions are in a single place
- Cake Pattern: statically defined DI
- Protocol defines placeholder for dependency - the abstraction
- Another protocol defines the concrete dependency. This inherits from the abstract protocol, and an extensions makes in concrete
- Great article: Dependency Injection with the Cake Pattern in Swift by Bob Cottrell
Do-It-Yourself Functional Reactive Programming
Manuel M T Chakravarty - SkillsCast - Slides
- React to change in structured safe manner
- Only mutate local properties
- Explicit streams of change propagation
- Track kinds of changes with types
- A stream is a function mapping from time to values
- An associated type depends of the type of the protocol