見出し画像

3日間 iOSDC2022

iOSDCとは以下のような技術カンファレンスのことです。

iOSDC Japan 2022 はiOS関連技術をコアのテーマとしたソフトウェア技術者のためのカンファレンスです。今年はリアル会場とオンライン配信のハイブリッド開催を予定しています。
日本中、世界中から公募した知的好奇心を刺激するトークの他にも、パンフレットに掲載された技術記事、参加者であれば誰でも作れる即興のトーク・アンカンファレンスなど、初心者から上級者まで楽しめるコンテンツがみなさんを待っています。
9月10日(土)〜9月12日(月)はお祭りです!お楽しみに!!

https://iosdc.jp/2022/

めっちゃ楽しいお祭りでした。
参加形式はオンラインです。今年で2回目になります。
以下は視聴したカンファレンスの自分用のメモです。
※トーク者の敬称は省略させていただいております。

Day 0

ノートアプリのテキストエディタの解体新書 : 
かっくん fromkk

UIについて:UIStackViewを採用
スクロール追従について:UITextViewの高さが変わらないため変わるように実装。
ドラックアンドドロップ
iPad対応readableContentGuideを使うとiPhoneで謎のマージンが。。
テキスト操作:UITextViewDelegateでうまくやる。
画像埋め込み
ツールバー:スクロールさせたいので自作。
キーボードショートカット:UIKeyBoard Command。
パーサー:濁点・半濁点が前の文字と結合してしまう。。

unicodeScalars。で解決。
パフォーマンス:iPhoneX以降なら1万字から2万字までならいいかんじ

ありがたいサンプルコード

https://github.com/fromkk/TextEditorSample


ウーニャ、しってる。みんなふんいきでSwiftUIをつかってる。 : 
uhooi the_uhooi

Viewの分割と命名を議論したい!。
基本的には可読性の向上。
画像とテキストがある場合はLabelでスッキリさせられる場合がある。
SwiftUIでは「Style」がキー
フードトラック
単純なビューはコンピューテッドプロパティで切り出すといい
extensionでプライベートに隠蔽できる。

アトミックデザイン

決めたら明文化して規約に!。

皆さんの意見抜粋(さすがUhooiさん。。滝のようなツイートでした。)。


SwiftPMのプラグイン機能をiOSアプリ開発に活用する : 
宇佐見 公輔 usamik26

アプリ内のモジュール分割をSwift Packageを使って実現するパターン紹介。

主にビルドツールプラグイン。
(ライブラリ周り難しいです。。がSPMは好きです。)

参考:スライド


20分間で振り返るIn-App Purchaseの歴史 : 
inokinn inokinn

In-App Purchaseの激動の歴史をじっくり振り返る。

13年の歴史をもつ。StoreKitで実装。
消耗型・非消耗型・自動更新購読型・非自動更新購読型

サブスクリプション編
自動更新購読の追加:2011年に実装されたが新聞・雑誌系でないと審査に通りにくかった泣。
ユーザの定期購読の状態変化の通知の仕組みが追加:2017。それまではステータスポーリングがやばかったが工夫して少し楽になった。
購読状態取得API:2021
過去の課金履歴取得API:2021

ビジネス編:Ask to Bay:2014。子供の購入の承諾を保護者に確認する機能。ファミリー共有機能:2020。

実装編:レシートフォーマット:2013。StoreKit2:2021。

テスト編:かつてのSandbox環境。返金はおろか、手動で購読の解除も不可能だった泣。何度も使うと購読しなくなる泣。2021で改善。


SwiftUI Navigation のすべて : 
アイカワ kalupas226

Binding failable initializer

extension Binding {
    init?(unwrapping binding: Binding<Value?>) {
        guard let wrappedValue = binding.wrappedValue
        else { return nil }

        self.init(
            get: { wrappedValue },
            set: { binding.wrappedValue = $0 }
        )
    }
}

下記スライド中にも注意書きがありますが標準でもBinding failable initializerの実装はあるもののバグがあるそうです。
https://gist.github.com/stephencelis/3a232a1b718bab0ae1127ebd5fcf6f97

参考:スライド


Day 1

あなたの知らない AR の可能性を空間レベルで拡げる VPS の世界 : HEAVEN chan / ikkou ikkou

VPSは“Virtual Private Server”ではなく“Visual Positioning Service/System”
VPSとは何か
「位置」と「向き」を高精度に合わせる。
ARとの相性がいい。

City scaleのARが実現しやすい。

参考:スライド


Kotlin Multiplatform Mobile でiOSとAndroidの実装差異を無くす : 新田 陸 hal8563

導入に至った経緯
ロジック部分の品質が求められる・OS間差異

メリット
OS間差異を解決できる。
androidとswiftでコードを共通化できる。
分け方はOSのAPIの差異で考えて分ける。
共通化のしやすさで、UI・ハードウェア関連はネイティブ、ビジネスロジックはKMMで分けている。

iOSエンジニアがKMMにもつ疑問点

  • kotlinのコードはどのようにSwift上で動作するのか?

kotlin->KMM->Objective-cのフレームワークに変換される。

  • リポジトリの管理方法は?

公式サンプルではkotlin(Android)・Swift・kotlin(KMM)がひとまとまりになっている。しかし規模が大きくなってくると大変なので分けたい。
iOSではフレームワークがあればいい。そのため下記のように分ける。
KMM用リポジトリ->Framework用リポジトリ->iOSリポジトリ
Framework用のリポジトリからはCocoaPodsやSwiftPMなどで取得する。

  • iOS用APIはKMMで呼ぶのはどうしているのか?

共通のコードがある。
URL Session -> Ktor
Core Data -> SQLDelight
KeyChain -> Kissme
ないものはどうするのか
Local AuthenticationやCore MLなど(2022/09/11現在)など。
ネイティブのコードをKMMから呼び出す方法がある。

実際にやってみての課題。
ネイティブ開発メンバーはネイティブ開発に、KMM開発メンバーはKMMに注力してしまい関心が薄れてしまっていた。
解決策
定期的な相互理解を深める機会を設けた。
ネイティブメンバーからはKMMの「ビジネスロジック・インターフェースの理解」。
KMMメンバーからはネイティブの「KMM利用箇所の把握」。


CoreGraphicsでドット絵を描こう : 
noppe noppefoxwolf

 制約環境を提示することも提供価値としているアプリ。
バケツ機能について
CGContextから色を取得する必要がある。
しかし特定の座標の色を取得するAPIはない。
cgContext.dataから画像が格納されているポインタを知ることはできる。
メモリレイアウトを確認する。
lldbでcgContext.dataのアドレスを確認。

(lldb) frame var -L ctxData
0x000000016d5379e8: (UnsafeMutableRawPointer) ctxData = 0x600000c51670

XcodeのView Memoryにアドレスを入力して確認。

パフォーマンスの最適化
インデックスカラー
画像を256色のグレースケールで編集し、グレーの色それぞれにフルカラーの色を対応させたインデックスを作成、そのインデックスを元に描画することで、メモリの確保が1/4ほどで済むようになる。レトロゲームの2P カラーの仕組みでもある。
ただしCGContextにこの機能はないので、CIImageのCIFilterを使う。フィルターのシェーダはMetalで記述する。

参考:スライド

ありがたいサンプルコード

https://github.com/noppefoxwolf/PixelArtKit


Swift Concurrency時代のリアクティブプログラミングの基礎理解 : ばんじゅん🍓 banjun

2014 RPの流行り
2019 SwiftUI Combine
2021 Swift Concurrency

いわゆる非同期処理ならSwift Concurrency
データフローを扱いたい状態を複数のオブジェクト・クラスに伝播させたいならRP

確かに基礎でしたが改めてまとまって地に足つくような形で知ることができ、また自分の知らない過去でのRP関連を図で見ることができたのも良かったです。
またAPIのプロパティ名など(例えばsignalやdriverなど)で会話をしていたので今後はオペレータと呼ぶなどできそうと思いました。


正規表現って結局何なのさ?〜エンジニアのためのコンピューターサイエンス入門〜 : ta_ka_tsu ta_ka_tsu

正規表現:言語を決定する表現の一つ

どんな言語Lに対してもそれに対応する正規表現はあるか?
No

正規言語:ある正規表現で表現できる言語
DFA・NFA・GNFA:言語を決定する仕組み

受理状態にたどり着いたら「受理する」という。

正規表現の性質
反復補題:正規言語に含まれる一定以上長い文字列は必ず下記スライド164の条件を満たすようなxyzの連接で表現できる。

参考:スライド


レガシーなプロダクトからドメイン層を再設計する : 
石井 潤、高橋 陽太郎

提供したい価値を見直すとアプリ内のドメイン設計が価値を提供できる体制になっていない場合がある。

情報とデータは違う。

参考:スライド


SwiftUIとUIKitを仲良くさせる : 
Apurin Mikhail auramagi

UIHostingControllerでの状態の持ち方
・UIViewControllerとViewで共通のObservableObjectを通して管理する。
・CombineのPublisherを渡して購読する。
・プロパティ・アクションを@Environmentに入れる。
・共通モデルを@EnvironmentObjectで設定する。(<-本記事を書いている私事にはなりますが現(2022/09/12)チームではこちらを採用中です。)

UIHostingControllerでのレイアウト
SwiftUIではmin 最低値・ideal 理想・max 最高値が設定でき「min <= ideal <= max」の関係で成り立っている。
initrinsicContentSizeが呼ばれることでideal(理想値)が適用される。
デフォルトでinitrinsicContentSizeが呼ばれないので呼んであげる必要がある。

UIHostingConfiguration
StateとStateObjectは要注意。

Swift Concurrency Next Step : 
shiz stzn3

おさらい

Structured concurrency
・async/awaitを使って複数の処理を同時並列に実行する。
・キャンセルを連動させることもできる。
実装:async let 構文・Task Group 構造体

Unstructured concurrency
・構造化されていないタスクを生成することもできる。

Actor
データ競合を防ぐ。

最近のアップデート
・non-isolated async関数のエグゼキュータの明確化
・Clock, InstantProtocol, DurationProtocol
・Strict Concurrency Checking

よく起こる問題
・MainActorブロッキング
・Actor競合
・協調スレッドプールの枯渇
・Continuationの誤用

Swiftランタイム設計思想

協調スレッドプールのデバッグ:ビルドフェーズのRunのEnvironment Variablesから「LIBDISPATCH_COOPERRATIVE_POOL_STRICT=1」で協調スレッドプールのサイズを1に制限する。

CheckedContinuationを使う。

リエントラントを許可する実装することで重複リクエストを防ぐなどに使える。

参考:スライド


アニメーションAPIのすべて : 
岸川克己 k_katsumi

基礎からCoreAnimationの奥深くまでサンプルコードと動くアニメーションで学べます!。今すぐダウンロード!笑。

https://github.com/kishikawakatsumi/UltimateGuideToAnimations


Day 2

Xcode が遅い! とにかく遅い!! 遅い Xcode をなんとかする方法 : Yoshimasa Niwa niw

大量のインデックス作成でXCBBuildServiceが900%に達して他のことができなくなる問題
何が原因か?XCBBuildServiceがSwiftPM関連のバグを踏み止まる。Xocdeはそうとも知らずリクエストを送り続けてしまう。
回避策
Xcodeのインデックス作成時にXCBBuildServiceに送ろうとするプロセス間崇信を妨害する。
XCBBUILDSERVICE_PATH環境変数を使う。
XCBBuildServiceProxyKitのHybridXCBBuildService:XCBBuildService間のプロトコルのエンコード・デコードをしてくれる。
自前のXCBBuildServiceを作りHybridXCBBuildServiceでリクエストを奪う。
複数のターゲットのインデックスを検出しCreateBuildRequestが来たら阻止する。
それ以外はオリジナルのXCBBuildServiceに横流しをする。
動かすときは自前のXCBBuildServiceをXCBBUILDSERVICE_PATHに登録してからXcodeを起動する。
そしてなんとXcode14 Beta2で治っています!

llvmロック問題
clangのモジュールロック
ロック機構に問題あり
パケット衝突検出に似た仕組み
デフォルトで1分30秒
回避策
1 ロックを使わないようにする。
BuildingImplicitModuleUsesLockのOTHER_CFLAGSに-Xclang -fno-implicit-modules-use-lockを設定。
ただし複数のclangが同じモジュールを作る可能性が増えるので効果があるかは状況次第。全てのコアが綺麗に使われるようになるので「気分は良い」。
2 ツールチェインを置き換える。
llvm::LockFileManagerやclangの挙動を変える。
~/Library/Developer/Toolchainsに配置する。
Xcodeのメニューから切り替えられる。
ただしツールチェインのビルドはかなり大変。
clangだけならCC環境変数で置き換えるということもできる。

が本来ならXcodeが治ってほしい。。

外部ビルドツールを使うという手も。Bezel


20分でわかる!速習resultBuilder : 
たまねぎ _chocoyama

複数要素の組み合わせを宣言的に行えるようにする。
内部DSLに近い。
ViewBuilder・RegexComponentBuilderで使われている。
要素を取集し、最終的な結果として出力。
メリット
・カンマなし・制御構文が使える。
・特徴可読性・保守性を高められる。

カスタムでresultBuilderを作成できる。
例:NSMutableAttributedString

注意点
・DSL利用者に学習を求めることになる。
・無闇な導入は過度な抽象化によりコストが高くなることも。。
・DSLの利点を理解し検討することが必要。

参考:スライド


シーンに応じた使いやすいQRコード読み取り機能を実装しよう : jollyjoester jollyjoester

iOSではiOS7.0から対応が始まった。
AVFoundationを詳しくみていく。
セッションはキューを使う。メインでやるとUIをブロックしてしまうため。
builtInWideAngleCamera 最も汎用的なカメラデバイスを指す。
QRをメタデータとして扱うためにAVCaptureMetadataOutputを用意しキューを作成。
キューの登録。
注意点metadataOutputはかなり連続で呼ばれる。
AVCaptureVideoPreviewLayerを使い表示する。これはUIなのでメインスレッド。
Zoom機能 videoDeviceInput.deviceにアクセスするので排他アクセスをとるのが重要。
Torch機能 Zoomとほぼ同じ。
枠を作りたい。rectOfInterestを使う。座標系に気をつける。
読み取り後などの音や振動も重要。

参考:記事


LINE iOSのビルド環境の変遷 : Giuk Jung

Bazelの利点
正確性による高速化
スケーラビリティ
多言語に拡張可能

注意点
Bezelはappleによって更新はされない。
つまり遅れることがある。M1対応はappleの発表から1年後。

Bezelに多くのパッチを当てた。

ビルドしかしない。Xcodeへのインテグレーション作業は必須。定義にジャンプ・ブレークポイントなどが動かないことも。これはIndexingを自前でやるしかないことを示す。

Bezelの学習コストが高い。。

ライブラリ管理が大変。バージョン予測がしにくい。依存関係は手でやるしかない。XcodeGenと依存関係構成が一致しない。

キャッシュの管理が大変。

ただし圧倒的にビルドが速い。
しかしそれだけでデメリットを抱えていいのか?

ビルドの速さを実現する方法
・キャッシング:ディスクキャッシュ・分散キャッシュ
・インクリメンタル:変更したものだけをリビルドする。

CIとLocalの比較
CI:ほぼクリーンビルドでキャシングがメイン。
Local:ほぼリビルドでインクリメンタルがメイン。

Bezelキャシングの出来が圧倒的。
一方Xcodeは M1 Max によってインクリメンタルの速度が圧倒的。

さすがLINEさん全員のMacをM1 Maxに。

全てが解決。


Effective PencilKit / 新聞スクラップ体験の実現 : 
shimastripe shimastriper

Apple Pencilで書き込みを行いたい。

表示非表示の切り替えも可能。リモートで共有もされている。

PencilKit iPadだけでなくiPhoneでも指で書き込める。
メリット
簡単に導入できる・低レイテンシ・imageで出力可能。

Drawing with PencilKitを参考にするといい。

PencilKitでは画像への書き込みAPIがないので拡張する。
2枚のScrollViewの同期は難しい。
PKCanvasView内のcontentにimageをaddして解決!。

プレビュー・エディットモード
❌isUserInteractionEnabled = false
✅drawingGestureRecognizer.isEnabled

独自ペンツールを入れたい。
ジェスチャーを切り替えることで実現。

ビジュアルリグレッションテスト


iOS15からのCommunication NotificationとSiri : 
まつじ mtj_j

Siriに「人」を教えてあげる必要がある。
INPerson「人」personHandleが重要。
donate Siriに情報を提供すること
INSendMessageIntent メッセージの送信を示す。

Group Communication Notification
recipients, 2つ以上が必須。


AirPlayの裏舞台 : なめき ちはる Ridwy

Appleのデバイスから同一ネットワーク内にある他の機器で音楽・写真・動画を再生する機能。
ミラーリングして外部ディスプレイ・スピーカーとしての利用も可能。

表舞台
AirPlayを複数行うと音がずれずに再生できる。
(動画は1対1)

歴史
2002 Rendezvous
2004 AirMac Express
2005 Bonjour
2017 AirPlay2 マルチルーム再生機能

デバイスの検出の裏側
Bonjour
複雑な設定なしにローカルネットワーク内でサービスを提供するインスタンス
_airplay._tcp, _ropa._tcp
Multicast DNS (mDNS)のレコードを活用。

利用シナリオ毎の裏側(公式ドキュメントなし!!)
写真:HTTPみたいな感じでPUT送信
曲:RTSPで送信、DASPで受信
動画:POSTでURLを送信、送信状態を受信
ミラーリング:パケットで送信

選択画面の調整
AVRoutePickerVIew
アプリを閉じても再生:plist


音声プラットフォーム「Voicy」のiOS開発について : 
立花和也 kzytcbn315

問題
見積もりが難しい。テスト範囲が広い。

原因
・アウトカムではなくアウトプット重視してしまっていた。
・外部品質の寄与ができてなかった。
・情報が集約してしまう。

Feature チーム:ユーザに向き合うアウトプット重視のチーム。
task Force チーム:外部品質を高める。
Crossing チーム:アウトカムを高めるチーム。
さらにエンジニアを機能毎に配備。



終わりに

iOSDCスタッフの方々そして登壇者の方々・参加者の方々お疲れ様でした!!🎉🎉🎉🎉。
今年もめちゃくちゃ最高でした!。来年はオフラインで参加したいです。
そのためにも新作のアプリをリリースしようと思います。

iOSDCで得たつながりや知見を活かしてどんな難題でも解決できそうな気持ちです。

繰り返しにはなりますが、iOSDCスタッフの方々そして登壇者の方々・参加者の方々本当にお疲れ様でした!。来年も参加します。


この記事が気に入ったらサポートをしてみませんか?