DEV Community

Pablo Terradillos
Pablo Terradillos

Posted on

From React to SwiftUI

Some time ago, I've started working on TaskMeUp 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 + some design system (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
  4. 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

import SwiftUI

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

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
Enter fullscreen mode Exit fullscreen mode

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 to the memory space that holds the object and not the object itself.

let's take a look

On Javascript,

let user = {
  name: "Pablo"
}

let anotherUser = user

anotherUser.name = "Emiliano"

console.log(user.name) // "Emiliano"
console.log(anotherUser.name) // "Emiliano"
Enter fullscreen mode Exit fullscreen mode

On 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"
Enter fullscreen mode Exit fullscreen mode

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,

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"

Enter fullscreen mode Exit fullscreen mode

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. 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

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()
}
Enter fullscreen mode Exit fullscreen mode

Here test is trying to return either an User or a Person, both of them implementsGreeterthough by specifiend thattestreturnssome Greeterwe are saying that it returns an specific type and on our example it can be anUseror aPerson, 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, which is equivalent to getter and setters 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
}
Enter fullscreen mode Exit fullscreen mode

}

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:

If you are interested on Software engineering and the web, you can reach me on twitter as @tehsis

Top comments (1)

Collapse
 
adamwakif profile image
Adam WaƘiƑ

I have 3 years experience in React and 2 years with Flutter .. This year I changed my career to iOS Dev because of SwiftUI and Swift itself .. It was the best choice I made this year