SwiftUI、はじめました

本投稿は TECOTEC Advent Calendar 2020 の4日目の記事です。

みなさま、おはこんばんちは。投資戦略システム事業部でiOSのエンジニアをしています、赤池です。
昨年Appleが新しくSwiftUIを発表し、その時は情報量も少なく後回しにしていたのですが、発表されてから一年以上も経つと流石にいろいろ調べられるようになってきたので、今年から本格的にSwiftUIを触ってみようと思いました。

SwiftUIについての説明はこちら↓ developer.apple.com

今のところ業務で使う予定はまだありませんが、いずれ訪れるであろう時代の波に置いていかれないように勉強していこう、というわけで今回はApple公式のチュートリアルを見ながら、Swiftのときとどれくらい書き方が変わって、どれくらい私の中の常識が通用しなくなったのかを見ていきたいと思います。
とりあえず今回はSection4までにしていきたいと思います(全部は長いので……)
チェケラ!

Apple公式のチュートリアルはこちら↓ developer.apple.com

Section1 新規ファイルの作成

新規ファイルの作成に関してはほとんど変更がありませんね。Projectを作る際のInterfaceに、「Storyboard」を選ぶか「SwiftUI」を選ぶかの違いです。

f:id:tecotec_akaike:20201202230135p:plain:w200f:id:tecotec_akaike:20201202230204p:plain:w200
← Swift  SwiftUI →

そしてProjectが出来上がった後から、早速違いが出てきます。Projectのファイル構成です。

f:id:tecotec_akaike:20201202231224p:plain:h300f:id:tecotec_akaike:20201202231235p:plain:h300
← Swift  SwiftUI →

Swiftの方はおなじみの「ViewController.swift」「Main.Storyboard」が作られていますが、SwiftUIの方には「Main.Storyboard」がなく、代わりに「ContentView.swift」があります。
ではこの「ContentView.swift」を見てみると……

f:id:tecotec_akaike:20201202231701p:plain
SwiftUIのContentView.Swfitを開いたところ

あらやだすご〜い、やだぁ〜。なんていう感想がポツリとこぼれました。SwiftUIはStoryboardを使う代わりに、コードを更新すると即時でプレビューが更新されるようになりました。
これはかなり大きな進歩で、今まではLabelの中身を変えたらとりあえずビルドしなければいけなかった(純粋には違う)のですが、それがこうして簡単に表示されるようになったのは大きな進歩ですね。花丸をあげましょう。

ちなみに「ContentView.swift」にあるコードですが、これは最初から記述されているものです。こういうところも親切になってますね(苦笑

import SwiftUI

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

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

上の方でContentViewそのもの、下の方でPreviewを設定している感じですね。ちなみにこれをSwiftでやろうとすると、

import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var label: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        label.text = "Hello, world!"
    }
}

のようになるので、この時点でだいぶ違うんだな、ということが解ります。

※ちなみにですが、大抵の場合、これくらいならStoryboardで設定しますが、今回はコードで指定します

Section2 Textのカスタマイズ

では続きましては、チュートリアルに倣ってTextのカスタマイズをしてみましょう。
最終的に表示させたいのはこれ↓

f:id:tecotec_akaike:20201202233412p:plain:h300
Section2 完成図

これを実現するためには、SwiftUIの場合はこのように書きます(公式。ContentViewの方だけ)。

struct ContentView: View {
    var body: some View {
        Text("Turtle Rock")
            .font(.title)
            .foregroundColor(.green)
    }
}

個人的な感覚の話になりますが、直感的な書き方になっている気がします(他の言語にあまり詳しくない)。
ちなみにSwiftで同じようなことを書くとこんな感じになります(UILabelの設定部分だけ、フォントのサイズは適当)。

        label.text = "Turtle Rock"
        label.font = UIFont.systemFont(ofSize: 18)
        label.textColor = .green

Textの設定に同じ行数を使っていますが、SwiftUIの方は「.」で要素同士を繋いでいるのに対して、Swiftの方はプロパティに値を代入する形をとっています。
書き方だけで言えばSwiftのほうが丁寧で、SwiftUIのほうがカジュアル(?)な気もしますね。
ただ、このくらいであれば両者にほとんど差異はないようにも見えます。明確な差が出てくるのは次からですね。

Section3 StackViewを組み合わせて表示する

ここからSwfitUIの利点が如実に出てきます。とりあえずは完成形を見てみましょう。完成形はこちら↓

f:id:tecotec_akaike:20201202235259p:plain:h300
Section3 完成図

そもそもStackViewとはなんのこっちゃと思う方もいるかも知れませんが、簡単に言うとWebでいうところのテーブル表示をするための機能です。
こんな感じのやつだと思っていただければ。

TH TH
TD TD

StackViewの中に表示したいViewを置くと自動で整列してくれる便利機能で、最近の開発ではなくてはならない、かけがえのない存在です。
ではこれをSwiftUIで書いてみましょう。こんなふう書くことができます(公式)。

struct ContentView: View {
    var body: some View {
        VStack(alignment: .leading) {
            Text("Turtle Rock")
                .font(.title)
            HStack {
                Text("Joshua Tree National Park")
                    .font(.subheadline)
                Spacer()
                Text("California")
                    .font(.subheadline)
            }
        }
        .padding()
    }
}

VStackというのが縦方向、HStackというのが横方向のテーブルを作っているのですが、私は最初にこれを見たとき、SwiftUIすげえ!!! となりました。
というのもSwiftで同じことをしようとすると、コードだとおそらく20行くらい必要で(書きませんが)、基本的にはStoryboard上で設定するものなのですが、同じように設定しようとすると結構手間がかかるからです。
Storyboardで設定すると、まずはこのように各Viewを配置して、

f:id:tecotec_akaike:20201203001150p:plain
StoryboardのView配置
その上で制約(画面端から◯◯px離れている、Viewの高さは△△px等、画面を表示するために必要な情報)を細かく設定していく必要があるのですが、この制約というのがかなり面倒なもので、実装するときに頭を悩ませることが多い代物です。
なので、ほとんど制約を気にせずに簡単なコードだけでStackViewを記述できるSwiftUIがかなり便利なものであることが解りますね。

Section4 画像の円形トリミング

最後は画像を円形にトリミングして周囲に境界線を引いて、更に影をつけるというものです。Twitterのプロフィールアイコンみたいな感じです。例によって完成形はこちら

f:id:tecotec_akaike:20201203002702p:plain:h300
Section4 完成図

どこででも見るやつですね(多分)。これをSwiftUIを使って書くとこうなります(公式)

struct ContentView: View {
    var body: some View {
        Image("turtlerock")
            .clipShape(Circle())
            .overlay(
                Circle().stroke(Color.white, lineWidth: 4))
            .shadow(radius: 10)
    }
}

SwiftUIすげえ!!!(2回目)
円形のトリミングってよく使う機会があると思うんですが、Swiftで書く場合は基本的にコードから指定するしかないんですよね。だからSwiftUIで簡単にした、とも言えますが……
ではSwiftで書いてみましょう。
※imageViewというのは画像を表示させるために必要なViewです。

        imageView.clipsToBounds = true
        // 円形にする
        imageView.layer.cornerRadius = imageView.frame.height / 2
        // 境界線を引く
        imageView.layer.borderColor = UIColor.white.cgColor
        imageView.layer.borderWidth = 4
        // 影をつける
        imageView.layer.masksToBounds = false
        imageView.layer.shadowColor = UIColor.black.cgColor
        imageView.layer.shadowOffset = CGSize(width: 2, height: 2)
        imageView.layer.shadowRadius = 5
        imageView.layer.shadowOpacity = 0.3

「imageView.layer」が……多い……!
Swiftの場合はすべてをプロパティで設定するので、必然的に似たような書き方を繰り返す傾向が強くなります(他の言語はわかりませんが)。なので弊害として、一瞥しただけだとプロパティ名を見間違えることもあって、時々大変な事になったりします(経験談)。
そういったところを防げるというのも、SwiftUIの利点になるのかな、なんて思ったりしてます。

まとめ

ということで今回はSwiftUIのチュートリアルを見ながら、

  • 今までSwiftでどのように書いていたか

  • Swiftとはどう違うのか

について見てきました。Swiftという名前は冠しているものの、ほとんど別物のように見えますね。実際、勉強を始めてみるとそう感じることが多く、慣れるまでに時間がかかりそうです。
ですがきっと、マスターできれば開発に幅を持たせることができると思うので、これからも頑張って勉強してきます。
あと、今からiOSの開発を勉強したい方はSwiftUIのほうがいいと思います。書き方が簡単なので、とっつきやすいんじゃないかな、と思います。あえてObjective-Cという茨の道(需要がないわけではない)を選ぶ天邪鬼さんもいるかもしれませんが、基本的にはSwiftUIでいいと思います。

お読みいただきありがとうございました。みなさま、良きSwiftUI、Swift、Objective-Cライフを。
アデュー ノシ

 

tecotec.co.jp