UPDATE: Support for switch statements and pattern matching was added in Swift 5.3, so this project is no longer needed.
The lack of switch statements, pattern matching, and if let x = x can make expressing certain things in SwiftUI a bit cumbersome. Switcher gives you back that power.
Consider the following enum:
enumViewState:Equatable{case state1
case state2(String)case state3(left:Int, right:Int)}If we want to represent a view which can be in one of these states, we'd probably want to write something like:
structMyView:View{letstate:ViewState
// 🛑 Swift Compiler Error: "Function declares an opaque return type, but the return statements
// in its body do not have matching underlying types"
varbody:someView{switch state {case.state1:returnView1()case.state2(let string):returnView2(string)case.state3(let left,let right):returnView3(left, right)}}}Unfortunately, SwiftUI doesn't compile this unless we wrap all of these views in AnyViews (which has it's own set of problems. With Switcher, expressing this is a breeze, and it works entirely without AnyView:
structMyView:View{letstate:ViewStatevarbody:someView{Switcher(state).just(ViewState.state1){View1()}.match(ViewState.state2){ string inView2(string)}.match(ViewState.state3){ left, right inView3(left, right)}}}In .match, the associated values of the enum you define in the first argument become the arguments to the closure you pass as the second argument. 🎉
Note: If your enum has cases with no associated values, your enum will need to conform to Equatable in order to match on those cases.
Unwrapping Optionals with if let something = something { ... } is common practice in Swift. Switcher brings this functionality to SwiftUI:
structIfCaseLetDemo:View{
// We only want to draw something if this field is not `nil`
letoptional:String?varbody:someView{Switcher(optional)
// `if let` is just the same as `match` on `Optional`'s `.some` case:
.match(Optional.some){ unwrappedOptional inText(unwrappedOptional)}
// Optional fallback. You can leave this out and nothing will be drawn.
.fallback{ _ inText("Fallback text here")}}}No enum? No problem. The following types of matchers are supported too:
letcount:Int=...Switcher(count)
// If your type is equatable, you can match against values directly with `.just`
.just(2){ _ inText("Double trouble.")}
// All matchers send the value that was matched as an argument to their closure
.just(3){ three inText("\(three) == 3")}
// Arbitrary predicates are also supported with `.when`
.when({ $0 >9 && $0 <11}){ _ inText("Ten.")}
// Use `.fallback` to catch all remaining cases. Note: cases are matched in order, so always put `fallback` last!
.fallback{ n inText("\(n)")}Switcher's enum-related functionality is powered by pointfreeco/swift-case-paths.