20200920のiOSに関する記事は13件です。

[Swift] protocol制約をかけた型で"Cannot use mutating member on immutable value"と言うエラーが出る場合の対処。

swift5で次のコードを実行すると

Cannot use mutating member on immutable value: 'hoge' is a 'let' constant

と言うエラーが出ます。これにしばらくハマってしまったので解決方法を書いておきます。

protocol Hoge{
    var items:[String]{get set}
}

class Fuga:Hoge{
    var items: [String]
    init(_ items: [String]){
        self.items = items
    }
}

class Piyo:Hoge{
    var items: [String]
    init(_ items: [String]){
        self.items = items
    }
}

var hoges:[Hoge] = [Fuga(["a"]), Piyo(["a"]), Fuga(["a"])]
hoges.forEach{ (hoge: Hoge) in
    hoge.items.append("b")          //エラー:Cannot use mutating member on immutable value: 'hoge' is a 'let' constant
}

print(hoges.map{$0.items})

items{get set}で宣言しており、問題はないように見えますが、エラーではhogeが定数だと言っています。forEach内で変更しているのが問題なわけでもなく、実際次のコードはすんなり動きます。

var hoges:[Fuga] = [Fuga(["a"]), Fuga(["a"]), Fuga(["a"])]
hoges.forEach{ (hoge: Fuga) in
    hoge.items.append("b")
}

このエラーの原因はprotocolに準拠した型がclassstructか分からないことです。structは基本的に不変なので、もしもHogeに準拠した型がstructだった場合変更ができなくなってしまいます。

ということで、対応にはprotocolclassの制約をかけてあげることです。

protocol Hoge:class{           //ここが大事!!!!
    var items:[String]{get set}
}

class Fuga:Hoge{
    var items: [String]
    init(_ items: [String]){
        self.items = items
    }
}

class Piyo:Hoge{
    var items: [String]
    init(_ items: [String]){
        self.items = items
    }
}

var hoges:[Hoge] = [Fuga(["a"]), Piyo(["a"]), Fuga(["a"])]
hoges.forEach{ (hoge: Hoge) in
    hoge.items.append("b")
}

print(hoges.map{$0.items})

以上です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DockerでReact Native(TypeScript)+Expoのプロジェクト構築

まえおき

React Native+Expoで構成されたプロジェクトのDockerコンテナをMac OS X上に構築する手順を記載しています。

各端末の情報

  • PC

    • Mac OS Catalina Ver.10.15.6
    • docker version 19.03.12, build 48a66213fe
    • docker-compose version 1.26.2, build eefe0d31
  • iPhone

    • iPhone XR
    • iOS:13.7

ExpoClientで動作検証済みの端末

  • iPhone(iOS:13.7)

前提

  • docker, docker-compose導入済み

手順

1. Expoアカウントを作成します

Expoアカウントの作成方法

2. Expoクライアントアプリのインストールとセットアップをおこないます。

iPhoneでExpoクライアントアプリのインストールとセットアップ方法

3. Docker環境を構築します

ファイル構成

root
└── docker
    └── react_native
        └── dockerfile
└── docker-compose.yml
└── .env

docker/react_native/dockerfile

FROM node:14-alpine

WORKDIR /usr/src/app/

RUN apk update && apk add bash

RUN yarn global add expo-cli

docker-compose.yml

version: "3"
services:
  react_native:
    build: ./docker/react_native
    volumes:
      - ./react_native/:/usr/src/app
    env_file: .env
    command: yarn start
    ports:
      - "19000:19000"
      - "19001:19001"
      - "19002:19002"

.env

Expoを利用する各端末のIPなどを設定する必要があります。

  • ADB_IP
    • 検証端末のIPアドレスを指定してください。カンマ区切りで複数指定可能なようです。
  • REACT_NATIVE_PACKAGER_HOSTNAME
    • Dockerコンテナ可動端末のIPアドレス
ADB_IP=192.168.0.10,192.168.0.11,...
REACT_NATIVE_PACKAGER_HOSTNAME=192.168.0.2

4. Dockerコンテナをビルドします

docker-compose build

5. Dockerコンテナへ接続します

docker-compose run --rm react_native bash --login

6. expoプロジェクトを作成します

expo init .

7. プロジェクトテンプレートを選択するとプロジェクトのセットアップが開始されます

わたしは[blank (TypeScript)]を選択しました。

? Choose a template: (Use arrow keys)
  ----- Managed workflow -----
  blank                 a minimal app as clean as an empty canvas
❯ blank (TypeScript)    same as blank but with TypeScript configuration
  tabs                  several example screens and tabs using react-navigation
  ----- Bare workflow -----
  minimal               bare and minimal, just the essentials to get you started
  minimal (TypeScript)  same as minimal but with TypeScript configuration

8. セットアップが完了したらコンテナから抜けます

9. Dockerコンテナを起動します

docker-compose up

10. 表示されたQRコードを検証端末上で読み取ります

スクリーンショット 2020-09-20 20.16.22.png

11. 検証端末でExpo Clientアプリが起動しREACTの画面が表示されます

スクリーンショット 2020-09-20 21.31.10.png

12. react_native/App.tsxを更新すると・・・

react_native/App.tsxのファイル内に記述された表示テキストの末尾に☺️を追加してファイルを更新します。

スクリーンショット 2020-09-20 20.22.23.png

13. 更新した内容が検証端末へ自動的に反映されます

ホットリロードによって末尾の☺️がiPhone上の検証画面へ自動的に反映されます。

スクリーンショット 2020-09-20 20.24.19.png

参考

DockerでReact Native環境作成から、Expo Clientで実機確認するまで
WSLでReact Native + Expo環境を作ろう
DockerでExpo / React Nativeを実行する

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iPhoneでExpo Clientのインストールとセットアップ

まえおき

React Nativeの開発支援サービスExpoの検証用クライアントアプリケーションのiPhoneでのインストールとセットアップ方法を記載しています。

EXPOアカウントの登録手順

別の記事に手順を掲載しています。
Expoアカウントの作成方法

手順

  1. AppStoreで「expo client」を検索し、ダウンロードします

    スクリーンショット 2020-09-20 20.54.59.png

  2. ダウンロードが完了したら[開く]をタップします

    スクリーンショット 2020-09-20 21.00.04.png

  3. アプリが起動したら[Sign in to your account]をタップします。

    スクリーンショット 2020-09-20 21.01.24.png

  4. ユーザ名(またはメールアドレス)とパスワードを入力して[Sign In]をタップします

    スクリーンショット 2020-09-20 21.02.17.png

  5. プロフィール画面が表示されたらセットアップ完了です。

    スクリーンショット 2020-09-20 21.07.53.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UIAlertViewのようにいつでもどこでも必ず表示されるアラートを実現

問題点

今更ながらUIAlertViewがdeprecatedになった警告に対応しました。

'UIAlertView' is deprecated: first deprecated in iOS 9.0 - UIAlertView is deprecated.

という警告ですね。

どう変えればいいかはググればいっぱい出てくるので割愛しますが、問題点は・・・

  • 表示対象のUIViewControllerが必要。
  • 二つのUIViewControllerを一つのUIViewController常にpresentViewControllerできない。

という問題です。

例えば、どこかのUIViewController内で表示してるのであれば、

    UIAlertController *alert = [UIAlertController alertControllerWithTitle: title
                                        message: message
                                 preferredStyle: UIAlertControllerStyleAlert];

    UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK"
                             style: UIAlertActionStyleDefault
                           handler: handler];
    [alert addAction: ok];
    [self presentViewController:alert animated:YES completion:nil];

といった感じで表示できますが、昔のUIAlertViewはどこからでも表示できたので、例えばModelの中などでも使用されてたり、UIViewControllerが取得できないdelegateの中で使用されてたりして困りました。

そこでAPPからrootControllerを取得してそこに表示すればええやん!ってことでやってみました。

UIViewController *rootController = [[[[UIApplication sharedApplication]delegate] window] rootViewController];
[rootController presentViewController:alert animated:YES completion:nil];

こういう感じですね。これで表示はされるのですが、同じくUIPopoverControllerも同じpresentViewController:alertを使って表示される仕組みに変わっていて、それがrootControllerに表示された状態同じようにアラートを出そうとすると

Warning: Attempt to present <UIAlertController ....> ... which is already presenting

のような警告がでて無視されちゃうんですね。Modelの中で色々使いまわされてるので、どんなシチュエーションでも必ず表示されるアラートが欲しい!というわけで色々試した結果いけそうなのができたので共有します。

解決策

    UIAlertController *alert = [UIAlertController alertControllerWithTitle: title
                                        message: message
                                 preferredStyle: UIAlertControllerStyleAlert];

    UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK"
                             style: UIAlertActionStyleDefault
                           handler: nil];
    [alert addAction: ok];

    UIViewController *rootController = [[[[UIApplication sharedApplication]delegate] window] rootViewController];
    if(rootController.presentedViewController != nil){
        [rootController.presentedViewController presentViewController:alert animated:YES completion:nil];
    } else {
        [rootController presentViewController:alert animated:YES completion:nil];
    }

まあ、単純な話ですが、既にpresentedViewControllerがあったらそこに表示、なければrootに表示するだけです。

みんな大好きStackOverFlowで見つけました。サイトはSwiftのコードですね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

大規模なiOSアプリ開発を2年以上継続して得られた知見の共有

前書き

それなりに大規模なアプリの新規開発〜機能追加を行う中で得られた知見をまとめます。

アプリのジャンル/ライフサイクル、チームメンバーのスキルレベルなどによって適用できない事項もあるかと思いますが、一つの事例として参考にしていただければ幸いです。

<アプリ/チームの概要>

  • iOS版開発チームとしては最小4人〜最大9人。
    • その他、Androidチーム、バックエンドチーム、デザインチーム…などなど諸々合わせて総勢20人〜30人
  • アプリの累計ダウンロード数は数百万。
  • App Store上のカテゴリは「ファイナンス」。
  • リリースサイクル(計画リリース)は平均で2ヶ月に1回。
  • 開発環境はXcode + Swift。
  • Scrumで開発。

本文・コメント含め、これ以上に具体的なことは書けませんのでご了承ください。
本記事の内容は内容はあくまで私個人の見解であり、所属企業における立場、戦略、意見を代表するものではありません。

UI構築

ポリシー

  • 一時期はStoryboardと、コードベース・レイアウトが混在していた時期もありましたが、現在ではコードベース・レイアウトのみに統一しました。
  • 理由は以下のようなStoryboardのデメリットを感じることが多くなってきたためです。
    • 人数が多いとStoryboardのconflictが多く、その解消がとにかく面倒臭い。
    • Storyboardでは、画面修正のレビューが辛い。
    • アプリ規模が大きくなるにつれ、Xcode上でStoryboardを開く時の待ち時間が長くなってしまった。
    • デザイナーからのUI/UX要求レベルが上がってきて、画面の状態が複雑になってきた。
      • 例えば、ローディングプレースホルダを表示しつつ裏でAPI通信>取得成功時は通常View、エラー時はエラー用の特殊なView、など。。。
      • Storyboardでは静的な状態はプレビューできるが、上のような動的な状態変化が多いと意味がない。
    • Storyboardでは、フォント、色など、アプリの統一ポリシーを適用し忘れることがしばしばある。
  • ただし、Unwind Segueは便利なので、画面遷移はStoryboardを使っています。
  • コードベース・レイアウトを容易にするために、自作ライブラリを構築しました(productionコードなので公開はできません)。

参考リンク:
iOSアプリケーションでコードベースのレイアウトを積極利用する
[Xcode] [Swift] 実務的Tips: Unwind Segueで2つ以上前の画面に一気に戻って画面を再更新する

評価

  • コードベース・レイアウト統一に至るまでに紆余曲折はありましたが、それが生産性・品質・保守性ともにベストな方法である、と評価しています。
  • ただし、画面遷移のみStoryboardに依存している状態はあまり「見通し」がよくないので、改善の余地がありそうです。

アーキテクチャー・パターン

ポリシー

  • 当初は標準的なCocoa MVCで作っていました。当然FatViewController化しました。
  • アプリの規模が大きくなり、またエンハンスメントを重ねるごとに改修が困難になってきました。
  • このため、MVVMへのリアーキテクチャーを進めました。
    • 一気に行わず、新規機能や大規模改修に合わせて実施。
    • ライブラリは使わず、設計パターンだけを適用。
  • MVVMアーキテクチャーを選定した理由:
    • Clean Architectureなどの複雑なアーキテクチャーよりも、MVVMへの変更の方が改修規模が小さかったため。
    • メンバーのスキルレベルに差があり、MVVMより複雑なアーキテクチャーを全員が習熟することは困難であったため。

(具体的な実装例は追って別記事を投稿する予定です。)

評価

  • 保守性・拡張性が上がったと評価しており、今後も継続する予定です。

ライブラリ管理

ポリシー

評価

  • ライブラリに起因するトラブルは開発計画を大きく狂わせるので、今後も必要最小限に止める方針に変わりないと思います。
  • Carthageについては、2020年9月現在でXcode 12でビルドエラーになるというクリティカルな問題が発生しているので、CocoaPodsに近日中に乗り換えるかもしれません。。。
  • 大規模アプリにおいては、ライブラリ管理ツール、導入ライブラリ共に、その選定は慎重にならざるを得ないです。

コードレビュー

ポリシー

  • IBM Cloud上にGitLabを導入しました。
  • コードレビューは99.9%実施しています。
  • GitLabのマージリクエスト上でレビューコメントをやりとりするスタイルです。
  • レビューアーは原則として複数人としています。
    • 一次レビューはメンバー
    • 最終レビューはリーダー
  • コードレビューの目的は以下の通りと宣言しており、その観点で気になったことがあればレビューコメントを書くようにしています。
    • システムのメンテナンス性、リーダビリティ、理解のしやすさを改善すること。
    • ブラックボックステストでは検出しづらい不具合(例:メモリーリーク)を発見すること。
    • 知識を共有すること。
  • 一応、コーディングガイドラインはありますが項目は最低限です。
    • 「強制アンラップは理由がない限りは使わないようにしよう」「インデントは合わせよう」「Xcodeの設定を合わせよう」程度です。
    • 私見ですが、ガチガチに縛ろうとして規約を増やしたところで、読むことが大変になるだけで、完璧に守ることは困難です。
    • 規約で縛るよりも、上のような「目的」を共有することの方が大事では、と考えます。

参考リンク:
[Xcode] 実務的Tips: チーム内でXcodeの設定項目を合わせて不要な修正差分が出ないようにする

評価

  • 品質・保守性には大きな効果が認められ、コードレビューを行わないという選択肢は今後もありません。
  • 以下の点は要改善ポイントです。
    • リーダーの負荷が高いこと(レビューに追われて自分の担当分の実装時間が削られる)。
    • リーダーがボトルネックになること。
      • リーダーが不在だとマージできない。
      • 先行タスクのマージリクエストがレビュー未完了だと後続作業が滞る。

テスト

ポリシー

  • 1年ぐらい、XCUITestによるテストの自動化に取り組みました。→詳細は「参考リンク」の記事を参照
  • しかしながら、機能改修時のメンテナンスコストがあまりにも大きかったです。
    • コード修正は1時間でも、既存のテストの修正に半日以上かかることもザラ。。。
  • このため、現在では以下のような手法を取っています。
    • ロジック部分のテストはXCTest。
    • UI部分のテストは実動作で確認。
    • APIについては、Node.jsベースのスタブツール(ローカルサーバー)を自作し、正常系/異常系レスポンスのテストを行う。
  • 以上は開発チームとしてのテストで、業務観点での総合テストは別途QAチームがテストシナリオに即して行う。

参考リンク:
XcodeのUIテストフレームワーク「XCUITest」のTips

評価

  • 私たちのプロダクトではUIの改変が多いため、XCUITestは費用対効果の観点で合いませんでした。
  • MVVMパターンへのリアーキテクチャーとの「合わせ技」で、なるべくView/ViewControllerには画面表示以外のロジックは書かないようにし、ViewModelのXCTestを増やすように取り組んでいるところです。

CI/CD

ポリシー

  • 以下の目的で、CI/CDを取り入れています。
    • Sprintの途中であっても、マージされた機能はいち早くQAエンジニアに渡してテストしてもらいたい。
    • あるいは、オーナーやデザイナーに動かしてもらい、フィードバックしてもらいたい。
  • 現状は、JenkinsでGitLabのブランチを監視して、fastlaneをキックしてビルドを走らせ、TestFlightにアップロードしています。
  • テストは自動で走らせるものの、失敗はSlackに自動postするだけで、デプロイは止めません。
    • 緊急のバグ修正時などはテストコードの修正は後回しにするケースもあるので…

評価

  • アプリの規模が大きくなるに応じてビルド時間が長くなるので、大規模アプリでは自動デプロイは必須です。

後書き

  • DX時代が到来し、各企業とも顧客とのエンゲージメント向上のためにスマホアプリを活用する例は多く、ライバルに遅れを取らないためには高・多機能なアプリを早いサイクルでリリースすることが求められています。
  • しかしながら、OSも開発環境も絶えず進化している中で、大規模なアプリを、迅速かつトラブルなくリリースし続けることは容易ではありません。
  • それを成し遂げるのためには「完璧な手法をじっくり作り上げること」ではなく「早いサイクルで小さい改善を積み重ねること」と考えています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

大規模なiOSアプリ開発を2年以上継続して得られた知見

前書き

それなりに大規模なアプリの新規開発〜機能追加を行う中で得られた知見をまとめます。

アプリのジャンル/ライフサイクル、チームメンバーのスキルレベルなどによって適用できない事項もあるかと思いますが、一つの事例として参考にしていただければ幸いです。

<アプリ/チームの概要>

  • iOS版開発チームとしては最小4人〜最大9人。
    • その他、Androidチーム、バックエンドチーム、デザインチーム…などなど諸々合わせて総勢20人〜30人
  • アプリの累計ダウンロード数は数百万。
  • App Store上のカテゴリは「ファイナンス」。
  • リリースサイクル(計画リリース)は平均で2ヶ月に1回。
  • 開発環境はXcode + Swift。
  • Scrumで開発。

本文・コメント含め、これ以上に具体的なことは書けませんのでご了承ください。
本記事の内容は内容はあくまで私個人の見解であり、所属企業における立場、戦略、意見を代表するものではありません。

UI構築

ポリシー

  • 一時期はStoryboardと、コードベース・レイアウトが混在していた時期もありましたが、現在ではコードベース・レイアウトのみに統一しました。
  • 理由は以下のようなStoryboardのデメリットを感じることが多くなってきたためです。
    • 人数が多いとStoryboardのconflictが多く、その解消がとにかく面倒臭い。
    • Storyboardでは、画面修正のレビューが辛い。
    • アプリ規模が大きくなるにつれ、Xcode上でStoryboardを開く時の待ち時間が長くなってしまった。
    • デザイナーからのUI/UX要求レベルが上がってきて、画面の状態が複雑になってきた。
      • 例えば、ローディングプレースホルダを表示しつつ裏でAPI通信>取得成功時は通常View、エラー時は特殊なView、など。。。
      • Storyboardでは静的な状態はプレビューできるが、上のような動的な状態変化が多いと意味がない。
    • Storyboardでは、フォント、色など、アプリの統一ポリシーを適用し忘れることがしばしばある。
  • ただし、Unwind Segueは便利なので、画面遷移はStoryboardを使っています。
  • コードベース・レイアウトを容易にするために、自作ライブラリを構築しました(productionコードなので公開はできません)。

参考リンク:
iOSアプリケーションでコードベースのレイアウトを積極利用する
[Xcode] [Swift] 実務的Tips: Unwind Segueで2つ以上前の画面に一気に戻って画面を再更新する

評価

  • コードベース・レイアウト統一に至るまでに紆余曲折はありましたが、私たちのアプリではコードベース・レイアウトが生産性・品質・保守性ともにベストな方法である、と評価しています。
  • ただし、画面遷移のみStoryboardに依存している状態はあまり「見通し」がよくないので、改善の余地がありそうです。

アーキテクチャー・パターン

ポリシー

  • 当初は標準的なCocoa MVCで作っていました。当然FatViewController化しました。
  • アプリの規模が大きくなり、またエンハンスメントを重ねるごとに改修が困難になってきました。
  • このため、MVVMへのリアーキテクチャーを進めました。
    • 一気に行わず、新規機能や大規模改修に合わせて実施。
    • ライブラリは使わず、設計パターンだけを適用。
  • MVVMアーキテクチャーを選定した理由:
    • Clean Architectureなどの複雑なアーキテクチャーよりも、MVVMへの変更の方が改修規模が小さかったため。
    • メンバーのスキルレベルに差があり、MVVMより複雑なアーキテクチャーを全員が習熟することは困難であったため。

(具体的な実装例は追って別記事を投稿する予定です。)

評価

  • 保守性・拡張性が上がったと評価しており、今後も継続する予定です。

ライブラリ管理

ポリシー

評価

  • ライブラリに起因するトラブルは開発計画を大きく狂わせるので、今後も必要最小限に止める方針に変わりないと思います。
  • Carthageについては、2020年9月現在でXcode 12でビルドエラーになるというクリティカルな問題が発生しているので、CocoaPodsに近日中に乗り換えるかもしれません。。。
  • 大規模アプリにおいては、ライブラリ管理ツール、導入ライブラリ共に、その選定は慎重にならざるを得ないです。

コードレビュー

ポリシー

  • IBM Cloud上にGitLabを導入しました。
  • コードレビューは99.9%実施しています。
  • GitLabのマージリクエスト上でレビューコメントをやりとりするスタイルです。
  • レビューアーは原則として複数人としています。
    • 一次レビューはメンバー
    • 最終レビューはリーダー
  • コードレビューの目的は以下の通りと宣言しており、その観点で気になったことがあればレビューコメントを書くようにしています。
    • システムのメンテナンス性、リーダビリティ、理解のしやすさを改善すること。
    • ブラックボックステストでは検出しづらい不具合(例:メモリーリーク)を発見すること。
    • 知識を共有すること。
  • 一応、コーディングガイドラインはありますが項目は最低限です。
    • 「強制アンラップは理由がない限りは使わないようにしよう」「インデントは合わせよう」「Xcodeの設定を合わせよう」程度です。
    • 私見ですが、ガチガチに縛ろうとして規約を増やしたところで、読むことが大変になるだけで、完璧に守ることは困難です。
    • 規約で縛るよりも、上のような「目的」を共有することの方が大事では、と考えます。

参考リンク:
[Xcode] 実務的Tips: チーム内でXcodeの設定項目を合わせて不要な修正差分が出ないようにする

評価

  • 品質・保守性には大きな効果が認められ、コードレビューを行わないという選択肢は今後もありません。
  • 以下の点は要改善ポイントです。
    • リーダーの負荷が高いこと(レビューに追われて自分の担当分の実装時間が削られる)。
    • リーダーがボトルネックになること。
      • リーダーが不在だとマージできない。
      • 先行タスクのマージリクエストがレビュー未完了だと後続作業が滞る。

テスト

ポリシー

  • 1年ぐらい、XCUITestによるテストの自動化に取り組みました。→詳細は「参考リンク」の記事を参照
  • しかしながら、機能改修時のメンテナンスコストがあまりにも大きかったです。
    • コード修正は1時間でも、既存のテストの修正に半日以上かかることもザラ。。。
  • このため、現在では以下のような手法を取っています。
    • ロジック部分のテストはXCTest。
    • UI部分のテストは実動作で確認。
    • APIについては、Node.jsベースのスタブツール(ローカルサーバー)を自作し、正常系/異常系レスポンスのテストを行う。
  • 以上は開発チームとしてのテストで、業務観点での総合テストは別途QAチームがテストシナリオに即して行う。

参考リンク:
XcodeのUIテストフレームワーク「XCUITest」のTips

評価

  • 私たちのプロダクトではUIの改変が多いため、XCUITestは費用対効果の観点で合いませんでした。
  • MVVMパターンへのリアーキテクチャーとの「合わせ技」で、なるべくView/ViewControllerには画面表示以外のロジックは書かないようにし、ViewModelのXCTestを増やすように取り組んでいるところです。

CI/CD

ポリシー

  • 以下の目的で、CI/CDを取り入れています。
    • Sprintの途中であっても、マージされた機能はいち早くQAエンジニアに渡してテストしてもらいたい。
    • あるいは、オーナーやデザイナーに動かしてもらい、フィードバックしてもらいたい。
  • 現状は、JenkinsでGitLabのブランチを監視して、fastlaneをキックしてビルドを走らせ、TestFlightにアップロードしています。
  • テストは自動で走らせるものの、失敗はSlackに自動postするだけで、デプロイは止めません。
    • 緊急のバグ修正時などはテストコードの修正は後回しにするケースもあるので…

評価

  • アプリの規模が大きくなるに応じてビルド時間が長くなるので、大規模アプリでは自動デプロイは必須です。

後書き

  • OSも開発環境も絶えず進化している中で、大規模なアプリを、迅速かつトラブルなくリリースし続けることは容易ではない、と感じます。
  • 「早いサイクルで小さい改善を積み重ねる」をモットーに、まだまだ模索を続けて行こうと考えています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ARCoachingOverlayViewでユーザーにデバイスをうごかしてもらって、ARKitに世界情報をあたえる

ARKitがWorldTrackingを確立するには、デバイスを動かして、ARKitに視点を与える必要があります。

ARCoachingOverlayViewでユーザーにガイダンスを出して、デバイスをうごかしてもらいます。

Sep-20-2020 14-12-53.gif

1、ARCoachingOverlayViewを初期化します。

let coachingOverlay = ARCoachingOverlayView()

ARCoachingOverlayViewの設定

coachingOverlay.goal = .anyPlane //情報を取る目標設定
// 可能な値
    case anyPlane
    case horizontalPlane
    case tracking
    case verticalPlane

coachingOverlay.activatesAutomatically = true //Tracking状態が不十分になると、再度コーチングするか

// セッションとデリゲートを設定
coachingOverlay.session = sceneView.session
coachingOverlay.delegate = self

// Viewとして扱う
coachingOverlay.frame = sceneView.bounds
sceneView.addSubview(coachingOverlay)

2、ARCoachingOverlayViewDelegateを設定

コーチングの状態によって呼ばれるDelegate functionは以下

func coachingOverlayViewWillActivate(_ coachingOverlayView: ARCoachingOverlayView) {
    // コーチングが表示される前に呼ばれる。ここでコーチング中操作できないButtonなどを非表示にする。
}

func coachingOverlayViewDidDeactivate(_ coachingOverlayView: ARCoachingOverlayView) {
    // コーチングが終了したあとに呼ばれる。ここでコーチング中操作できないButtonなどを再表示する。

}

これでARSessionをrunすると動くはずです。
必要な情報が得られたら、コーチングは消えます。
このステップをやったほうが、正確なワールドトラッキングが得られます。


Core MLを使ったアプリを作っています。
機械学習関連の情報を発信しています。

Twitter
MLBoysチャンネル
Medium

相棒
note

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOSDC 2020 前夜祭に参加しました。

概要

iOSDCに参加しました。
前夜祭の内容になっています。

少し遅れてしまい2つしか見ていないですがメモ程度に残します。

見たトークは

  • Call Directory Extension詳解
  • あなたの知らない連絡先の世界

です。

Call Directory Extension詳解

プロポーザルはこちら

  • Call Directory Extensionとは発信者名表示とか出せる機能
  • 黎明期の時はすごい発展したのに、最近はバグなどがあってもAppleが対応しないという悲壮感が面白い発表でした笑
  • Call Directory Extensionの利用の際にユーザー許可してもらうところの説明は丁寧にやるように気を付けるなど、実践者ならではの具体的なアドバイスがよかったです。
  • 息をするようにバグが出るみたいです

初めての情報がいっぱいで、実際に商用開発されている方ならではの話が聞けて面白かったです!

あなたの知らない連絡先の世界

プロポーザルはこちら
スライドはこちら

  • ミドルネームや3世などどういう風に連絡先に入るのか。サーバーに姓名だけ入れといて大丈夫?笑
  • 電話番号のバリデーションを数字だけにするとダメ!記号とか英語も使えるし、記号の使い方はiphoneユーザとしてもすごく勉強になったし面白かったです。
  • iOSはvCard形式で、連絡先の情報の構造の話がよかった
  • PersonNameComponentsFormatterを使うと人の名前の姓名の分割などができる。Foundationに入っているので気楽に使えると#askthespeakerでおっしゃってました。
  • 連絡先の履歴がiOS13から取得できるようになったとのこと、この機能はobjective-Cでしか使えず。裏番組もobjective-Cの話題だったので、iOSDCではなくobjective-C-DCだ!

発表がユーモアがあってすごく面白かったです Day2でも登壇されるとのことで期待!

まとめ

iOSちょっとかじったくらいでも面白かったです。
DAY1、DAY2も楽しみたい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

iOSDC 2020 メモ

Day 01

Track D - iOSには無いmacOS独自機能をCatalystで実装する @fromkk

3 メニュータイプ
* メニュー
* タッチバー
* ツールバー

サンプル

https://github.com/fromkk/CatalystSampler

動画:

https://www.youtube.com/watch?v=_7FfMCEBPiY&feature=youtu.be

Track B - 400種類のアプリを毎日ビルドする自動化の技術 @k_katsumi

ビルド・申請作業とは

ワークフロー関係者

Customer ・ Tantou ・ Engineer
Screen Shot 2020-09-20 at 11.33.02.png

Dependabot良いですね!
https://dependabot.com/

スライド

https://speakerdeck.com/kishikawakatsumi/400zhong-lei-falseapuriwomei-ri-birudosuruzi-dong-hua-falseji-shu

Track B - ファッション業界を技術で変える、ZOZOの挑戦〜CTOが語る理想の組織像とは〜 @kyuns

ご飯タイム

もうちょっと採用などの作戦とか聞きたかったな〜

Track B - デバッグメニューのメンテナンスが大変だったので、専用アプリを作りました @FromAtom

https://speakerdeck.com/fromatom/iosdc-japan-2020

App Groupsを利用してデータシェアする

供用のUserDefaultsを利用してDebugメニューアプリでコントロール

コツ

UIの実装は面倒、UIを生成コードで楽にする

サンプル

https://github.com/FromAtom/iosdc-2020-sample

意見
複数のアプリ結構便利そうだけど一つしかない場合Developerメニュー作成すべきかな
コード反対しているところミスったら結果は一緒と思って?

Track B - ベジェ曲線の知らない世界 @takoikatakotako

https://qiita.com/takoikatakotako/items/39e3d46dd9f7a700c0b3

ムズッ

Track B - GitHub ActionsでiOSアプリをCIする個人的ベストプラクティス @the_uhooi

https://speakerdeck.com/uhooi/iosdc-2020

CIのメリット
1. リポジトリーにエラーが含まれていないのを保証
2. 自動で何か実行できる(手間かからない)
3. 誰かのローカルに頼らない
4. 結果を簡単に確認できる!

デメリット
1. 学習コスト
2. 色々なサービスがユニークなワークフロー・書き方がある(CircleCI, Bitrise, GitHub Actions)

サンプル

https://github.com/uhooi/iOSDC2020-Talk-Sample

あとはGitHub Actionsライブコーディング!

┌|▼▼|┘ ┌|▼▼|┘ ┌|▼▼|┘ ┌|▼▼|┘ ┌|▼▼|┘

Track B - 効率よくUIKitからSwiftUIへ移行する @yhkaplan

Slides: https://speakerdeck.com/yhkaplan/migrating-from-uikit-to-swiftui-efficiently

YouTube (English): https://youtube.com/watch?v=kedKk96SXxA

YouTube (Japanese): https://youtube.com/watch?v=Mavk5AQAz7U

Source: https://github.com/yhkaplan/presentations/tree/main/2020/09/20

色々大変そうですね。。。

Architecture
1. Redux
2. The Composable Architecture
3. MVVM

Track A - LT

Group 1

Catalystに対応したアプリをリリースするまでのリジェクト集

https://speakerdeck.com/fromkk/iosdc-2020-lt

Apple Pencilと左利き対応

https://speakerdeck.com/kwzr/apple-penciltozuo-li-kidui-ying

DroidKaigiの公式アプリで始める_iOSアプリOSSコミッターへの道

https://speakerdeck.com/entaku/droidkaigifalsegong-shi-ahuriteshi-meru-iosahuriosskomitutahefalsedao

iOS Custom Keyboardsでできること/できないこと/やってはいけないこと

https://speakerdeck.com/kyome22/iosdc-japan-2020-lt
https://github.com/Kyome22/IronKeyboard

Group 2

Copyable PDF作るには

https://github.com/EndouMari/SampleScreenshot

あなたのアプリ、✨リブランディング✨できますか?

https://speakerdeck.com/monoqlo/iosdc2020

Day 02

Track B - Xcode PreviewでUIKit @kenmaz

https://speakerdeck.com/kenmaz/xcode-previews-deuikitbesufalseapurikai-fa-woxiao-lu-hua-suru-iosdc-japan-2020

iOS13未満切らないと使えないのでまだまだっか〜

二つの重要なポイント
1. UIViewRepresentable/UIViewControllerRepresentable
2. PreviewProvider

同時に多言語の画面確認できる?!

Screen Shot 2020-09-21 at 11.02.42.png

後で導入してみよう〜

Track D - iOSアプリ開発のためのThe Composable Architectureがすごく良いので紹介したい @yimajo

https://speakerdeck.com/yimajo/iosapurikai-fa-falsetamefalsethe-composable-architecturegasugokuliang-ifalsedeshao-jie-sitai

4 Important Points
1. State Mgmt
2. Composition
3. Side Effect
4. Testable

Parts
Screen Shot 2020-09-21 at 11.33.55.png

Flow
Screen Shot 2020-09-21 at 11.34.20.png

Track A - 大解剖!UIColorファミリー @S_Shimotori_pub

https://speakerdeck.com/s_shimotori/uicolor-anatomy
https://speakerdeck.com/s_shimotori/uicolor-cluster

UIColor 18サブクラスある!

Screen Shot 2020-09-21 at 13.41.17.png

Track E - SwiftのWebAssembly対応の軌跡 @kateinoigakukun

https://speakerdeck.com/kateinoigakukun/the-state-of-swift-webassembly
EiaiAvcUcAA6w3_.png

Optimize後 3.5MBまで持っていけてすごいな!

Track B - SwiftUI時代の Functional iOS Architecture @inamiy

後でゆっくり考えるw

Track E - Apple Silicon への長い道 @hak

omoroi

LT大会

参加できなかったトーク資料

4年間運用されて表示速度が低下した詳細画面を改善する過程で得た知見 @marty_suzuki

https://speakerdeck.com/martysuzuki/iosdc-japan-2020-day-1-track-b-10-50

Background Notificationで新聞紙面の大きい画像の自動ダウンロードを実現する @shimastriper

https://speakerdeck.com/shimastripe/background-notificationdexin-wen-zhi-mian-falseda-kiihua-xiang-falsezi-dong-daunrodowoshi-xian-suru?slide=4

そろそろCombine @shiz

スライド
https://speakerdeck.com/shiz/sorosorocombine

補足資料
https://github.com/stzn/CombineStudy

iPadOSでマウス・キーボード対応アプリを作る

https://speakerdeck.com/cc4966/ipados-app-using-pointer-and-keyboard

iOSではじめるWebAR

https://speakerdeck.com/ikkou/webar-in-ios

iPadOSDC: Multiple Windows

https://speakerdeck.com/hironytic/ipadosdc-multiple-windows

ConcurrencyWithGCD

https://speakerdeck.com/taka1068/concurrencywithgcd

SwiftでのConcurrent Map(並行処理map)の実装について

https://taka1068.hatenablog.jp/entry/2020/09/20/034600

iOSエンジニアだし、Androidアプリも作れるでしょ?

https://speakerdeck.com/akatsuki174/iosensiniatasi-androidahurimozuo-rerutesiyo

Migrate Swift 4.2 to 5.2

https://speakerdeck.com/shomasegi/migrate-swift-4-dot-2-to-5-dot-2

iOSリジェクト戦記

https://speakerdeck.com/hcrane/iosdc2020-iosriziekutozhan-ji

iOS のキーボードと文字入力のすべて

https://speakerdeck.com/niw/ios-falsekibodotowen-zi-ru-li-falsesubete

Webとネイティブアプリの付き合い方を改めて考える

https://speakerdeck.com/kiwi26/native-apps-and-web

SwiftUIを導入したアプリ設計

https://speakerdeck.com/yuta24/swiftuiwodao-ru-sitaapurishe-ji

実践!「みてね」における自動生成活用例

https://speakerdeck.com/ushisantoasobu/shi-jian-mitene-niokeruzi-dong-sheng-cheng-huo-yong-li

iOSアプリは「感情」を宿すのか?
AIとアプリの未来について

https://speakerdeck.com/yukinaga/iosapuriha-gan-qing-wosu-sufalseka-aitoapurifalsewei-lai-nituite

Swiftで始める静的解析

https://speakerdeck.com/matsuji/swiftdeshi-merujing-de-jie-xi

アプリのパフォーマンスを継続的に計測する

https://speakerdeck.com/kariad/apurifalsepahuomansuwoji-sok-de-niji-ce-suru

Micro Modular Architecture with Bazel

https://speakerdeck.com/ra1028/micro-modular-architecture-with-bazel

Synchronized iPhones, Again!

https://speakerdeck.com/toyship/synchronized-iphones-again

google/mediapipe で始めるARアプリ開発/iOSDC2020

https://speakerdeck.com/noppefoxwolf/iosdc2020

実装したくなる音声編集

https://speakerdeck.com/yoseiyamagishi/shi-zhuang-sitakunaruyin-sheng-bian-ji

テストコードが増えるとバグは減るのだろうか?

https://speakerdeck.com/ahiru/does-more-test-code-mean-fewer-bugs

良いリンク

https://consim.design/
https://dependabot.com/
https://dev.to/natterstefan/how-to-add-a-readme-to-your-github-profile-2bo9
https://qiita.com/SnowCait/items/7a30ff80be70a739915c

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

XCTSkipの使い方まとめ

はじめに

Xcode11.4からXCTestフレームワークに新しく導入されたプロパティの一つに「XCTSkip」があります。

XCTSkipを使用することで明示的に「スキップ」の結果を出力することができます。

特に統合テストにおいては、必要条件や依存関係が必ずと言っていいほどあるかと思います。
例えばアプリケーションがiPad特有の機能を持っている場合はiPhoneではテストできませんし古いOSでは利用できないAPIを用いる場合テスト対象は必然と絞られます。

そんな条件付きの実行が必要なテストを行う際に「XCTSkip」が活躍します。

中の実装は「こちら」をご参照ください。

なぜ「スキップ」があると良いのか?

以前まで(Xcode11.4より前)は下記の2択しかありませんでした。

  • テストを合格にする
  • テストを不合格にする

もし一部の条件下では必ずテストが成功するようにしていた場合、検証に合格していないプログラムが機能するということになりますし、テスト失敗とした場合は何が悪いのかの判断ができず無駄に時間を消費してしまいます。

XCTSkipを利用することでResult Bundlesを見た際にテスト結果のより詳細な情報がわかるようになりテスト全体の把握が容易になります。

Xcode11よりResult Bundlesへのデータの集約方法も変更されたのですが、そこら辺の詳細に関しては別の機会に記事を書きたいと思います。

使い方

使い方を紹介するために簡単なサンプルを作成しました。
テキストを音声で読み上げるとてもシンプルなものです(あまり良い例が思い付かず優しい目で見てください)

import AVFoundation

class Speech {

    private var nonMaleJPVoices: [AVSpeechSynthesisVoice] {
        return AVSpeechSynthesisVoice.speechVoices()
            .filter { $0.language == "ja-JP" && $0.gender != .male }
    }

    private func letsSpeaking() {
        let synthesizer = AVSpeechSynthesizer()
        let utterance = AVSpeechUtterance(string:"こんにちは")
        utterance.voice = nonMaleJPVoices.first
        synthesizer.speak(utterance)
    }

}

letsSpeaking()をコールすると「こんにちは」と音声が発せられます。
nonMaleJPVoicesでは使用可能な音声オブジェクトのうち「言語が日本語」かつ「男性以外」の音声情報を渡す実装になっています。

今回はnonMaleJPVoicesの正当性をテストしてみたいと思います。
nonMaleJPVoicesの要件は以下の2つです。

  • 言語が日本語
  • 男性以外

実際に書いたテストは下記です。

class SpeechTests: XCTestCase {

    func testNonMaleJPVoicesContainOnlyJapaneseLanguage() throws {
        XCTAssertFalse(Speech().nonMaleJPVoices.contains{ $0.language != "ja-JP" }, "nonMaleJPVoices must not contain any language other than Japanese.")
    }

    func testNonMaleJPVoicesContainOnlyNonMaleGender() throws {
        XCTAssertFalse(Speech().nonMaleJPVoices.contains{ $0.gender == .male }, "nonMaleJPVoices must not contain a male voice.")
    }

}

上から順に

  • nonMaleJPVoicesは言語が日本語の要素を持つAVSpeechSynthesisVoiceの配列であること
  • nonMaleJPVoicesは音声の性別が男性以外の要素を持つAVSpeechSynthesisVoiceの配列であること

を確かめるためのテストです。
良さそうに見えるのですが、一つ注意が必要です。

AVSpeechSynthesisVoiceGenderはiOS13より追加されたプロパティなのでそれより前のOSバージョンでは取得ができません。
iOS12ではgenderへのアクセスができないのです。

その場合テストはどうなるでしょう?

まず、機能の実装にはOSバージョンの条件分岐が入ります。

internal var nonMaleJPVoices: [AVSpeechSynthesisVoice] {
        if #available(iOS 13.0, *) {
            return AVSpeechSynthesisVoice.speechVoices()
                .filter { $0.language == "ja-JP" && $0.gender != .male }
        }
        return AVSpeechSynthesisVoice.speechVoices()
            .filter { $0.language == "ja-JP" }
    }

すると男性以外という条件を含むのはiOS13以上となります。

先ほどのテストに戻りますがこのままではテストとしては不十分なので修正をする必要があります。

class SpeechTests: XCTestCase {

    /// 修正が必要    
    func testNonMaleJPVoicesContainOnlyNonMaleGender() throws {
        XCTAssertFalse(Speech().nonMaleJPVoices.contains{ $0.gender == .male }, "nonMaleJPVoices must not contain a male voice.")
    }

}

どのように修正するのがよいでしょうか?
iOS13未満では必ずテストが成功するようにしますか?

ここで活躍するのがXCTSkipです。

性別に関してテストすべきなのはiOS13以上の時だけでありそれより下のOSではテスト不要なのでスキップするのが適切です。

早速修正しましょう!

class SpeechTests: XCTestCase {

    func testNonMaleJPVoicesContainOnlyNonMaleGender() throws {
        guard #available(iOS 13.0, *) else {
            throw XCTSkip("AVSpeechSynthesisVoiceGender tests can only run on iOS 13.0+")
        }

        XCTAssertFalse(Speech().nonMaleJPVoices.contains{ $0.gender == .male }, "nonMaleJPVoices must not contain a male voice.")
    }

}

実際にiOS12系の端末でテストを実行してみるとこうなります。
スクリーンショット 2020-09-19 20.45.57.png
何やら見慣れないマークが表示されていますがこれがスキップしたことを示すマークです。

Report Navigatorよりスキップの詳細を見ることができます。
スクリーンショット 2020-09-19 20.51.01.png

使い方はとても簡単ですね...!

スキップの種類

XCTSkipを開始する関数は2種類あります。

XCTSkipIf(::file:line:)

条件式が真の場合にスキップします。

func testExample() throws
    try XCTSkipIf(UIDevice.current.userInterfaceIdiom == .pad, "this tests are not for iPad only")

    // test for other than iPad ...
}

XCTSkipUnless(::file:line:)

条件式が偽の場合にスキップします。

func testExample() throws
    try XCTSkipUnless(UIDevice.current.userInterfaceIdiom == .pad, "this tests are for iPad only")

    // test for iPad only...
}

XCTSkip

先に関数は2種類と説明しましたが、XCTSkip構造体を直接投げることも可能です。

その場合はガードと組み合わせる使い方がおすすめでWWDC20の「XCTSkip your tests」のセッションでも同じように紹介されていました。

func testNonMaleJPVoicesContainOnlyJapaneseLanguage() throws {
        guard #available(iOS 13.0, *) else {
            throw XCTSkip("this tests can only run on iOS 13.0+")
        }

        // test for iOS13+ ...
    }

まとめ

テストを書いていく中で特定の条件下では実行できないテストというのが必ずあると思います(特に統合テスト)

そんなときにXCTSkipを使うことでテストの実行結果をより正確にモデル化することが可能となります。

テストの結果についてより具体的に詳細を把握するためにもぜひスキップしてみてはいかがでしょうか!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift】循環参照 丸わかり?

循環参照

循環参照とは?

お互いのインスタンスを参照しあい、メモリが解放されない現象。
「解放」...もうここ使わないから、あとはご自由にどうぞ、というイメージ。?

image.png

なぜNG?

メモリ リークを引き起こす。
最終的にメモリが足りなくなり、アプリが落ちてしまう。

メモリ リーク

メモリの解放忘れが原因で、永久にメモリが消費され続けること。
再現性が低く 見つけるのが困難で、悪質なバグの一つ。

循環参照 を 防ぐには?

弱参照をする。
weakunownedを使う。(-> unknowned ではない...!)

unowned: 所有されていない
unknown: 知られていない、不明な
unknowned -> こんな言葉ない

なぜ防げるのか

弱参照を行うと、参照カウントは変わらないため。

weakは「このインスタンスへの参照は、カウントしないよ」
という制限を、メモリ管理機能(= Automatic Reference Counting) に伝える。

参照カウント

「プロパティや変数、定数からの インスタンスへの参照」が いくつあるかをカウントするもの。

参照の種類

  • 強参照: strong -> デフォルト
  • 弱参照: weak
  • 非所有参照: unowned

強参照されたインスタンスは、参照カウントが 1 増やされます
弱参照非所有参照を行うと、参照カウントは変わりません

weak と unowned の違い

インスタンスが破棄された場合、弱参照(= weak) 元にはnilが代入されます。

非所有参照(= unowned) では、変数にnilが代入されません。
( -> インスタンス解放後に変数にアクセスすると エラー)

改めまして、「循環参照」とは??

  • 循環参照とは、インスタンス間でお互いを強参照しあった場合に参照カウントが0にならず、メモリ上にインスタンスが残り続けてしまう状態のこと。

  • 永久にメモリが消費され続ける、「メモリリーク」という現象を引き起こす恐れがある。

  • それを防ぐために、weakunownedを使用して弱参照を行う。

 Swiftのメモリ管理を知る

おしまい。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift】AudioKitを使ってみた(2020.9)

はじめに

【2020.9.21】 Oscillators and the Physics of Sound に書き漏れがあったので追記しました。

サウンドファイルの再生じゃなくて、音そのものを発信(発振?)させるのってどうすればいいんだろうとググっていて、AudioKitというライブラリを見つけました。

で、AudioKit Tutorial: Getting Startedというチュートリアルが、順を追って丁寧に解説されてるので動かしてみました。

ただページそのものがかなり古い(2016/バージョンは3.6)ので、公式ページにある最新版のAudioKit Playgrounds (zip)(バージョンは4.9.5)で動かしてみたときの変更点を備忘録としてまとめておきます。DLはこちらから。

実行環境

  • Xcode 11.6
  • macOS Catalina(10.15.6)
  • 公式ページのAudioKit Playgrounds (zip)(バージョンは4.9.5)

Getting Started

まず AudioKit Playgrounds (zip)は最新版を使うので、チュートリアルページのリンクではなく、公式サイトのDLページから入手します。ファイル名は「AudioKitPlaygrounds-4.9.5.zip」になります。

これを解凍してXcodeで開いた後に・・・

Click the + button in the bottom left-hand corner of the Navigator view. Select the New Playground… option, name it Journey, and save it in the Playgrounds folder the other playground files are stored in.

ナビゲータービューの左下隅にある+ボタンをクリックします。 [新しいプレイグラウンド…]オプションを選択し、「ジャーニー」という名前を付けて、他のプレイグラウンドファイルが格納されているプレイグラウンドフォルダに保存します。

と書いてありますが、ナビゲータービューの左下隅にある+ボタンでは「New Playground…」なんて出てこないので、ナビゲータービュー上で右クリックすると「New Playground Page」が出てきますのでここから追加できます。
スクリーンショット 2020-09-20 0.18.44.png
Xcodeのバージョンの問題かしらん?Playgroundってあんまり使ってないんで。。。

さらに以下のような注釈がありますが・・・

This project will fail unless you build the project at least once using Product / Build, or ⌘-B. Once built, run the playground again and you’ll hear your playground emit 10 seconds of a beeping sound. You can use the Play/Stop button at the bottom left of the playground window within the Debug Area to stop or repeat the playground.

このプロジェクトは、Product / Buildまたは⌘-Bを使用してプロジェクトを少なくとも1回ビルドしない限り失敗します。 作成したら、遊び場をもう一度実行すると、遊び場から10秒間のビープ音が聞こえます。 デバッグ領域内のプレイグラウンドウィンドウの左下にある[再生/停止]ボタンを使用して、プレイグラウンドを停止または繰り返します。

Note: If the playground fails to execute, and you see errors in the Debug Area, try restarting Xcode. Unfortunately, using playgrounds in combination with frameworks can be a little error-prone and unpredictable. :[

注:プレイグラウンドの実行に失敗し、デバッグ領域にエラーが表示された場合は、Xcodeを再起動してみてください。 残念ながら、フレームワークと組み合わせてプレイグラウンドを使用すると、エラーが発生しやすくなり、予測できなくなります。 :[

私の環境でも結構出たので、新規のPlaygoundファイルを作ったら「⌘-B」を押し、実行してエラーが出たときは、Xcodeを再起動したり、AudioKitPlaygrounds.xcodeprojに既に作成済みのPlaygroudファイルを実行してから、再度自分で書いたPlaygroundを実行したりしてました。

Oscillators and the Physics of Sound

このコードをそのまま実行すると、以下のエラーが出ます。

error: 02Oscillators.xcplaygroundpage:21:1: error: use of unresolved identifier 'AKPlaygroundLoop'
AKPlaygroundLoop(every: 0.5) {
^~~~~~~~~~~~~~~~

最新バージョンでは、AudioKitとAudioKitUI(おそらくUI系)と二つのフレームワークに分割されていて、'AKPlaygroundLoop'は AudioKitUI にあるので、

import AudioKitUI

を追加すればOKです。以降、'AKPlaygroundLoop'が出てくる箇所ではimportを忘れずに。

【参考】AudioKit/AudioKit/iOS/AudioKit/User Interface/AKPlaygroundLoop.swift

【2020.9.21追記】

rampTimeもエラーになります。

error: 02Oscillators.xcplaygroundpage:18:12: error: value of type 'AKOscillator' has no member 'rampTime'
oscillator.rampTime = 0.2
~~~~~~~~~~ ^~~~~~~~

これは rampDuration に変更されていうようなので、以下のように変更します。

//---rampTimeは、rampDurationに変更
oscillator.rampDuration = 0.2

【参考】AudioKit Reference AKOscillator Class Reference

Sound Envelopes

import AudioKitUI

を追加すればOKです。

Additive Sound Synthesis

1.まず以下を追加。

import AudioKitUI

2.Live ViewにUIを表示するので、Live Viewを表示する必要があります。「Alt+Cmd+Return」で表示/非表示を切り替えます。

【参考】How to create live playgrounds in Xcode

  1. AKPlaygroundView クラスを使ってUIを作成していますが、これがエラーになって動かない。

AudioKitPlaygrounds.xcodeprojに既存の他のファイルを見てみると、AKLiveViewController を使っているようなので、こちらで書き換えました。クラス名を含めた変更点は3つ。

・AKPlaygroundView >> AKLiveViewController
・override func setup() >> override func viewDidLoad()
・addSubview() >> addView()

GitHubで、AudioKit/AudioKit/iOS/AudioKit/User Interface/を見ると、どちらのクラスも存在しているので AKPlaygroundView で何故ダメなのかは不明。

4.Live View にUIが表示されるようになるが、音が鳴らない。

オシレーターを生成するための「createAndStartOscillator()」という関数があって、サンプルコードでは生成時に「oscillator.start()」を実行しているけど、「AudioKit.start()」の後に実行しないと音が鳴らないようです。

なので、createAndStartOscillator()にある「oscillator.start()」をコメントにして、「AudioKit.start()」のあとに以下のコードを追加すればOK。

//AKOscillator.start()は、AudioKit.start()の後でないと音が鳴らない
oscillators.forEach {
    $0.start()
}

Polyphony

1.まず以下を追加。

import AudioKitUI

2.AKPlaygroundView を AKLiveViewController に変更。Additive Sound Synthesis の項を参照。

Sampling

コードの変更点は、特になし。ただサンプルコードで使っている.wavファイルは、自分でDL(リンクあり)して該当Playground配下の「Resources」フォルダに入れておく必要があります。

まとめ

AudoKit、面白そうだけど、入門的な記事は古いものしか見当たらなかったので、まとめてみました。参考になれば幸いです。自分で書いたコードではないので、あえてコード全文は載せていません。

他にいい参考記事あったら教えてください。

シンセサイザーの音声合成的な知識が必要なので使いこなすにはハードル高そうですが、画面のキャラクタタップしたら「どう森」みたいにインチキ言語を喋るとかさせたら面白いかも(笑)。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【GoodReader】ホーム画面にショートカットを作成する方法

頑張る

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む