Yappli Tech Blog

株式会社ヤプリの開発メンバーによるブログです。最新の技術情報からチーム・働き方に関するテーマまで、日々の熱い想いを持って発信していきます。

try! Swift Tokyo 2025も最高だった件✨

はじめに

こんにちは!🌸
ヤプリでiOSエンジニアをしています、白数 (@cychow_app) です!

今年も4/9 (水) ~ 4/11 (金) の期間で try! Swift Tokyo 2025 が開催され、3日間参加してきました。
try! Swift Tokyoへの参加は今回が2回目となり、昨年のtry! Swift Tokyo 2024は渋谷で開催されていたのですが、今年は会場が立川に移動し、会場の規模も大きくなっていました!

会場がデカい.....!?

今年のtry! Swift Tokyo 2025でも、世界で活躍されている著名な方々が登壇されており、すべてのセッションが非常に興味深いものとなっていました✨
本記事ではtry! Swift Tokyo 2025の中からいくつかのセッションをピックアップし、実際のコードを交えながらご紹介できればと思います!

セッションのご紹介

① iOS 17, 16, 15などの新機能(Speaker:Vincent Pradeillesさん)

www.youtube.com

まずは初めにVincent Pradeillesさんのセッションです!
Vincentさんは普段、X(@v_pradeilles)などのSNSやYoutubeなどでiOS関連の技術について発信されている方で、私自身もVincentさんのYoutubeチャンネルをフォローし、普段から勉強させていただいていました。
(今回は動画ではなく、目の前で実際にお話しされていたので、個人的にすごくテンションが上がっていました…!🔥)

Vincentさんが目の前に…!

セッション内で紹介された便利なAPI

Vincentさんのセッションでは、iOS15、16、17それぞれで登場したAPIをいくつか取り上げ、その便利な利用方法についてご紹介されていました。


【セッション内でご紹介されたAPI】

  • iOS 15+
    • .formatted()
    • .privacySensitive()
    • Toggleコンポーネントの .toggle(.button)
  • iOS 16+
    • UIHostingConfiguration.swipeActions
    • TextField(,text:,axis: .vertical)
    • .fill(color.gradient)
  • iOS 17+
    • ContentUnavailableView.search
    • SubscriptionStoreView
    • .scrollTargetBehavior()
    • .containerRelativeFrame(), .visualEffect()
    • .contentTransition(.numericText())

上記の中でもiOS 15以降から利用可能となった .privacySensitive() や、iOS 17以降で利用可能となった .contentTransition(.numericText()) は全く知らなかったので、勉強になりました。
セッション内で紹介されていたそれぞれのAPIが具体的にどのように動作するのかは以下のリポジトリにて、私が遊んでみたソースコードを公開しておりますので、ぜひみなさんも遊んでみてください!!

github.com

② SwiftUI Textを使った特殊効果(Speaker:Paul Hudsonさん)

www.youtube.com

続いて、Paul Hudsonさんのセッションです。
Paulさんもまた、Appleプラットフォーム向けアプリ開発を学ぶことができる非常に人気のある学習サービス「Hacking with Swift」を運営されていたり、YoutubeやX(@twostraws)などいったSNSでも情報発信をされていたりします。
(私もHacking with Swiftの記事にはよくお世話になっています🙏)

昨年に引き続き今年も!!

Paulさんのセッションでは、1990年代に流行したMicrosoftの「WORDART(ワードアート)」と呼ばれる、文章をおしゃれ(?)にデザインする機能をTextRenderやMetalなどを駆使し、再現していくというものでした。

Lines、Runs、Glyphsについて

テキストはLines、Runs、Glyphsに区切ることができ、以下のような特徴があるようです。

赤線がLines (行)、緑線がRuns(ラン)、青戦がGlyphs(字形)

  • Lines
    • 画面サイズに合わせて必要の応じて行数が増えたり減ったりする。
    • テキストの「一行」。文章の中で改行や折り返しで区切られた単位。
  • Runs
    • 行の中にある同じ書式の単一のテキストチャンクのこと。
    • 「important」という単語は太字の斜体スタイルがつけられているため、独自のランとなる。
    • 日本語では「ラン/文字ラン/属性付きテキスト」と言われたりする。
    • 同じ属性(フォント、スタイル、色など)を持つ連続した文字列。日本語訳が難しいので「ラン」とカタカナで使うこともある。
  • Glyph
    • 一つ一つの文字がグリフと呼ばれる。
    • 日本語では「グリフ/字形(じけい)」と呼ばれたりする。
    • 実際に描画される「文字の形」。1文字が1つのグリフとは限らず、合字(ligature)や複合文字もある。

TextRenderer を用いたアニメーションの実装

Lines、Runs、Glyphsに対して独自の効果を与えたい場合、 TextRenderer プロトコルに準拠したRendererオブジェクトを用意し、カスタムしたいTextに対して .textRenderer() モディファイアを付与することで反映できるようです。

import SwiftUI

/// TextRenderer側
struct JumpAroundRenderer: TextRenderer {
    var moveAmount: Double
    var animatableData: Double {
        get { moveAmount }
        set { moveAmount = newValue }
    }
    /// 飛び跳ねるようなテキストアニメーションを描画する。
    ///
    /// - Parameters:
    ///   - layout: レンダリングするテキストレイアウト
    ///   - ctx: テキストの描画するためのグラフィックスコンテキスト
    func draw(
        layout: Text.Layout,
        in ctx: inout GraphicsContext
    ) {
        for line in layout {
            for run in line {
                for glyph in run {
                    let yOffset = Double.random(
                        in: -moveAmount...moveAmount
                    )
                    // コンテキストをコピーして、Y軸方向にオフセットを適用する。
                    // これにより、元のコンテキストは変更されず、オフセットされたコピーが描画される。
                    var copy = ctx
                    copy.addFilter(
                        .blur(radius: moveAmount / 4)
                    )
                    copy.translateBy(x: 0, y: yOffset)
                    copy.draw(glyph)
                }
            }
        }
    }
}

/// View側
struct JumpAroundRendererView: View {
    @State private var moveAmount = 0.0
    var body: some View {
        Text("***Yappli***\nmobile tech for all")
            .font(.system(size: 96))
            .lineSpacing(50)
            .multilineTextAlignment(.center)
            // 定義したTextRendererを設定
            .textRenderer(
                JumpAroundRenderer(
                    moveAmount: moveAmount
                )
            )
            .onAppear {
                withAnimation(.easeInOut(duration: 1).repeatForever(autoreverses: true)) {
                    moveAmount = 10
                }
            }
    }
}

手元でも確認してみましたっ!

Metalによるより複雑なアニメーション

また、TextRendererの他に、低レベルのGPU向けグラフィックス & 計算処理用フレームワークであるMetalを駆使することで、より複雑なアニメーション効果をテキストに与えることができるようです。Metalを利用するためには、Swiftだけでなく、Metal Shading Languageという言語を使用する必要があります。
セッション内ではテキストに対して、水のエフェクト、グレースケールグラデーションのエフェクト、虹色グラデーションのエフェクトなどを追加されていました。

このセッションを通して、私自身もMetalに対して非常に興味を持ち、Paulさんが作成されたInfernoというMetal学習用リポジトリをやってみようと思っています。
より詳しくソースコードを見てみたいという方は以下のPaulさんのリポジトリをご参照ください!

github.com

③ 素早く実現する優れたアプリデザイン(Speaker:Sebastiaan de Withさん)

www.youtube.com

続いて、Sebastiaan de Withさん(@sdw)のセッションです。こちらのセッションは3日間、数多くのセッションがありましたが、その中でも非常に印象に残ったセッションの一つです。
Sebastiaanさんは、Appleにてデザイナーとして「Find my Friends(友達を探す)」アプリの設計段階から携わり、現在はLuxでHalide、Kino、Spectreといったカメラアプリの開発に携わられています。

セッション内では未来からの電話も....!?

セッション内では、Apple時代のご経験や現在のHalideアプリの開発を行う上で感じたSebastiaanさんの教訓を中心に紹介されていました。

セッション内で紹介された教訓

  1. Embrace trying new things - ever starting over(新しいことに挑戦することを受け入れる - やり直すこともある)

  2. Care about things(すべてに気を配る)

  3. Inspiration is everything(インスピレーションがすべて)

  4. Fun is the driving force(楽しさこそが原動力)

  5. The best things take time: build a habit of craft(最高のものは時間がかかります。工夫する習慣を身につけましょう。)

Sebastiaanさんのセッションには、「ものづくり」に携わる上で大切なこと、これからどういったことを意識していくといいのかなど、今後もアプリの開発者として生きていく上での教訓がたくさん詰まっていると感じました。
(つらつらと感想を書いて言語化していますが、アーカイブ動画を見ていただくのが一番です…!)

「ものづくり」に携わられている方はぜひ一度Sebastiaanさんのセッションを見ていただきたいです!

④ 作って学ぶ正規表現 -やさしいSwift Regex入門- (Speaker:kishikawa katsumiさん)

www.youtube.com

最後にご紹介するのは、弊社でもご活躍されている岸川さん(@k_katsumi)のセッションです!!
今年はSwift5.7から利用可能となったSwift Regexに焦点を当て、Regexがどういう原理で動作しているのか、また自作で正規表現エンジンを作る場合どういった実装を行うのか、効果的なRegexに書き方などについて発表されていました。
(私自身も正規表現自体は少し苦手ですごく勉強になりました….!)

Swift Regexについて....!

今回のセッションを通して、Swift Regexについてたくさんインプットできましたので、その一部をご紹介できればと思います!

Regexにおける基本的な3つの操作

Swift標準の Regex では幅広く機能を展開していますが、以下の3つの基本的な操作(連結、選択、繰り返し)をサポートすることで、基本的なすべての正規表現を表すことができます。

  • 連結 (Concatenation)
    • 例: /try//t/ + /r/ + /y/
    • 文字列 try にマッチする。
  • 選択 (Alternation)
    • 例: /gray|grey/
    • 文字列 gray または grey にマッチする。
  • 繰り返し (Repetition)
    • 例: /(0|1*)/
    • 文字列 110001001... にマッチする。

また、シンタックスシュガーとも言えるような機能もあったりします。

  • Plus (+)
    • 一つ以上の繰り返しを意味する。
    • 例: /a+/ = /aa*/
  • Question Mark (?)
    • 空文字または括弧で囲まれた文字を意味する。
    • 例: /a?/ = /(|a)/
  • Character Classes
    • 指定した値の間で一致する文字を意味する。
    • 例: /[0-9]/ = /(0|1|2|3|4|5|6|7|8|9)/

Regexエンジンの構造と各フェーズ

Swift Regexエンジンのアーキテクチャ図

上記がSwift Regexエンジンが処理を実行する上での構造となります。
段階としては、Parse、Compile、Matchの3段階があるようです。

① Parseフェーズ:構文解析
正規表現の文字列を再帰的降順パーサーによって解析し、構文ツリー(Syntax Tree)に変換します。
各構文要素は Nodeというenumで定義されており、例えば alternation, concatenation, group, atom などが定義されています。

public indirect enum Node {
    case alternation(Alternation)
    case concatenation(Concatenation)
    case group(Group)
    case quantification(Quantification)
    case atom(Atom)
    case empty(Empty)
}

② Compileフェーズ:バイトコード生成
構文ツリーを元に、実行可能な命令列(バイトコード)へと変換します。
この際、必要最小限の命令セット(例:branch, save, splitSaving, match)を用いることで、簡潔ながら表現力のある処理が可能のようです。
各命令は Instruction というenumで定義され、Swiftコード上でもバイトコードの構築過程が明示的に記述されています。

extension Instruction {
    enum OpCode: UInt64 {
        ...
        case branch
        case match
        case save
        case splitSaving
        ...
    }
}

③ Matchフェーズ:仮想マシンによるマッチング実行
マッチ処理は仮想マシンが実行し、入力文字列と命令列を順に処理してマッチング判定を行っていきます。
処理途中でマッチが失敗した場合に備えて、セーブポイント(savePoint)を用意し、プログラム状態を復元できるようにもしているようです。
以下のような Proccesor 構造体の情報をもとにMatch処理が実行されています。

struct Proccesor {
    /// 入力変数:一致処理される文字列
    let input: String
    /// 命令変数:バイトコードの配列
    let instructions: [Instruction]
    
    /// 現在位置:一致処理される文字列のインデックス
    var currentPosition: String.Index
    /// プログラムカウンタ:実行されるバイトコードのインデックスのプログラムカウンタ
    var pc: Int

    /// セーブポイント:特定の時点でプログラム状態を保存し、その時点からプログラムを再開する
    var savePoint: [SavePoint] = []
}

このように、Regexは「最小構成の演算 × 明示的なエンジン処理」によって、シンプルかつパワフルな正規表現を実現しています。

さいごに

今回ご紹介したセッションの他にも多くの方が登壇されており、今年のtry! Swift Tokyo 2025も知的好奇心をすごくくすぐられました!
Youtubeでもアーカイブ動画が上がっておりますので、ぜひご覧になってみてください!
(私もこれからアーカイブ動画でどんどん復習していきます....💦)

www.youtube.com

最後にですが、try! Swift Tokyo 2025を企画、運営された皆様、本当にありがとうございました!!
来年のtry! Swift Tokyo 2026も今年に続き参加しようと思います✨