Citrus-Field TECH BLOG.

フリーランスのITエンジニア、iOSアプリの個人開発、業務委託(小売、ヘルスケア)を行っています。お仕事については、メールもしくはXのDMでご相談ください

テスト駆動開発

テスト駆動では次のプロセスを何度も回します。

  1. 目標を考える
  2. 目標を示すテストを書く
  3. 実行して失敗させる(REDの状態)
  4. 目的のコードを書く(コードの汚さは関係なし)
  5. テストを成功させる(GREENの状態)
  6. テストが通るまでリファクタリングを行う

テストに時間がかかるのは、コードが読みにくい(汚い)とか、 最初からロジックの最適化を考えてしまうことが時間を消耗しているように思います。

ただ、テストコードが揃っていれば、ロジックの目的、理解ができるため、 後から修正する場合が、圧倒的に楽になります。

不具合があっても、意図して書かれたコードか、単純な間違いなのか、 とりあえず場当たり的に書いたものなのか、 なにもわからない事態に陥ることにもなりかねません。

テスト駆動開発は、完璧主義ではありません。 ひとまず、最低限の品質を担保し、後に後任者に、 より高品質、高機能なプロダクトを委ねる手段と思っています。

【模索中】効率的な開発に向けたクリーンアーキテクチャの適用方法

もし、今現在、Swift用のクリーンアーキテクチャテンプレートを作るとしたらどんな感じになるだろうか

参考リンク一覧

最も影響を受けたもの。

github.com

clean-swift.com

medium.com

qiita.com

さっくりとした各コンポーネントの役割

Presentation Layer

ViewControllerとPresenter、Interactorについては以下のように一方向のつながりにするよう制約します。

ViewControllerは、Viewが検知したタップイベントなどをうけて、Interactorにそのイベントに対応するビジネスロジックを実行するよう依頼します。 InteractorはUseCaseを呼び出しビジネスロジックを実行してPresenterにその結果を通知します。 PresenterはInteractorからの結果通知をうけてViewControllerに表示内容を指示します。 ViewControllerはPresenterからの指示に従いViewの更新を行ったり、Routerを介して画面遷移を行ったりします。

以下のコンポーネント間はプロトコルでI/Fを定義しそれぞれI/Fに依存した実装をします。

ViewController -> Interactor Interactor -> Presenter Presenter -> ViewController

また、それぞれのコンポーネント間のメッセージは、以下のModel(struct)を定義してやりとりします。

Modelまわりの説明

  1. RequestViewController -> InteractorViewのイベントを通知する
  2. ResponseInteractor -> PresenterInteractorで処理した結果を通知する
  3. ViewModelPresenter -> ViewController表示する内容を指示する
struct ThreadList {
   struct Filter {
       struct Request {
           var star: Bool
       }
       struct Response {
           var star: Bool
       }
       struct ViewModel {
           var filterLabel: String
       }
   }
}

Domain Layer

UseCaseはInteractorから依頼されたビジネスロジックを実行します。 必要に応じてUseCaseからはRepositoryを介してDataStoreへアクセスしDBアクセスやAPI通信行います。 ここでもそれぞれプロトコルでI/Fを定義して、そのプロトコルに依存した実装にします。

また、UseCaseはDBアクセスなどの結果取得したEntityを、TranslatorにてPresentation Layerで利用できるModelに変換してから渡すようにします。

Data Layer

実際にDBにアクセスしたりAPI通信をしたりするDataStoreを置きます。 ここでもプロトコルでI/Fを定義して、そのプロトコルに依存した実装にします。 RepositoryからはそのI/FでDataStoreを呼びます。

ここまでの印象

一つのviewアクションの追加に、修正量が多すぎないか

ViewControllerでViewイベントを受け取ったらViewModelにイベント通知して(API通信などを行った上で)その結果をうけてViewControllerが画面を更新する流れに比べると、だいぶ細分化される。

個人開発など、プロジェクトの大部分の開発がかのうなら、開発コストやオーバーヘッドも大事。

そして、再考。

必要以上に複雑化しないよう注意する。

1. レイヤードアーキテクチャを簡素化

クリーンアーキテクチャの基本概念を取り入れるには、以下のように簡素なレイヤー分割を導入する

  • View (UI層): ViewControllerSwiftUIView
  • ViewModel (プレゼンテーション層): ビジネスロジックとUI更新を分離。
  • UseCase/Interactor (ユースケース層): ビジネスロジックを記述。
  • Repository (データアクセス層): データソースの抽象化(API通信やデータベース操作など)。

例:

protocol UserRepository {
    func fetchUserData(completion: @escaping (Result<User, Error>) -> Void)
}

class DefaultUserRepository: UserRepository {
    func fetchUserData(completion: @escaping (Result<User, Error>) -> Void) {
        // API通信の実装
    }
}

class FetchUserUseCase {
    private let userRepository: UserRepository

    init(userRepository: UserRepository) {
        self.userRepository = userRepository
    }

    func execute(completion: @escaping (Result<User, Error>) -> Void) {
        userRepository.fetchUserData(completion: completion)
    }
}

class UserViewModel: ObservableObject {
    @Published var user: User?
    private let fetchUserUseCase: FetchUserUseCase

    init(fetchUserUseCase: FetchUserUseCase) {
        self.fetchUserUseCase = fetchUserUseCase
    }

    func loadUserData() {
        fetchUserUseCase.execute { [weak self] result in
            switch result {
            case .success(let user):
                self?.user = user
            case .failure(let error):
                print("Error: \(error)")
            }
        }
    }
}

2. 依存性逆転の原則 (Dependency Inversion Principle)

  • 上記例のように、リポジトリ層を protocol で抽象化し、具体的な実装(例えばAPI通信)は外部で注入する形にする。
  • これによりテスト可能性が向上し、モックやスタブを利用してユニットテストが簡単になります。

3. DI (Dependency Injection) を活用

  • ViewControllerViewModel への依存をコンストラクタで注入する。
  • 小規模プロジェクトの場合、手動でDIを行い、サードパーティのDIフレームワークは必要ないことが多いです。

例:

let userRepository = DefaultUserRepository()
let fetchUserUseCase = FetchUserUseCase(userRepository: userRepository)
let viewModel = UserViewModel(fetchUserUseCase: fetchUserUseCase)

4. 非同期処理のシンプル化

  • Combine(もう辞めたい) や Swift Concurrency (async/await) を活用することで、非同期処理のコードがよりシンプルに。

例 (async/await を使用):

class DefaultUserRepository: UserRepository {
    func fetchUserData() async throws -> User {
        // API通信の実装
    }
}

class FetchUserUseCase {
    private let userRepository: UserRepository

    init(userRepository: UserRepository) {
        self.userRepository = userRepository
    }

    func execute() async throws -> User {
        return try await userRepository.fetchUserData()
    }
}

class UserViewModel: ObservableObject {
    @Published var user: User?

    private let fetchUserUseCase: FetchUserUseCase

    init(fetchUserUseCase: FetchUserUseCase) {
        self.fetchUserUseCase = fetchUserUseCase
    }

    func loadUserData() async {
        do {
            user = try await fetchUserUseCase.execute()
        } catch {
            print("Error: \(error)")
        }
    }
}

5. 工数を抑えるポイント

  • 単純化: 各レイヤーでやるべきことを最小限にする。
  • 抽象化しすぎない: すべてのクラスや関数を抽象化するのではなく、明確に必要な部分だけを抽象化する。

小規模プロジェクトでは、「完全なクリーンアーキテクチャを実装しなければならない」と考えず、必要に応じて適用する。

あれ?iOS18で仕様変化されている!と驚いたので変更点を書き出してみた。

なんだか、iOS18、iPad OS18のジェスチャー周りでハマったので、変更点を書き出してみた。

developer.apple.com

概要

iOS & iPadOS 18 SDK は、iOS & iPadOS 18 を実行する iPhone および iPad 向けのアプリの開発をサポートします。SDK は Xcode 16 にバンドルされており、Mac App Store から入手できます。Xcode 16 の互換性要件の詳細については、Xcode 16 リリース ノートを参照してください。

アクセシビリティ

解決された問題

  • 修正: 新しく追加された背景サウンド (火と夜) を再生できない場合があります。(128898875)

  • 修正: M4 搭載の iPad Pro モデルでは、サウンド認識とサウンド アクションが機能しない場合があります。(128949527)

  • 修正: アクセシビリティ設定で初めて入力した後、設定を再起動するまで、ミュージック ハプティクスが消える場合があります。(128960448)

アクセサリセットアップキット

解決された問題

  • 修正: ユーザーがアクセサリの表示名または SSID を変更できない場合があります。(128958722)

アクティビティの共有

解決された問題

  • 修正: 友人が完了したワークアウトの通知に誤ったテキストが表示される場合があります。(128939058)

広告属性キット

新機能

  • AdAttributionKit は、すでにインストールされているアプリのクリックスルー アトリビューションである再エンゲージメントの測定をサポートするようになりました。再エンゲージメントは、ユニバーサル リンクを使用したアプリ内のコンテンツへのディープ リンクもサポートします。(111224069)

解決された問題

  • 開発者モードを長時間有効にした後に開発ポストバックが送信されない問題を修正しました。(130100361)

アプリの意図

解決された問題

  • 修正: EntityURLRepresentation では、検証なしで任意のカスタム URL が許可されます。(119524801)

  • 修正: タイトルや説明を含む AppIntent の静的プロパティは同時実行安全ではありません。(128090148)

  • 修正: パラメータなし@Parameterおよび@Propertyラッパーによりプロトコル準拠エラーが発生する場合があります。(130219933)

既知の問題

  • @UnionValue型は現在、インテントの結果としてのみ機能します。 をインテント パラメータまたはエンティティ プロパティの型として使用しようとすると、コンパイルに失敗します。(128069844)@UnionValue

アプリストア

新機能

アップルキャッシュ

既知の問題

  • Tap to Cash を使用すると、2 台の iPhone をかざすだけで Apple Cash を送受信できます。支払いの送受信には Apple Cash アカウントが必要です。受信者が 7 日以内に Apple Cash アカウントを設定または個人情報を確認しない場合は、支払いは送信者に返金されます。開発者ベータ版では、Tap to Cash の支払いは 1 回の取引につき 250 ドルを超えることはできません。取引の制限は、開発者ベータ版またはパブリック ベータ版の期間中、いつでも予告なく変更される可能性があり、制限の引き下げも含まれる場合があります。(128977390)

補助アクセス

解決された問題

  • 修正: メッセージ アプリが Assistive Access でハングする場合があります。(127601737)

  • 修正: ユーザーが Assistive Access に写真やカメラ アプリを追加できない場合があり、Assistive Access 設定を開くと既存のユーザーの設定からアプリが削除される場合があります。(128905924)

オーディオ

解決された問題

  • 修正: 一部の Bluetooth ヘッドフォンは、特定の AVAudioSession 構成ではオーディオ出力ルートとして使用できない場合があります。(126693883)

電卓

解決された問題

  • 修正: 編集ボタンで履歴項目を削除すると、リストの一番上の項目が視覚的に削除されます。バックアップ データは正しいままです。(126768783)

カメラ

解決された問題

  • 修正: カメラの背景を置き換える場合、写真ピッカーを使用して写真ライブラリから背景画像を追加するには、ダブルクリックする必要がある場合があります。(122358378)

  • 修正: 起動後の最初のポートレート キャプチャが完了するまでに予想よりも時間がかかる場合があります。(128881179)

  • 修正: iPhone/iPad を起動した後、カメラ機能が動作するのに最大 2 分かかる場合があります。(128899310)

  • 修正: iPad のカメラ アプリからドキュメント スキャン機能を使用すると、カメラからのライブ プレビューではなく、黒い画面が表示される場合があります。(128907349)

  • 修正: ステージ ライト、ステージ ライト モノ、ハイキー ライト モノのライト フィルターを使用しているときに、背面カメラでポートレート モードのプレビューをオブジェクトに向けると、アーティファクトが表示される場合があります。アーティファクトはキャプチャされたアセットには影響しません。(129024197)

カープレイ

解決された問題

  • 修正: BMW ユーザーの場合、Bluetooth ペアリング UI が応答しなくなり、連絡先の転送が失敗する可能性があります。(129043855)

CFネットワーク

解決された問題

  • 修正:は常に +1 保持された CF 型オブジェクトを返していましたが、関数宣言はiOS 18、macOS 15、tvOS 18、visionOS 2 までは属性で装飾されていませんでした。CFNetworkExecuteProxyAutoConfigurationScript``CFNetworkExecuteProxyAutoConfigurationURL``CF_RETURNS_RETAINED

    C ベースの言語の場合、clang 静的アナライザーは、オブジェクトがリークされているかどうかを検出することがあります。ソース コードの変更は必要ありませんが、リークを修正することをお勧めします。

    Swift の場合、これらの関数の戻り値の型が からUnmanaged<>実際に返される CF 型に変更されるため、新しい SDK でコンパイルするときにはソースを変更して修正する必要があります。ただし、古い SDK でコンパイルされた Swift プログラムは新しい OS でも引き続き動作しますが、返される CF 型オブジェクトは、この変更前と同様にリークし続けます。(126154509)

コンテナ化

解決された問題

  • 修正: Xcode 15 から 15.3 で作成された重複コンテナの処理が改善されました。これらのバージョンの Xcode では、デバイス上に重複コンテナが作成されることがあります。この変更により、アプリが一貫したコンテナで起動し、アプリを削除すると重複コンテナも削除されます。(123480553)

コントロールセンター

解決された問題

  • 修正: コントロール センター ページ コントロールが、横向きのダイナミック アイランドに重なって表示されます。(125913281)

  • 修正: 編集モードを終了した後も、コントロール センターの空のページが残る場合があります。(126760824)

  • 修正: パラメーター化された OpenIntent アクションを持つコントロール ウィジェットが構成できません。(128241927)

  • 修正: アップデート前にコントロール センターの一部であったボイスメモ コントロールは、iOS 18 にアップグレードすると正しくレンダリングされなかったり、機能しなくなったりします。(129184182)

既知の問題

  • コントロール センター ギャラリーのアプリ アイコンは常にダーク モードで表示されます。(126721275)

コアML

解決された問題

  • 修正: Core ML モデル デプロイメント API が利用できません (および)。代わりに、バックグラウンド アセットまたはの使用を検討してください。(122955353)MLModelCollection``MLModelCollectionEntry``NSURLSession

コアメディア

解決された問題

  • 修正: 統合タイムライン上で再開オフセットがゼロ以外のインタースティシャル イベントをシークすると、イベントがキャンセルされる可能性があります。(129175283)

画面

解決された問題

  • 修正: Always On Display が有効になっている電話機は終了時にパニック/再起動を起こす可能性があります。(128268712)

フェイスタイム

新機能

  • 低データモードの FaceTime では、ネットワーク状態が良好な場合に、ビデオ通話の品質を向上させるために、より多くのデータを使用するようになりました。(128408959)

解決された問題

  • 修正: ユーザーがロック画面から FaceTime ビデオ通話を開始し、その後デバイスのロックを解除すると、カメラが無効になり、ユーザーが PiP 経由でリモート側を見ることができなくなります (その逆も同様)。(124719544)

ファイル

解決された問題

  • 修正: ユーザーが iPhone のファイル アプリの移動パネル内を移動できない場合があります。(128868597)

既知の問題

  • ホストが macOS Sequoia Beta にアップグレードされていない場合、visionOS 2 および iOS 18 シミュレーターでファイル アプリでローカル ファイルを作成できません。(132561244)

ファイナンスキット

解決された問題

  • 修正: トランザクション ピッカー経由で共有されたトランザクションに空の説明文字列が含まれる場合があります。(128618523)

フィットネス+

解決された問題

  • 修正: フィットネス アプリが初回起動時に Fitness+ For You ページをすぐに読み込まない場合があります。(127116109)

財団

新機能

  • JSONEncoder.OutputFormatting.sortedKeys は、異なる順序でキーをソートするようになりました。以前は、キーは数値、大文字と小文字を区別しない、またはローカライズされた順序でソートされていました。ベータ 4 以降、キーはキーの UTF-8 コンテンツに基づいて辞書式にソートされます。(126874437)

解決された問題

  • 修正:スタイルを使用した のような文字列とスタイルを使用した のような文字列が誤って生成されていましたが、その逆でした。この動作は、Duration.UnitsFormatStyle.UnitWidth の動作と一致するように修正されました。(125790342)Date.ComponentsFormatStyle"1m"``Date.ComponentsFormatStyle.Style.condensedAbbreviated``"1min"``.narrowDuration.UnitsFormatStyle.UnitWidth

フリーフォーム

解決された問題

  • 修正: iWork および Freeform に挿入された一部の画像が拡大表示されることがあります。(128637913)

手書き

解決された問題

  • 修正: ディスプレイと明るさの設定でディスプレイのズームを「スペースを増やす」に設定している場合、自動調整アニメーションにレンダリングの問題が発生する。(129419813)

ヘッドフォンの調整

新機能

  • macOS でヘッドフォン調整を設定で​​きるようになりました。AirPods Pro 2 でヘッドフォン調整を設定すると、他のオーディオ ソースに接続したときに調整されたオーディオが引き続き聞こえます。(130245415)

健康

解決された問題

  • 修正: 周期追跡で、ユーザーが妊娠を追加または編集した後に、複数の妊娠サンプルが保存されることがあります。(121271613)

  • 修正: 互換性のないスケジュール タイプについて、ミラーリングされた時計の通知を介して記録された薬の投与量は、デバイスがロックされている場合、携帯電話に保存されません。(128635016)

  • 修正: 妊娠後 12 週間または妊娠周期要因が削除された後、カーディオ フィットネス通知が自動的にオンに戻らない。(128659463)

  • 修正: 周期詳細ビューで、生理の流れが妊娠中の出血と妊娠後の出血として表示されます。(128929595)

  • 修正: 心拍数ウォッチ アプリが削除されても、ヘルスケア アプリとウォッチ設定の健康チェックリストに機能 (不規則なリズムの通知、高心拍数の通知、低心拍数の通知) がアクティブとして表示されます。(128970200)

  • 修正: 周期追跡スニペットに、妊娠前に記録された流れや症状が引き続き表示されることがあります。(129066144)

  • 修正: 周期追跡で、妊娠オンボーディングが完了したデバイスとは別のデバイスで妊娠サンプルが編集または作成されると、メディカル ID で妊娠情報が正しく表示されない場合があります。(130777331)

既知の問題

  • iOS 18 以外のデバイスで妊娠サンプルが削除された場合、該当する場合は、MedicalID から妊娠データを削除するようにユーザーに求めるメッセージは表示されません。(129296194)

    回避策:メディカル ID から妊娠データを手動で削除します。

  • 周期追跡では、妊娠オンボーディングが完了したデバイスとは別のデバイスで妊娠サンプルが編集または作成されると、メディカル ID で妊娠情報が正しく表示されない場合があります。(130784441)

    回避策:医療 ID を編集して妊娠情報を追加します。

ヘルスキット

解決された問題

  • 修正: Apple Watch ワークアウト アプリで作成されたワークアウト タイプのワークアウト ルートが、サードパーティのワークアウト アプリで利用できません。(123450917)

既知の問題

  • 今年 Swift 6 が導入されたことで、Swift 6 を使用するようにプロジェクトを更新した開発者はアプリに問題が発生する可能性があり、さまざまな HealthKit API 呼び出しを実行するとアプリがクラッシュする可能性があります。(131794283)

    回避策:コード内のコールバックに @sendable、NS_SWIFT_SENDABLE の注釈を付ける、または Swift 6 より前のバージョンの言語を使用します。

ホームアプリ

既知の問題

  • ユーザーがベータ 1 または 2 を実行している複数のデバイスを所有し、ユーティリティ アカウントを使用して Home をオンボードした場合、1 つのデバイスがベータ 3 にアップグレードされると、アカウントがオフボードされる可能性があります。(130850945)

    回避策:すべてのデバイスをベータ 3 にアップグレードした後でのみ、Home Utility アカウントを再度オンボードします。

ホーム画面

解決された問題

  • 修正: ホーム画面で暗い色または色付きのアイコンに切り替えるときに遅延が発生する場合があります。(129069905)

  • 修正: 起動後の最初の使用時に、アイコンの色合いスライダー ノブが選択した色に更新されない場合があります。(129114071)

ホームキット

解決された問題

  • 修正: ユーザーが常駐スイッチまたはプライマリ スイッチを再起動した場合、アクセサリのアクセサリ ファームウェア アップデートが提供されません。(128255088)

ホットスポット

解決された問題

  • 修正: キャリア EAP-SIM/EAP-AKA 自動ジョイントが失敗し、ユーザーはキャリアのパブリック ホットスポットを使用できなくなります。(130650425)

iCloudドライブ

解決された問題

  • 修正: iCloud Drive 経由で頻繁に変更されるファイルを同期すると、予想よりも多くのデータが使用されます。(128771010)

iPhoneミラーリング

解決された問題

  • 修正: iPhone ミラーリング中にディクテーションが利用可能になりました。(126654567)

  • 修正: iPhone ミラーリングを使用しているときに、Spotlight または App ライブラリでキーボード入力が機能しない場合があります。(126928807)

  • 修正: ユーザーは iPhone ミラーリングの使用中にロック画面アプリを起動できる場合があります。(128281331)

  • 修正: 設定で iPhone ミラーリングに互換性のないデバイスが表示される場合があります。(128633492)

  • 修正: カメラはいずれの場合も有効にならず、FaceTime のみに警告が表示されます。FaceTime は「iPhone ミラーリングではカメラが許可されていません」という警告をトリガーします。カメラが無効になっていても、他のアプリでは警告はトリガーされません。(128646948)

ジャーナリングの提案

新機能

  • ジャーナリングの提案では、人々が日々の経験を振り返り、書き記すことを奨励し、ジャーナリングの精神的な健康上のメリットを得るための一連の新機能が導入されています。API は、ランドスケープ モードとリフレクション プロンプトをサポートするようになりました。ヘルス アプリまたはジャーナル アプリにログオンした精神状態、スタンドアロンの iPhone を持ちながら実行したランニングおよびウォーク/ランニング混合セッション、MPNowPlayingInfoCenter に寄付したアプリによって再生されたメディア、写真からの人物とペットの名前のサポートが追加され、訪問した国と州を強調表示する旅行提案の機能強化も行われました。(129029773)

解決された問題

  • 修正: 空白の提案やエンジニアリング テキストが表示される場合があります。(128774773)

  • 修正: ユーザーが「+」をタップしてジャーナリング提案シートを開いた後、長いスピナーが表示される場合があります。(128950895)

  • 修正: 「+」をタップしてジャーナリング提案シートを起動しても起動しない場合があります。(128970387)

カーネル

廃止予定

  • kern.bootsessionuuidアプリでは利用できなくなりました。(47217954)

キーボード

解決された問題

  • 修正: ユーザーは設定でキーボードを構成できず、異なる言語のキーボードの追加/削除やキーボード拡張機能の追加/削除もできなくなります。(129174947)

ロック画面

解決された問題

  • 修正: ロック画面のクイックアクション ボタンが消える場合があります。(128096099)

  • 修正: ユーザーはロック画面で設定できるコントロールを設定できなくなります。(128967021)

郵便

解決された問題

  • 修正: メールが起動されるまでメールバッジの数が更新されない場合があります。(129914323)

既知の問題

  • iOS 18.0 ベータ 5 から iOS 18.1 ベータにアップグレードすると、すべてのメールが再ダウンロードされる可能性があります。(132930689)

地図

新機能

  • 一意かつ永続的な識別子である Place ID を導入しました。(129071038)

  • MKLocalSearch.Request に新しい resultTypes と追加の PointofInterestCategory 値を追加しました。(129073725)

  • マップの Place Card UI を表示するための Place Card API を導入しました。(129073922)

解決された問題

  • 修正: SMS 経由で受信者に送信するときに、Maps Share ETA が失敗する場合があります。(127547239)

  • 修正: Place Card API が場所の詳細を読み込めない場合があります。(128504304)

  • 修正: MKLocalSearch.Request を使用する検索では、結果タイプ オプション physicalFeature は無視されます。(128961972)

既知の問題

  • マップ ビュー内のポイントと物理的な場所 (CLLocationCoordinate2D) 間の変換は、高ズーム レベルでは不正確になる可能性があります。(129042241)

数学ノート

解決された問題

  • 修正: 負の数を調整すると、負の符号が複数になる場合があります。(123738353)

  • 修正: カンマを使用して数値を調整すると、数値がすぐに 0 に変更されることがあります。(127904684)

メモリ割り当て

新機能

  • システム メモリ アロケータ (malloc(3)) は、ほとんどの割り当てサイズに対して新しい実装に切り替わりました。ヒープ レイアウトの変更、割り当てが多いワークロードのパフォーマンスの違い、および断片化の変更により、潜在的なメモリ アクセス バグが露呈する可能性があります。(127493322)

メッセージ

新機能

  • 衛星経由で送受信されたメッセージは、他のデバイスに中継されない可能性があります。(125574729)

  • 衛星経由のメッセージは現在米国でのみ利用可能です。衛星経由の SMS メッセージは一部の通信事業者で利用可能です。(127751557)

  • 衛星経由のメッセージは現在米国でのみ利用可能です。衛星経由の SMS メッセージは一部の通信事業者で利用可能です。(131421891)

  • RCS メッセージングは​​、一部の通信事業者でご利用いただけます。(131499640)

解決された問題

  • 修正: メッセージが送信されたときではなく、メッセージをスケジュールしたときにメッセージ送信音が再生されるようになりました。(121896789)

  • 修正: メッセージを長押ししてタップバックを適用すると、ユーザーはサードパーティのステッカーを使用できなくなります。(122379099)

  • 修正: オフグリッドの場合、ユーザーが衛星経由でテキスト メッセージを送受信できるにもかかわらず、テキスト メッセージの会話に、通信事業者が衛星経由のテキスト メッセージをサポートしていないことを示すテキストが誤って表示される場合があります。(127334940)

  • 修正: SMS グループの会話で絵文字のタップバックが正しく表示されない場合があります。(127446747)

  • オングリッド時に MMS のマルチパート SMS 通知がデバイスによって正しく処理されない問題を修正しました。(128880899)

  • 修正: RCS がまだ登録されている場合でも、既存の RCS 1:1/グループ チャットは SMS にダウングレードされます。(130029732)

既知の問題

  • RCS および iMessage 参加者とのグループ メッセージの場合、テキスト メッセージの添付ファイルへの返信が受信側デバイスでスレッドとして表示されないことがあります。(133326509)

ネットワーキング

解決された問題

  • 修正: macOS 15 / iOS 18 以降にリンクされたアプリの場合、URLSession によって生成されるデフォルトの User-Agent リクエスト ヘッダー フィールド値に、ローカライズされたバンドル名ではなく、ローカライズされていないバンドル名が含まれるようになりました。(117380285)

通知

解決された問題

  • 修正: リスト表示ではロック画面の着信通知が表示されない場合があります。(129021171)

電話

解決された問題

  • 修正: 電話アプリで、アイコンをタップすると音声通話が開始されるにもかかわらず、キーパッドの検索結果には常にビデオ アイコンが表示される。(131601723)

写真

新機能

  • コレクションの順序と表示の変更は、iOS および iPadOS 18.0 ベータ 4 以前で行われた場合はリセットされます。(132117458)

解決された問題

  • 修正: iCloud フォト ライブラリ経由で写真とビデオの同期が停止する場合があります。(128325085)

  • 修正: 写真関連のサービスが応答しない場合があります。この問題は、iCloud フォト ライブラリの同期、カメラのキャプチャ、スクリーンショットのキャプチャ、共有に影響する可能性があります。(130739189)

  • 修正: iOS 18.0 ベータ 5 から iOS 18.1 ベータにアップグレードすると、フォト ライブラリが再構築されます。(131845921)

プラットフォーム

新機能

  • M3 以降および A16 Bionic 以降の Apple Silicon ベースのデバイスでは、CNTFRQ_EL0 および CNTVCT_EL0 レジスタの読み取りによって返される値が、以前の値 24 MHz ではなく 1 GHz に更新されました。アプリでは、引き続き、タイムキーピングなどの libsystem API を使用することをお勧めします。アプリが Apple のタイムキーピング API を使用している場合、この変更による影響を受けません。互換性のため、この変更は、このリリースまたはそれ以降に関連付けられた SDK を使用している場合にのみ表示されます。macOS では、Virtualization.framework VM 内で実行されているアプリケーションは、引き続き従来の動作を受け取ります。(84639494)mach_absolute_time()

  • iBoot のファームウェア イメージは、PCC イメージでクリアテキストで利用できるようになります。ファームウェア暗号化によって課されるオーバーヘッドを削減し、適切なポリシーを合わせるために、iOS、macOS、watchOS、tvOS、visionOS 上の iBoot ではファームウェア暗号化が無効になっています。詳細については、Private Cloud Compute を参照してください。(125171074)

ポッドキャスト

解決された問題

  • 修正: ポッドキャストのショートカットのオプションとして「トランスクリプトを表示」が誤って表示されます。(131070716)

プレビュー

解決された問題

  • 修正: デバイス上のプレビューのトリガーが失敗する場合があります。(129150211)

リアリティキット

新機能

  • Catmull-Clark サブディビジョンを使用する USD ファイルは、RealityKit でサブディビジョンを使用してレンダリングされるようになりました。35,000 未満のパッチを生成するメッシュは、サブディビジョンを使用してレンダリングできます。これにより、メモリ消費量が増加し、レンダリング パフォーマンスが低下する可能性があります。(129016034)

  • 仮想オブジェクトは、Display P3 色域を使用してレンダリングされるようになりました。セマンティックでに接続されたを使用する場合は、Display P3 色空間を使用してレンダリングします。(129017592)DrawableQueue``TextureResource``.color

解決された問題

  • iOS & iPadOS 17、macOS 14、visionOS 1 以前では、UnlitMaterials のブレンディング モードは.blending、、、.colorおよびセッターに一貫して応答しません。iOS & iPadOS 18、macOS 15、または visionOS 2 の RealityKit に対してビルドされるアプリケーションでは、アルファブレンディングの有効化は で明示的に構成する必要があります。開発者は、コードで構成されたマテリアルが意図したとおりにアルファブレンディングされていることを確認し、必要に応じて 設定を使用することをお勧めします。(118210191).baseColor``.blending = .transparent(opacity:)``.blending

  • iOS & iPadOS 17、macOS 14、visionOS 1 以前では、透明マテリアルの見かけの最終不透明度は.blending、、、.colorおよびセッターに対して一貫性のない応答をします。iOS & iPadOS 18、macOS 15、または visionOS 2 の RealityKit に対して構築されたアプリケーションでは、透明マテリアルの最終不透明度は、そのまたはのアルファとの乗算として計算されます。開発者は、コードで構成された透明マテリアルが意図した最終不透明度でレンダリングされることを確認し、必要に応じて、、および/または の使用を更新することをお勧めします。(125431647).baseColor``.color``.baseColor``.blending = .transparent(opacity:)``.color``.baseColor``.blending = .transparent(opacity:)

  • 修正: iOS では機能が正しく動作しない可能性があります。(125742631)pixelCast

  • 修正: 地面の影が予想よりも目立たない。(126498888)

  • 修正: Image 2D ArrayReality Composer Pro で Shader Graph ノードを使用すると、破損やシステムクラッシュが発生する可能性があります。(127122590)

  • 修正: 特定の iPad Pro の ARQL でグラウンド シャドウが表示されません。Xcode ストーリーボード経由でレイ トレース シャドウを有効にするアプリは適用されません。(127748381)

  • 修正:environmentのプロパティをに設定してもARKit セッションが自動的に開始されず、 の背景が黒くなる場合があります。(128417183)RealityView``.worldTracking``RealityView

  • 修正: RealityKit のベータ バージョンで書き込まれた Reality ファイルが、それ以降のバージョンでは読み込まれない場合があります。(128424173)

  • 修正: 物理シミュレーションの動作が以前のリリースと異なります。(128435086)

  • 修正: stopSpatialTrackingSession の関数が機能しません。(128559666)

  • 修正: 強調アクションは常に追加的であり、に設定して再生する必要があります。(128622689)separateAnimatedValue``true

  • 修正: Swift 6 言語モードでは、Entityクラスのサブクラスがコンパイルされません。(128787131)

  • 修正:.trigger関係する衝突シェイプの両方が.triggerモードを使用する場合、CollisionComponent のモードは CollisionEvents を生成しなくなりました。(129016567)

  • 修正: [.world, .plane, .image, .object, .face, .camera]LiDAR スキャナーのないデバイスで、アンカー機能をシーン理解機能と組み合わせて使用​​すると、それらのアンカー機能が動作しなくなる問題を修正しました。(129253808)

廃止予定

  • 以前のバージョンでは、子エンティティの順序が保持されることがありました。現在、 の子の順序はEntity信頼できない可能性があり、子の親が変更されると予期せず変更される可能性があります。(129015381)

スクリーンタイム

解決された問題

  • 修正: 親デバイスからリモートで承認すると、子供がアプリまたは Web サイトの 15 分、1 時間、または終日の例外を要求したかどうかに関係なく、常に 1 時間が付与されます。(129084141)

  • 修正: Apple Watch を以前のベータ版から 11.0 にアップグレードすると、スクリーンタイム アプリ制限が親と子の両方で削除される可能性があります。この問題が発生した場合、親はアプリ制限を再度追加する必要があります。(130981807)

検索

解決された問題

  • 修正: 「Apple の検索機能の向上に協力する」コントロールが機能しません。(129226418)

設定

解決された問題

  • 修正: 最近使った項目や検索結果が見つからない場合があり、ネストされたペインに移動できないことがあります。(128802504)

  • 修正: [全般] > [バージョン情報] にリストされる使用可能なストレージが正しくない場合があります。(129688831)

  • 修正: 「設定」>「一般」>「ストレージ」に移動すると、ポッドキャストを開いていないと設定アプリがクラッシュすることがあります。(131180865)

ショートカット

解決された問題

  • 修正: ショートカット エディターでは、まだ使用できない新しいアクションがいくつか提供される場合があります。これらのアクションのいずれかを使用してショートカットを保存すると、修正されたアクションを含む今後の更新後に修正が必要になる場合があります。(128841105)

  • 修正: SiriKit インテントまたは App Intent を追加または削除しても、ショートカット アプリにすぐに反映されない場合があります。(130039560)

  • 修正: ボードの作成とボードのショートカットを開くアクションとアプリのショートカットが利用できない場合があります。(133023610)

シミュレーター

解決された問題

  • 修正: シミュレーターで Safari を使用すると、シミュレーターがハングする可能性があります。(128545001)

シリ

新機能

  • iOS 18では、CarPlayのない車両にiPhoneをBluetoothで接続すると、新しいオプション「メディアソース経由で応答」によってSiriのオーディオ品質が大幅に向上します。まず、開発者向け設定を有効にして設定を有効にする必要があります。「開発者」→「Bluetooth車載テストでのSiri」→「設定でオーディオ出力を表示」に切り替えます。その後、設定の「Siriと検索」→「Siriの応答」→「車載Bluetoothに接続したとき」に移動して、この機能を使用できるようになります。(128692679)

ソフトウェアアップデート

解決された問題

  • 修正: iOS 18 ベータ 4 または macOS 15 ベータ 4 より前の iOS/iPadOS 18 ベータ ビルドまたは macOS 15 ベータ ビルドからアップデートするデバイスでダウンロード エラーが発生する場合があります。(130652449)

スポットライト

既知の問題

  • Spotlight のアイコンがホーム画面のアイコンと一致しない場合があります。(134088480)

ストアキット

新機能

  • は、カスタム コントロール スタイルをサポートするようになりました。カスタム コントロール スタイルを作成するには、に準拠する型を宣言し、メソッドを実装します。(106819454)SubscriptionStoreViewSubscriptionStoreControlStylemakeBody(configuration:)

  • コンパクトな高さのサブスクリプション ストア ビュー コントロールをレイアウトするための新しい標準スタイルが利用可能になりました。プラットフォームに適したページング効果を実現するにはと を使用し、オプションを水平スタックに配置します。watchOS では、コンパクトな高さのコントロールをレイアウトするための新しいスタイルが利用可能になりました。(110286601)pagedPicker``pagedProminentPicker``compactPicker``pagedPickerSubscriptionStoreView

  • や などのタイプを使用して、の階層構造を宣言します。 を使用して、グループをタブ ビューとして表示するか、ナビゲーション リンクとして表示するかを選択できます。(110429924) (FB12264937)SubscriptionOptionGroup``SubscriptionPeriodGroupSetSubscriptionStoreViewsubscriptionStoreOptionGroupStyle(_:)

  • サブスクリプション ステータスオブジェクトは、サブスクリプションが更新される価格と通貨を示す新しいプロパティをサポートするようになりました。また、次の更新に適用されるオファー (ある場合) の情報を含む新しいプロパティもあります。これには、オファー ID、オファー タイプ、支払いモードが含まれます。(114217892)RenewalInforenewalPrice``currency``offer

  • API の使用時に、完成した消耗品を含めることができるようになりましたTransaction。ユーザーは、アプリの Info.plist で true に設定することでこの機能を有効にできます。(115079880)SKInAppPurchaseHistoryIncludesConsumables

  • のコントロール スタイルを構成するときに、ユーザーはビュー修飾子を使用してコントロールの配置を指定できます。tvOS の場合、デフォルトでは、コントロールはマーケティング コンテンツの後ろに配置されます。(115319543)SubscriptionStoreViewsubscriptionStoreControlStyle(_:placement:)SubscriptionStoreView

  • Xcode 16 でアプリをビルドすると、ピッカー コントロール スタイルを使用するインスタンスの外観が更新されます。ピッカー項目の異なる背景色と形状を構成するために使用します。(120558960)SubscriptionStoreViewsubscriptionStorePickerItemBackground(_:in:)

  • ユーザーは、月間や年間などの API を使用して、サブスクリプション期間を比較するときに共通の値を取得できるようになりました。(122684230)Product.SubscriptionPeriod

解決された問題

  • 修正: Xcode で StoreKit テストをDone使用する場合、払い戻しリクエスト確認シートで選択するとエラーが返されます。(123865137)refund request API

  • 修正: VoiceOver がおよびで製品のタイトルと説明を読み上げません。(124254957) (FB13679318)ProductViewStoreView

  • オプション グループ スタイルで使用するとタブ コントロールが広すぎる問題を修正しました。(128567088)SusbcriptionStoreViewStoreContenttabs

  • 環境変数は Swift 6 と互換性を持つようになりました。(129929512) (FB13922875)requestReview

既知の問題

  • コンテナ ビュー内で使用すると、ウィンドウ バーが正しく機能しません。(117701666)SubscriptionStorePicker

    回避策:コンテナー内で使用する代わりに、メソッドからトップレベルのビューとして返します。SubscriptionStorePicker``makeBody(configuration:)

廃止予定

  • アプリ内購入のオリジナル API は廃止されました。これには、SKStoreReviewController、SKProduct、SKReceiptRefreshRequest、SKStorefront、SKPayment、SKRequest、SKProductsRequest、および SKProductDiscount が含まれます。現在の API と将来の機能強化については、 StoreKit 2にアップグレードしてください。(116600524)

Swift チャート

新機能

  • および を使用して数学関数をプロットします。 (117186178)LinePlot``AreaPlot

  • やなどのベクトル化されたプロット API を使用して、大規模なデータセットをより効率的に視覚化します。(117469419)PointPlot``RectanglePlot

解決された問題

  • 修正: 回転した軸ラベルが間違ったサイズに伸びる。(106013386)

  • 修正: アニメーション中にマークのぼかし効果と影の効果が消える場合があります。(125493885)

  • 修正: で作成された接続された散布図をアニメーション化する際の不具合。(127196185)LineMark

  • 修正: ストローク スタイルをアニメーション化できるようになりました。(127465359)

  • 修正: 関数プロットの場合、Y ドメインを自動的に推測できません。(128877906)

  • 修正: チャートを含むアニメーションでは、色が変化しなくても、アニメーションの継続時間中にマークが消える場合があります。(130023892).foregroundStyle(Color)

SwiftUI

新機能

  • を使用する場合、現在のタブをタップすると、埋め込まれたナビゲーション スタックがポップアップされるようになりました。(50924017)TabView

  • ピッカー コンテンツの個々のビューに修飾子を付加することで、ピッカーの個々のオプションにキーボード ショートカットを付加できるようになりました。(67682762) (FB8522629)keyboardShortcut()

  • 複数のビューをタイトルとして持つLabel内で を使用すると、それらのビューが垂直に積み重ねられ、最初のビュー以降のすべてのビューにサブタイトル処理が適用されます。(115528544)List

  • 、、およびで使用されるサブクラスの場合、SwiftUI はオブジェクト インスタンスごとにプロパティごとに 1 回だけ を呼び出すようになりました。とデフォルトのを使用する場合は、何も変更する必要はありません。 をオーバーライドする場合は、返すパブリッシャーの有効期間が、それを囲む の有効期間と一致するようにしてください。(116197689)ObservableObject``@EnvironmentObject``@ObservedObject``@StateObject``objectWillChange``@Published``ObservableObjectPublisher``objectWillChange``ObservableObject

  • iPad では、このautomaticスタイルを使用する TabView の水平サイズ クラスに新しい外観が追加されましたregular。タブ バーは下部ではなく上部に表示されるようになり、見た目もよりコンパクトになりました。(117029720)

  • 修飾子付きで表示される SwiftUI シートは、デフォルトでサイズ設定を.sheet使用するようになりました。 は、プラットフォームに応じてまたはに解決されます(詳細については、シンボルのドキュメントを参照してください)。iOS 18 およびそれに準拠したリリースより前のプラットフォームでは、カスタマイズできない異なるデフォルトのシート サイズ設定が使用されていました。iOS 17 以前では、現在プレゼンテーション サイズ設定と呼ばれているものが使用されていました。macOS 14 以前では、現在サイズ設定と呼ばれているものが使用されていました。visionOS 1 ではサイズ設定が使用されていました。iOS 18 およびそれに準拠した SDK に対してアプリをリンクする場合は、シートのプレゼンテーションを監査し、最適なサイズ設定を選択してください。シートの内容に修飾子を適用します。.automatic``.automatic``.form``.form.fitted(horizontal:false, vertical: true)``.page``.fitted``.fitted``.presentationSizing

   ContentView().sheet(isPresented: $present) {
     SheetView().presentationSizing(.form)
   }

(117551515)

  • highPriorityGesture と ScrollView の相互作用が改善されました。(119333786)

  • iOS 18 にリンクされたドキュメントベースのアプリケーションに、新しい起動画面のデザインが追加されました。ユーザーは、アプリ定義に を追加することで、デフォルトのデザインをカスタマイズできます。ユーザーは、画面のタイトルと背景を変更したり、アクション ボタンを置き換えたり、装飾的なアクセサリ ビューを追加したりできます。DocumentGroupLaunchScene

    ドキュメントベース以外のアプリでも、 経由で新しい画面を使用できます。(119843158)DocumentLaunchView

  • View プロトコルおよびその他の同様の SwiftUI プロトコルに準拠する型は、デフォルトで に分離されるようになりました。アクター分離に関する SwiftUI のランタイム動作は変更されていません。SwiftUI ビューおよび同様の型は、実行時に常にメインアクターで評価されてきました。この変更により、潜在的なデータ競合の安全性の問題に対するコンパイル時の診断が改善されます。新しいデフォルトのメインアクター分離をオプトアウトして、以前のデフォルトの分離を復元するには、必要に応じてメソッドとプロパティに nonisolated キーワードを追加するか、プロトコル準拠を拡張機能に移動して型全体をオプトアウトします。(120815051)@MainActor

  • FormatStyleCapitalizationContext に依存し、文字列補間によって LocalizableStringResource に埋め込まれている既知の FormatStyle は、文の構造に基づいて大文字と小文字を自動的に推測するようになりました。大文字と小文字は、unknown以前から自動的に推測されていた場合にのみ自動的に推測されます。(122688257)

  • Text(_:format:)環境からおよびを使用して、SwiftUI に既知のものが自動的に挿入されるようになりました。(123662780)FormatStyle``TimeZone``Calendar

  • @Entryマクロを使用して、カスタム、、、プロパティの宣言を簡素化できるようになりました。(125568810)EnvironmentValues``FocusedValues``Transaction``ContainerValues

  • ジェスチャに名前を付ける機能が追加されました。この名前は、依存関係を確立するときに UIGestureRecognizers に表示されます。(126527559)

  • TabSection 内に TabSection をネストすることは、iPadOS および visionOS の TabViewStyle でサポートされています。(128237671).sidebarAdaptable

解決された問題

  • 長押しジェスチャにより他の子孫ビューでのジェスチャがブロックされる問題を修正しました。(57368881)

  • UIButtonused with がタッチを受信しない可能性がある問題を修正しました。SwiftUI のタップ ジェスチャもインスタンスと正しく調整されるようになりました。(57885589)UIViewRepresentable``UITapGestureRecognizer

  • 修正: iOS 18 以降にリンクされたアプリの場合、popover修飾子は iOS および iPadOS の引数を尊重するようになりました。(66839017) (FB8350757)arrowEdge

  • 修正: メニューを閉じるときに SwiftUI ジェスチャが誤ってトリガーされなくなりました。(69703502) (FB8751308)

  • 修正:未使用の子ビューの永続的な状態を再利用できるようになりました。要素内のビューによって作成された値は、以前よりも早く破棄される可能性があります。(90667238)ForEach``@State``ForEach

  • 修正:のコンテンツまたは詳細列でキャプチャされた により、暗黙的なスタックがポップされるようになりました。DismissAction``NavigationSplitView

    iOS 18 以降にリンクされたアプリおよびそれに合わせたリリースの場合、以下の例のボタンをクリックすると、サイドバーの選択がすべてクリアされるようになりましたList。以前は、iOS では何も表示されずに失敗し、macOS ではウィンドウが閉じられていました。

   NavigationSplitView {
     List(…)
   } detail: {
     DetailView()
   }

   struct DetailView: View {
     @Environment(\.dismiss) private var dismiss

     var body: some View { 
       Button("Pop") { dismiss() }
     }
   }

以前の動作を維持するには、の上の環境からをキャプチャします。(92522613)DismissAction``NavigationSplitView

  • 修正: A は、スクロールできない端に安全領域のインセットを伝播するようになりました。デフォルトでは、画面サイズを占めるスクロール ビューのスクロール インジケーターのインセットが改善されました。(102766716)ScrollView

  • 修正: アウトライン リストが正しくアニメーション化されません。(106239318)

  • 検索可能な候補が、現在の検索テキストに一致する補完オプションを自動的に除外する問題を修正しました。必要に応じて、候補から完全一致を明示的に除外する必要があります。(107706241)searchCompletion

  • 修正: “@dependencies” の代わりに、変更された監視可能なプロパティのキー パスを出力するようになりました。(111392797)View._printChanges

  • 修正:またはを指定したビュー修飾子を使用すると、包含ウィンドウを使用して、遅延スタックがレンダリングするコンテンツが決定されます。(111796138)scrollClipDisabled()``ScrollView``LazyHStack``LazyVStack

  • 修正: SwiftUI は、プロトコルに準拠する型Appが値型であることをアサートするようになりました。(113634782)

  • 修正: macOS では、スタイルのトグルがプログラムで状態が変更される.switchとアニメーション化されるようになりました。これは、iOS および iPadOS の既存の動作と一致します。トグルの状態を更新するときにトランザクションのプロパティを設定することで、すべてのプラットフォームでアニメーションを無効にすることができます。(115071023)isOn``disablesAnimations

  • 修正:またはをText介して作成されたものの自動更新により、長時間実行されるライブ アクティビティで使用されると、バッテリーの消耗が増大していました。秒の値を示す数字の変化をアニメーション化することはなくなり、電力への影響を最小限に抑えています。(115906895)Text(_:style:)Text(timerInterval:pauseTime:countsDown:showsHours:)

  • 修正: nil アンカーで修飾子を使用した場合に、SwiftUI が nil をオーバーライドしなくなりました。以前の動作を復元するには、アンカーを指定します。(116124988)scrollTargetAnchor``scrollPosition(id:anchor:)``topLeading

  • 修正: iOS 18 SDK にリンクする場合、SwiftUI は、シートのサイズに依存する.sheetプレゼンテーション設定 (またはなど) によって発生するプレゼンテーションのサイクルを防止します。iOS 18 より前のバージョンでは、これらのサイクルは、ある程度の振動の後に独立して落ち着くことがありました。(117699610)presentationDetents``presentationBackground

  • 修正: 少なくとも 1 つのシーンがアクティブな場合、アプリの scenePhase がアクティブとして報告されるようになりました。(117864591)

  • 修正: iOS 18 SDK にリンクするときに、修飾子の引数が尊重されるようになりました。以前は のデフォルト引数に依存していた場合、この引数は尊重されず、代わりにポップオーバーが の動作で表示されていました。明示的な値を渡すと、その値が尊重されるようになりました。パラメーターに明示的な引数を渡さない場合、iOS 18 SDK で再コンパイルすると、オーバーロード解決によって、システムが最適な矢印の端を選択する、矢印の端を取らない新しいメソッドが選択されます。iOS 18 SDK で再コンパイルするときは、ポップオーバーが間違った方向に表示されてクリップされたり画面外になったりしないようにしてください。(117921721)arrowEdge``.popover``.top``.any``arrowEdge

  • 修正: スクロール ビューがコンテンツ インセットでの操作を受け入れるようになりました。(117928468)

  • 修正:遅延コンテナ内の修飾子は評価されなくなりました。およびは、遅延コンテナ内で使用されると警告をログに記録します。このコンテキストでの遅延コンテナには、、、、、、およびが含まれます。 を遅延コンテナ内で使用すると、実行時にログに記録されたエラーがユーザーに表示されます。 修飾子をビュー階層の上位に移動して、遅延コンテナの外部に配置します。遅延コンテナ内でナビゲーション デスティネーション修飾子を許可すると、2 つの大きなコストが発生します。(1) navigationDestination が画面外にスクロールされた場合、アプリ ナビゲーションの状態が未定義になる可能性があります。(2) ナビゲーション システムは、ナビゲーション デスティネーションが最新の状態であることを確認するために、リストのすべてのコンテンツを調査する必要があります。これらの修飾子を遅延コンテナの外部でのみ許可すると、アプリ ナビゲーションの信頼性とパフォーマンスが向上します。(117998693).navigationDestination(for:destination)``.navigationDestination(isPresented:destination:)``navigationDestination(item:destination)``List``LazyVGrid``LazyHGrid``LazyHStack``LazyVStack Table``TabView``navigationDestination

  • UIControlSwiftUI ジェスチャがビュー内のサブクラスまたはジェスチャと同時にトリガーされる問題を修正しました。(119335307)UIViewRepresentable

  • 修正: のルートにあるビューには常に一致するコールバックが含まれるようになりました。(119737698)NavigationStack``onAppear``onDisappear

  • 修正: 合成モディファイアの順序が影に関して尊重されるようになりました。以前は追加されたブレンド モードが影にも適用されていましたが、これはなくなりました。ブレンド モード モディファイアは影モディファイアの後にのみ適用されます。その結果、塗りつぶしと追加された影は異なるブレンド モードを使用できるようになりました。同様のルールが適用されますが、外側のモディファイアは内側のモディファイアと乗算されます。たとえば、影は50% の不透明度 (描画するもの)で描画され、それ自体は 25% の不透明度で描画されます。(119738072)ShapeStyle``fill(style.blendMode(…).shadow(…))``ShapeStyle.opacity()``opacity()``fill(style.opacity(0.5).shadow(…).opacity(0.5))``style``style

  • ポップオーバー プレゼンテーションが安全領域外に出ると自動的に閉じられる問題を修正しました。(120458490)

  • 修正: iOS 18 に合わせたリリースより前にデプロイされたアプリでは、関数に渡されるブール値の意味が反転していました。(120561508)ContentTransition.numericText(countsDown:)

  • 修正: ボタンのタップ可能領域を増やす場合など、ジェスチャで変更されたコンテンツの形状が反映されない場合があります。(120938385)

  • 修正:Picker無効な選択で初期化された場合、 A の現在の値ラベルがデフォルトで最初のオプションに設定されなくなりました。(121871839)

  • 修正: NavigationSplitView で列の表示/非表示をすばやく切り替えると、サイドバーが表示または非表示の位置で動かなくなる可能性がある問題を解決しました。(122840735)

  • 修正: サイドバーのヘッダーが目立つようになっても反応しなくなりました。(123518195)

  • sheetビュー階層から修飾子が削除されるときの問題を修正しました。これは、sheet修飾子がステートメントの 1 つのブランチにありif、ステートメントの条件が変更された場合に発生する可能性があります。iOS 18 以降にリンクされたアプリおよび調整されたリリースでは、sheet修飾子が階層から完全に削除されても、シートに関連付けられたバインディングはリセットされません。(123742063)

  • 修正:子ビューは、ビューのパラメータが変更された可能性がある場合にのみ無条件に再評価されなくなりました。(123902210)ForEach``ForEach

  • 修正: TabSection を別の TabSection 内にネストするとアプリがクラッシュする可能性があります。(123928013)

  • 修正: コンテンツのサイズがコンテナーのサイズより小さい場合、右から左に表示する言語でのスクロール ビューの動作が改善されました。(124008045)

  • 修正:のパラメータに渡されるデータ構造または に沿った要素がより効率的に比較されるようになりました。 をそれ自身と等しく設定することによる副作用はもはや信頼できず、おそらく発生しません。(125093883)NavigationPath``path``NavigationStack(path:root:)``path

  • 修正:関連するセルが表示される前に、ルート ビューの状態がリセットされるようになりました。(125100960)UIHostingConfiguration

  • 修正: 、、、、、は実行時にクラッシュするのではなく、コンパイル時にサポートされていない条件を診断するようになりました。 (125379937)SceneBuilder``WidgetBundleBuilder``TableColumnBuilder``TableRowBuilder``CommandsBuilder``ToolbarContentBuilder``if #available

  • 修正: カスタム プレビューを含むコンテキスト メニューを操作できない問題を解決しました。(125517121)

  • 修正: 、およびそのビュー コントローラー バリアントでは、 が true に設定されたレイヤーが作成されなくなりました。(125561916)UIViewRepresentable``NSViewRepresentable``allowsGroupOpacity

  • 修正: 特定のシナリオで、不必要に小さいカレンダー単位を選択したり、大きいカレンダー単位を省略せずにゼロ値を表示したり、常時オンディスプレイで秒を表示したりするなど、最適ではない出力が生成されました。(125885307)Text(_:style:)

  • 修正:タイマーが一時停止されている、まだ開始されていない、またはすでに終了している場合でも、秒の値を編集していました。(125885429)Text(timerInterval:pauseTime:countsDown:showsHours:)

  • 修正:searchable()に修飾子を適用すると、タブを切り替えるときにタブ ビューで検索状態がリセットされます。(125926765)TabView

  • 修正: タップ可能なコントロールの近くにスクロール ビューを配置するとタッチが受信されない問題を解決しました。新しい SDK で再構築する場合は、小さなボタンとタップ ターゲットが正しく拡大されていることを確認してください。修飾子を使用できます。(126232279)contentShape

  • 修正:を介して作成された、ドキュメント編集を許可しないシーンでは、ドキュメント ビューがレンダリングされません。(127076044)DocumentGroup``DocumentGroup(viewing:viewer:)

  • 修正: DocumentLaunchView 内の NewDocumentButton() が押されたときにドキュメントの作成に失敗します。(127389818)

  • 修正: カスタマイズ動作を持つタブにカスタマイズ識別子が指定されていない場合、TabView カスタマイズでランタイム エラーが発生しますautomatic。(127442031)

  • 修正: 非推奨の一部のナビゲーションリンクが機能しない可能性があります。(128358023)NavigationView

  • 修正:.sheet修飾子付きで表示されるシートはデフォルトで になります。これにより、シートの内容によっては、シートが狭すぎたり大きすぎたりすることがあります。これは正しくありません。デフォルトのプレゼンテーション サイズは である必要があります。(128902804)FittedPresentationSizing``.form

  • 修正:別のものから派生したget/set でラップされた引数を持つ非推奨のリンクは、派生バインディングの更新が遅すぎると、宛先ビューを更新しない可能性があります。(129018685)NavigationLinks``isActive``Binding``Binding

  • 修正: Swift 6 言語モードでは、エントリの型が明示的に宣言されている場合、@Entryマクロは非型でも動作するようになりました。(129073803)Sendable

  • UIKit の依存関係を解決するときに、修飾子に渡された名前gestureが使用できない問題を修正しました。(129590852)

ヒントキット

新機能

  • 新しいAPI と同期は、今後のベータ SDK リリースを通じて利用可能になります。(129425412)TipGroup``CloudKitContainer

翻訳

新機能

  • ユーザーはテキストを翻訳し、アプリ内で結果を表示できます。クラスをご覧になり、WWDC24 のビデオ「Meet the Translation API」(112844581) で詳細をご確認ください。TranslationSession

  • 翻訳では、翻訳アプリでのヒンディー語翻訳、システム全体の翻訳、Safari 翻訳、新しい翻訳 API がサポートされるようになりました。(116622913)

解決された問題

  • 修正: iPhone で使用する場合、シート上の背景がプレゼンテーション ビューを透過せずにブロックします。(128504309).translationPresentation()

UIアプリケーション

解決された問題

  • 修正: iOS 18、iPadOS 18、Mac Catalyst 18、または tvOS 18 SDK で構築されたアプリケーションは、非推奨のメソッド を呼び出します。指定された URL は開かず、常に を返します。(125695759)UIApplication.openURL(_:)``false

開発者

解決された問題

  • 修正:期待どおりに動作しません。(126277771)UITabGroup.managingNavigationController

  • 修正: UIDocumentBrowserViewController の「最近」タブで「+」記号を使用して新しいドキュメントを作成すると失敗する場合があります。(128520498)

  • 修正: 子が選択されたときに tabBarController(_:didSelectTab:previousTab:) が呼び出されません。(128697021)UITabGroup

  • 修正: RTL 言語の iPad タブ バーでタブ タイトルが表示されない。(130154177)

廃止予定

  • アプリアイコンの名前で呼び出された場合UIImage(named:)、以前はマスクやシャドウが適用されていないアイコンセットの未定義の画像を返していました。iOS 18 では nil を返すようになりました。アプリ自体にアイコンを表示するには、目的の画像を画像セットとしてアセットカタログに追加します。(130491812) (FB14052579)

ビジョンフレームワーク

廃止予定

  • faceCaptureQualityはonに置き換えられました。(132508104)captureQuality.score``FaceObservation

財布

新機能

  • 詐欺行為を防止するため、iPhone に ID を追加する際、ユーザーは一連の頭や顔の動きの代わりに、またはそれに加えて、Live Photo を撮影するよう求められる場合があります。Live Photo はデバイスと Apple によって評価され、送信された写真が生きている人物のものであり、同じ生きている人物が写真を送信していることを確認します。(129338051)

解決された問題

  • 修正: Wallet に Face ID を要求するが有効になっている場合、アプリ内で Wallet の ID を共有することはできません。(128775860)

ウォレットとApple Pay

既知の問題

  • Apple Watch をお使いの場合、iPhone の Wallet で接続されたアカウントを再認証するよう求められる場合があります。(129127520)

    回避策: iPhone と Apple Watch が同期するまで待ちます。数分経っても問題が解決しない場合は、iPhone で接続を再認証してみてください。

ウォッチフェイス

解決された問題

  • 修正: iPhone の Apple Watch > 文字盤ギャラリーで、ポッドキャスト アプリとミュージック アプリのコンプリケーションが利用できません。(131747921)

ウェザーキット

解決された問題

  • 修正: HistoricalComparisons データは、他の気象データセット (例: CurrentWeather) とともに要求されない限り返されません。(107204312)

  • 修正: 返された HistoricalComparisons 条件 (降水量など) に、ベースラインと現在の値のプレースホルダー値が含まれる場合があります。(126496817)

  • 修正: 90 日を超える DayTemperatureSummary および DayPrecipitationSummary データの応答が返されるまでに時間がかかる場合があります。(127768828)

  • 修正: averagePrecipitationProbability や averageSnowfallAmount などの一部の PrecipitationStatistics フィールドにプレースホルダー値が表示される場合があります。(128008885)

  • 修正: WeatherKit v2 は現在 Swift でのみ利用可能で、REST API では使用できません。(128024852)

ウィジェットキット

解決された問題

  • 修正: 現在、「autoPresentConfigAfterAdding」を採用しても、ウィジェットまたはコントロールの構成シートが自動的に表示されません。(114470520)

  • 修正: アクション ボタンで使用されるコントロール ウィジェットでは、無効およびプライバシー保護されたコントロール状態が正しくレンダリングされません。(125867980)

  • 修正: コントロール ウィジェットのラベル ビューが環境から編集理由を読み取れない場合があります。(126232534)

  • 修正:コントロール センター、ロック画面、アクション ボタンのコントロール ウィジェットには修飾子が効きません。(126862283)promptsForUserConfiguration()

  • 修正: ControlCenter.currentConfigurations に構成されたコントロール プッシュ トークンが含まれません。(127601613)

  • 修正: コントロール テンプレートのビルド時に、「テンプレート要求が失敗しました: WidgetKit.ChronoError.AppIntent.conversionFailure(underlyingError: AppIntent に 'timerName' のパラメーター値がありません」というエラーが発生する場合があります。ユーザーは、@Parameter の初期化子で既定値を設定するか、クエリで既定のメソッドを使用する必要があります。(129066701)

  • 修正: ControlWidgetButton および ControlWidgetToggle を使用するウィジェット拡張機能は、Xcode 16 ベータ 4 以前からビルドすると、iOS 18 ベータ 5 以降でクラッシュします。(130760581)

既知の問題

  • サブタイトルと値の両方を指定するコントロール ウィジェットの場合、コントロール センターにはサブタイトルのみが表示されます。(127906735)

  • アプリ拡張機能のバンドルから読み込まれる ControlWidgetConfiguration で使用される画像は、シンボル効果のコンテンツ遷移を使用すると不具合が発生する可能性があります。(131789007)

    回避策:イメージに .contentTransition(.identity) ビュー修飾子を適用します。

ウィジェット

解決された問題

  • 修正: RTL のホーム画面でウィジェットのサイズを変更すると、期待どおりに動作しない場合があります。(128625613)

  • 修正: アップデート直後にホーム画面の色付けを有効にすると、システムによって自動的に再読み込みされるまでウィジェットの背景色が誤って表示される場合があります。(128701638)

廃止予定

  • 従来の Today View 拡張機能は iOS 18 で削除されます。(116246167)

Wi-Fi通話

解決された問題

  • 修正: T-Mobile ユーザーは、同じ iCloud アカウントにサインインしているセカンダリ デバイスで Wi-Fi 通話を開始/受信できなくなります。(130227345)

#

原点回帰

そーだいさんの書いたこの記事に刺激をもらった。 モバイルとバックエンドが近いというだけでなく、 なりたい明確な人物像を演じることが必要だ。

理想の自分を演じることで、理想に近づく

メンターあるいはメンタルコーチはいるか。 疑うことを恐れていないか。 コンフォートゾーンで安楽し、hungry精神を忘れていないか。

公立の中高で、場当たり的な受験英語を習って、それが役に立たず人生に活かせなかった悔しさ。

極めて再現性の低い不具合を対処したこと。また、その機会を与えてくださった方々への感謝。

Swiftで今も多用されているクロージャ (Closures)が原因で、循環参照(retain cycle)が生じてメモリリークや不安定な挙動に繋がっていた経験。

フルマラソンで4時間を切れない現実。

倫理観の問題定義、脳死は人の死か、受精卵は人の始まりか、この定義には臓器移植や再生医療などの莫大なビジネスが介在している事実。

自分の行いで結果が大きく変わる。理想の人物に近づく勇気を持っておくこと。

後悔なき人生とコミュニティなど不思議な縁のために。

シンプルなWatchOSアプリを作る

WatchOS用のミニアプリを作る、そのアプリでリューズの回転の使い方も解説します 今回はゼロから新しいアプリを作りたいと思います。

これから作るアプリのスクリーンショット

SwiftUIで実装しています。WatchOSでは、iOSなどと比較し使用できるフレームワークやOSSに成約があるため注意が必要です。

このアプリは、ユーザーが今日食べるべき果物を提案し、もしそれが気に入らない場合は、ボタンをクリックすることで果物を変更するできます。 また、回転するCrownでフルーツの文字サイズを変更できます。

設計

最初に、いくつかの果物を含む配列を定義する必要があります。

@State var fruits = ["🍎 Apple", "🍒 Cherries", "🍓 Strawberry", "🥭 Mango"]

今のところはこれで十分です。(@State アノテーションを追加することを忘れないでください。 これは、この変数が後で変更される可能性があることを意味します)

フルーツを表示してランダムに変化させる

では、今日の果物を表示し、毎ターンランダムに果物が手に入るようにしましょう。

img

var body: some View {
        VStack{
            Text(fruits[0])
                .font(.system(size: 20))
        }
        .padding()
        .onAppear{
            fruits.shuffle()
        }
}

VerticalStackを作成し、それをText要素に入れ、その中にfruits配列の最初の要素を入れています。そして、UIが表示されるたびに配列をシャッフルしています。

ボタンとフッターテキストの追加

同じように、新しい果物をランダムに生成するためのボタンを追加して、デザインを少し美しくしてみましょう。

var body: some View {
        VStack{
            Text(fruits[0])
                .font(.system(size: 20))
            Spacer()
            Button("Random"){
                fruits.shuffle()
            }
            Spacer()
            Divider()
            Spacer()
            Text("Rotate the digital crown to change text size")
                .font(.footnote)
                .multilineTextAlignment(.center)
        }
        .padding()
        .onAppear{
            fruits.shuffle()
        }
    }

私たちのデザインは完成しました。あとは、約束した機能を確実に実現していきます。

機能性

リューズを回転させるトリガーとなるシンプルなシステムを追加する必要があります。これは、私たちが決めた範囲での回転量を指します。

@State var scrollAmount = 10.0

この変数はアプリ内のテキストのサイズを意味します。

Text(fruits[0]).font(.system(size: scrollAmount))

.focusable().digitalCrownRotation($scrollAmount) のコードを VStack に追加します。 (フォーカス可能であることは重要です。これなしではコードは機能しません)

VStack{
    // Our design
}
.focusable()
.digitalCrownRotation($scrollAmount)

これでリューズの回転量の値が分かりました。 しかし、範囲の最小値、最大値、増加量がないという問題がまだあります。 関数に次のようなパラメータを渡します。

VStack{
    // Our design
}
.focusable()
.digitalCrownRotation($scrollAmount, from: 10, through: 20, by:1, isContinuous: false)

最小値、最大値、増加量を決定しました。 WatchOSアプリではテキストが小さすぎたり大きすぎたりするのは適切ではないため、これは重要です。 それらを制限する必要があります。

最終的なコード

すべてのソースコードは下記をご覧ください。

import SwiftUI

struct ContentView: View {
    @State var fruits = ["🍎 Apple", "🍒 Cherries", "🍓 Strawberry", "🥭 Mango"]
    @State var scrollAmount = 14.0
    var body: some View {
        VStack{
            Text(fruits[0])
                .font(.system(size: scrollAmount))
            Spacer()
            Button("Random"){
                fruits.shuffle()
            }
            Spacer()
            Divider()
            Spacer()
            Text("Rotate the digital crown to change text size")
                .font(.footnote)
                .multilineTextAlignment(.center)
        }
        .padding()
        .focusable()
        .digitalCrownRotation($scrollAmount, from: 10, through: 20, by:1, isContinuous: false)
        .onAppear{
            fruits.shuffle()
        }
    }
}

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

動作

現状、日本では、WatchOS用のアプリケーションが諸外国と比較し少ない状況が続いています。 しかし、YAMAPなどWatchOSの制約に負けず高度なUIを実現したアプリは、 WatchOSならではの機能を発揮しています。

yamap.com

一度、WatchOSの可能性を検討してはいかがでしょうか。

テスト駆動開発で確実なロジックを設計、実装するための考え方

AndroidとiOSで、同一機能のネイティブアプリを開発する場合、AndroidとiOSのロジック(アーキテクチャのModel)は一致している必要があります。


アジャイル開発であっても、単体テストは、確実に漏れなく確認します。

正解はドキュメントでは無く、ロジックを確認できるテストコードです。


アーキテクチャがMVVMでもMVPでも、Android とiOSで共通のロジック(Model)が、実装されていなければ、同じ動作を担保できません。 
そのためには、Android側でJUnitを用いたテストコード、iOSでXCTestを用いたテストコード、詳細設計レベルのドキュメント、テスト仕様書をすることが必要です。


現在までにさまざまな開発支援ツールで、 - コードからドキュメントを生成するツール - ドキュメントからコードを生成するツール が、ありましたが、信頼できるものに出会うことは無かったです。それらのツールが生成したコードとドキュメントを人間が問題ないか確認する手間が負担となるためです。

この負担を減らしたくても、ツールの成果物が問題ないか確認する手間は、人間がテストコードを書くよりも信頼できるものはないです。 また、人間であれば、テストコードを書く時点で、仕様の抜け、漏れに気づくことが出来ます。 そして、テストができないコードを書いてしまうミスもなくせます。   ユニットテストは難しいものと考えないでください。   単純な、足し算を行うファンクションのテストコードの、例として、2+3を計算して、結果に5が戻り値になるか、サンプルコードを示します。   Swift、Kotlin、まだAndroidでJavaが使われているプロダクトがあるようなので、Javaのテストコードについても、サンプルコードを示します。  

Swiftで XCTestを使ったユニットテストのコード

 

1. ロジックのコード(Calculator.swift)

class Calculator {
    func add(_ a: Int, _ b: Int) -> Int {
        return a + b
    }
}


2. ユニットテストのコード(CalculatorTests.swift)

import XCTest

@testable import YourAppName
class CalculatorTests: XCTestCase {
    var calculator: Calculator!
    override func setUp() {
        super.setUp()
        calculator = Calculator()
    }

    override func tearDown() {
        calculator = nil
        super.tearDown()
    } 
 
    func testAddition() {
        let result = calculator.add(2, 3)
        XCTAssertEqual(result, 5, "Expected 2 + 3 to equal 5")
    }
}

ポイント

setUp でテスト対象オブジェクトを初期化し、tearDown でクリーンアップします。

XCTAssertEqual を使って、計算結果が期待通りであるかを検証します。

Android(Kotlinの場合)


Androidでは、JUnitとMockitoなどを使用してユニットテストを実行します。こちらも同じように、簡単な加算機能のユニットテストを見てみましょう。  


1. ロジックのコード(Calculator.kt)

class Calculator {
    fun add(a: Int, b: Int): Int {
        return a + b
    }
}


2. ユニットテストのコード(CalculatorTest.kt)


import org.junit.Assert.*
import org.junit.Before
import org.junit.Test

class CalculatorTest {
    private lateinit var calculator: Calculator

    @Before
    fun setUp() {
        calculator = Calculator()
    }

    @Test
    fun testAddition() {
        val result = calculator.add(2, 3)
        assertEquals(5, result)
    }
}

ポイント:

@Before アノテーションを使って、テスト前に必要なセットアップを行います。

assertEquals を使って、期待する結果と実際の結果を比較します。

Android(javaの場合)

1. ロジックのコード(Calculator.java)

public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }
}


2. ユニットテストのコード(CalculatorTest.java)

import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;

public class CalculatorTest {
    private Calculator calculator;
    @Before
    public void setUp() throws Exception {
        calculator = new Calculator();
    }

    @Test
    public void testAddition() {
        int result = calculator.add(2, 3);
        assertEquals(5, result);
    }
}

  ポイント:

@Before アノテーションで、各テストメソッドの実行前に setUp メソッドが呼ばれ、Calculator インスタンスを初期化します。

assertEquals を使用して、計算結果が期待通りであることを検証します。


Javaを使ったAndroidのユニットテストでは、JUnitを使い、Kotlinの時と同様にロジックの検証が可能です。

every one Happy Cording!