From React to SwiftUI
Published: 2020-12-16 13:01:28

Some time ago, I've started working on [TaskMeUp](https://taskmeup.alidion.studio) for which I wanted to provide a native experience beyond a web one.

I considered lucky that just one year ago, Apple announced SwiftUI, a framework which, on Apple words:

>  provides views, controls, and layout structures for declaring your app’s user interface. 

Something that might sound similar for those of us comming from the web world, since it's quite similar to React (and some other tools and frameworks, of course)

Truth is that SwiftUI takes a lot of inspiration from React and it's quite similar, though adapted to Apple ecosystem and offering an experience similar to what on the web frontend world would be React + (Mobx)[https://mobx.js.org/README.html] + [Storybook](https://storybook.js.org/) + some [design system](https://github.com/auth0/cosmos) (Apple's own on this case).

# Starting with SwiftUI

To start working with SwiftUI we need macOS (on the contrary of the web, Apple's ecosystem is not open)

1. We open up Xcode
2. Select "Create new Xcode project"
3. Choose iOS -> App
5. We fill in some data, and quite important, select "User interface: SwiftUI"

Xcode will then initialize the project and we will see on its main screen a few files already created. By default, we will have open "ContentView.swift", our first *SwiftUI view* 

```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        Text("Hello, World!")
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
```

We can already compile this and run (cmd + r) on a simulator or even on an device (either iOS, iPadOS or macOS). We can also see to the right or the bottom of the editor (depending on our preferences) a preview of our application/view (most likely you will need to click on "resume" for something to happen, this preview stops working with ease).
Let's take a look at what's going on here:

The first line `import SwiftUI` is clear, we import that framework (Apple's calls frameworks to all its libraries), bringing to our context all of the names and symbols declared there.

Right after it we see a `struct` named `ContentView` which implements a `protocol` named `View`

# protocols, classes, structs, references, etc

Let's start from the simplest one: a `protocol` is similar to what in Typescript or Java is called an `interface`. That is to say, a _contract_, we are stating our `struct` will have a set of specific attributes and/or methods. You can't declare types on javascript so there's not an equivalent for this other than documenting (or doing a runtime check) what properties or methods an specific object will have.
By saying that `ContentView` implements the View `protocol`, we can use ContentView anywhere a View is expected.

Let's move on to the `struct`: This is similar to a `class` in Javascript and an instance of this `struct` is similar to an object. There's one caveat though: on Swift, **structs instances will be always passed as values**
 
What does that means? If we pass our _object_, via a function call or an assigment, this object will be copied and the function or the new symbol will get _a copy_ of it.
On Javascript, objects are always passed by _reference_, that means that what we pass is actually a [pointer](https://en.wikipedia.org/wiki/Pointer_(computer_programming)) to the memory space that holds the object and not the object itself.

let's take a look

On Javascript,

```javascript
let user = {
  name: "Pablo"
}

let anotherUser = user

anotherUser.name = "Emiliano"

console.log(user.name) // "Emiliano"
console.log(anotherUser.name) // "Emiliano"
```

On Swift,

```swift

struct User { 
  var name: String
}

var user = User(name: "Pablo")
var anotherUser = user
anotherUser.name = "Emiliano"

print(user.name) // "Pablo"
print(anotherUser.name) // "Emiliano"
```

While it's not present on the code we are analizing, Swift provides `class`, which we can say is similar to a `struct` which values are passed by _reference_ (on the same way than Javascript).
The syntax is quite similar than the previous example, 

```swift
class User {
  public var name: String

    init(name: String) {
        self.name = name
    }
}

var user = User(name: "Pablo")
var anotherUser = user
anotherUser.name = "Emiliano"

print(user.name) // "Emiliano"
print(anotherUser.name) // "Emiliano"

```

You can also notice that I had to make two changes: specify the name attribute as `public` (by default on classes these are private) and define a constructor (yes, `init` method is to Swift's classes what `construct` is on Javascript ones)

Let's get back to the initial SwiftUI code. As a sole property of this `struct` we have `body`. On this case, the ":" (from `var body: some View`) are telling us that `body` conforms to... _some view_.
We can read this literally, body is some view, _we don't care which one_.
Once again this is something that won't have a purpose on javascript or any other not strongly typed language, though a valid question is "what's the different between `some View` and just `View` if in both cases `View` is a `protocol`?
Well, `some View` is more similar to a [generic type](https://docs.swift.org/swift-book/LanguageGuide/OpaqueTypes.html). By specyfing `some View` we are stating that this variable is of an specific View type, not just any View.

For example, the following example will throw an error

```swift
protocol Greeter {
    func greet() -> String
}

class Person: Greeter {
    func greet() -> String {
        return "Hello"
    }
}


class User: Greeter {
    func greet() -> String {
        return "Howdy!"
    }
}

// This function is invalid
func test(a: Int) -> some Greeter {
    if a > 5 {
        return User()
    }

    return Person()
}
```

Here `test` is trying to return either an `User` or a `Person, both of them implements `Greeter` though by specifiend that `test` returns `some Greeter` we are saying that it returns an specific type and on our example it can be an `User` or a `Person`, not both.
If we clear the word `some`, the example will compile successfully.

# Computed properties

`body` has more secrets, it immediately opens a curly braces that surrounds a piece of code.
This is known as [Computed Properties](https://docs.swift.org/swift-book/LanguageGuide/Properties.html#ID259), which is equivalent to [getter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) and [setters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set) methods of javascript.
On this case, since we are not specifying how to assign a new value to body, it's a getter.

```
struct Person {
    var name: String
    var yearOfBirth: Int

    var age: Int {
        2020 - yearOfBirth
    }
}

var p = Person(name: "Pablo", yearOfBirth: 1987)

print(p.age) // 33 

```

What's inside the curly braces is just a function. Swift loves to eliminate redundant code, that's why on single line functions, the result of that line is returned (when you have more lines, you'll need to add `return 2020 - yearOfBirth`)

Last but not least (finally!), `body` returns `Text("Hello world")`. If we do "option + click" on  Text, we will see that this is a `struct` that implements `View` (which was expected since we are declaring that body will return `some View`)

# Views and Components

We can say that `Text("Hello world")` is a component, like React components. SwiftUI knows exactly how to show it, with which style and on what position (even considering if it's running on an iPhone, Apple Watch, Apple TV, etc).
SwifUI provides of course a lot of components and we can also define our owns. Actually on this example, `ContentView` is a component just like Text is.

For example, let's surround our Hello World on a `List` component

```swift
struct ContentView: View {
    var body: some View {
        List {
            Text("Hello, World!")
        }
    }
}

```
And we can see how our application has changed.

We can also make our Text clickable/tapable using a `Button`

```swift
struct ContentView: View {
  var body: some View {
    List {
      Button(action: {
        print("Hi")
      }) {
        Text("Hello, world!")
      }
    }
  }
}
```
Now everyime we click (or tap) our text, we will see "Hi!" on Xcode debug console.

Worth noticing that all views has methods to change their styling. Eg. we can do `Text(...).fontWeight(.bold)` to show that text in bold.


# Extra

## parameters labels

As you might have seen, when calling a function in Swift, parameters also indicates its names. Swift allow us to define labels on the parameters ans even define different names for the implemenation and the calling:

```swift
getAvatar(for: "Pablo")

func getAvatar(for user: String) {
  // ...
  // user -> "Pablo"
}

```

I can omit the `for` label and use it as `getAvatar(user: "Pablo")` or just use an _ to completely omit the name, but it won't read as good.

## Functions as last parameter

I'm not exactly sure how this is called, though something that originally confused me on swift, are cases like the one we have in Button above

```swift
 Button(action: {
    print("Hi!")
   }) {
     Text("Hello, World!")
   }
```

Like Javascript, Swift can use functions as first class citizens, pass them as values and therefore our functions can accept them as parameters. What's courious is that when the function is also the last argument of the function, you can completely omit the label and write the function outside of the parenthesis:

```swift 
func doSomething(value: Int, method: (Int) -> ()) {
  method(value)
}

doSomething(value: 5) { val in
  print(val) // 5
}
```

We can also be explicit of course


```swift
doSomething(value: 5, method: { val in
  print(val) // 5
})
```

# Final thoughts

SwiftUI has a similar premise than React: Our view is a function of our state and views are composed from other views.
Much of the mindset you used on React can be used on SwiftUI as well.
Xcode also provides a lot of guidelines to help us writing our code as well.

Also, SwiftUI makes it easier to follow Apple conventions and write a _decent looking_ UI that adapts to the system (ie. font changes, dark mode, etc) with almost 0 effort from our side.
The major caveat at this point is that the whole platform is not _stable_ as we would like. On each new OS version (or even Xcode versions) things might breaks on mysterious ways or just behave differently, so I think that while is not strictly required, a deeper understanding of the Apple's _previous_ UI framework UIkit is still valuable when working on mid to large sized apps. 

If you have reached this far and you are interested on learning about Swift or SwiftUI, these are some great resources:

* [100 days of SwiftUI](https://www.hackingwithswift.com/100/swiftui) by Paul Hudson
* [Standford CS193p classes](https://www.youtube.com/watch?v=jbtqIBpUG7g) on SwiftUI
* [Apple's introduction to SwiftUI on WWDC 2019](https://developer.apple.com/videos/play/wwdc2019/216/)
* [Apple's tutorials on SwiftUI](https://developer.apple.com/tutorials/swiftui/)

If you are interested on Software engineering and the web, you can reach me on twitter as [@tehsis](https://twitter.com/tehsis)