❸ Playgrounds App教材のすべて 前編
アプリが開発できる Playgrounds 4 にはたくさんの無料サンプル(App教材)があります。
でも順に制覇しようとすると落とし穴に!
説明が最小限なうえにシンプルな順に並んではいません。
入門者を迷わせる説明の間違い‼️などがいくつかありました。
はじめてアプリを作る場合はこの記事を参考に効率よくサンプルに取り組んでください。
【2022年9月現在ダウンロードされる『自分だけの物語を選択する』が大幅に変わっています。『別ものに変わった「自分だけの物語を選択する」』を参照してください】
【2022年1月30日 ガイドのステップ別説明を追加し、App教材コード・説明の間違いや要注意点に‼️マークを追加しました】
各アプリについて詳しく書いていたら長文になってしまいました。
前編と後編でそれぞれ 5 つの App教材を解説し、どの順序で取り組むのがおすすめかは後編に書きます。
この記事は『Playgroundsでアプリデビュー』マガジンで読むことができます。
Playgrounds 4 のインストールは『❷ PlaygroundsでApp教材を動かす』を参照してください。
ここで説明に使っている Playgrounds アプリは最新のバージョン 4 です。
バージョン 3.4. 以前の場合は 4 にアップデートしてください。
バージョンは 設定アプリ Playgrounds で確認できます。
Playgrounds 4 の使い方は『❷ PlaygroundsでApp教材を動かす』を参照してください。
🟩 1 Playgrounds 4 のApp教材
Playgrounds 4 のApp教材は、説明付きの Appプロジェクトのサンプルです。
一部は手順に従って操作するチュートリアルで、そのほかはコードを日本語で解説しています。
説明を読み
動かす
一部変更してどうなるか確認
の手順を体験するためのサンプルです。
完全なアプリにビルド可能なサンプルです。
🟢 1.1 Playgrounds 4 から利用可能なAppプロジェクト
Appプロジェクトはアプリを作成するための Playgrounds 書類です。
1.1.1 Appテンプレート
Appテンプレートで最小構成のAppプロジェクトを見ることができます。
サンプルをすべてやってから、アプリを作る場合の起点として利用するためのものです。
「そのほかのプレイグラウンド」から「App」をタップするとマイプレイグラウンドに「マイApp」として保存されます。
「マイApp」のアイコンはランダムに変わるようです。
(アイコンは自分の好みに変更できます)
このテンプレートはシンプルで、ソースコード二つだけです。
ここでは詳しくは説明しません。
まず App教材を試してください。
1.1.2 SwiftUI フレームワーク
Appプロジェクトは SwiftUI(スイフト ユーアイ)フレームワークを使います。
SwiftUI は柔軟に画面のコードを書くことができますが、使いこなしには Swift 言語の理解が欠かせません。
SwiftUI についてこれまで多くの記事を書いてきました。
まとめて読めるマガジン「SwiftUI初級脱出パッケージ」を用意しました。
有料記事もおよそ半分試読できますので、ぜひ目を通し参考にしてください。
SwiftUI は画面アップデートや画面遷移などが、これまでの手続型コーディングとはまったく違います。
型やメソッドなどに英文ドキュメントへのリンクを付けています。
リンクのある型やメソッドは SwiftUI などフレームワークのものです。
リンクのないものは基本的に App プロジェクト内で定義されているものです。
ドキュメントは英文なので、最初はとてもむずかしく感じると思います。
でも形式が決まっていますし、翻訳ツールを使うこともできます。
できるだけドキュメントを見る癖を付け Swift と SwiftUI のスキルを獲得してください。
🟩 2 App教材の入手
🟢 2.1 Playgrounds 4 でダウンロードして入手
「その他のプレイグラウンド」からダウンロードします。
「マイプレイグラウンド」の一番下「すべてを見る」をタップすると「その他のプレイグラウンド」画面にきりかわります。
「Appギャラリー」と「Appを拡張する」がApp教材(Appプロジェクト)です。
もちろんインターネット接続が必要です。
ネットワークに接続していないと何も表示されません。
「入手」ボタンで直接ダウンロードも可能です。
サムネイル画像をタップすると、説明画面を表示します。
「Appギャラリー」はさらに一覧画面があります。
「Appギャラリー」欄の「すべてを見る」をタップすると次の画面を表示します。
各App教材の画面では概要説明があります。
サムネイル画像はアプリ機能をイメージさせる画像を背景に、設定済みのアプリアイコンが描かれています。
コードを学ぼうの説明画面ではプロジェクトの実行画面を表示しますが、App教材では実行画面はありません。
(実行画面は間に合わなかっただけかも知れません。)
🟢 2.2 コードを学び、Appを作る
ここには4つの教材があります。
ブック形式が3つとApp教材(Appプロジェクト)がひとつです。
2.2.1 コーディングを始めよう
コードを学ぼう 1 と 2 のダイジェスト版です。
App教材とは違い、ブック形式のプロジェクトです。
プログラミングがはじめての人はこちらではなく、「コードを学ぼう1」に取り組んでください。
こちらは Swift 以外のプログラミング言語経験者が Swiftを体験するのに適した教材です。
2.2.2 Appの作成を始めよう
アプリ作りのチュートリアルです。
アプリとしては完全ではありません。
アプリ起動時に IntroView() を表示しますが、ExperimentView に画面を切り替えるコードはありません。
コードを学ぼうなどブック形式とは画面も操作も違っています。
App形式プロジェクトの使い方など詳しくはこちらに書きました。
VStack や Text について「SwiftUI初級脱出パッケージ」にある「SwiftUIの文法 その1 View」で詳しく説明しています。
2.2.3 コードを学ぼう 1
Swift 言語にはじめて取り組む人向けの教材です。
ブック形式のプロジェクトです。
サブタイトルは「Swiftの基本」です。
アプリを作るには少なくとも「コードを学ぼう 2」までやってからとりかかってください。
「コードを学ぼう」は教材ととしてパズルの要素があります。
正しくコーディングしてパズルも解けないと次に進めません。
パズルとして解けなくても心配ありません、プログラミングに慣れるための教材として使ってください。
こちらの無料記事で解答例が参照できます。
2.2.4 コードを学ぼう 2
コードを学ぼう 1 の次に取り組むための教材です。
「コードを学ぼう 2」は中級編となっています。
これは基礎編である「コードを学ぼう 1」の後から取り組む教材であることを明確にするためあえて中級編としたように思えます。
プログラミング言語の難易度としてはまだ初歩の段階ですので、安心して取り組んでください。
残念ながら「コードを学ぼう」1 と 2 を最後までやっても、すぐにアプリを作るのは難しいです。
参考書などが必要ですが、「コードを学ぼう」には少し込み入った内容は含まれないため、残念ながら 1 と 2 を終えた後でも、一般のプログラミングの入門書を見ると難しいと感じると思います。
「辞書」や「オプショナル」それに「クロージャ」「ジェネリック」「クラスと継承」など初学者にはやっかいな部分が「コードを学ぼう 1 と 2」では解説されていないためです。
これらはアプリ作りに必須です。
そのために私の書いた『Swift5初級ガイド』を役立ててください。
この電子書籍で解説しているのは Swift のバージョンは 5.3 までです。
5.5 で追加になった点は、公式ドキュメントの日本語訳を参照してください。
『ドキュメント改訂履歴』のリンクから追加変更部分を日本語で参照できます。
🟩 3 Appギャラリー
7つのApp教材があります。
どれもアプリとして実行可能なもので、日本語ガイドでコードの説明があります。
🟢 3.1 プロフィール
サブタイトルは「タブのナビゲーションについて学ぶ」です。(英語タイトルは「About Me」)
「Appの作成を始めよう」の次に取り組むには不向きです。(本格的なアプリの構成になっていて SwiftUI 初学者には難しい)
3.1.1 概要
複数画面を切り替えて利用できる「タブインターフェイス」のサンプルです。
利用するビューも写真、テキスト、カラー、ボタン、スクロールビューと種類が多く、応用のサンプルといえます。
プロジェクトの容量は3.6MBです。
バージョン番号は 1月21日現在 V 1.0.0 です。(ダウンロードできる App教材はどれも V1.0.0 で同じなので以下の説明では割愛します)
3.1.2 内容
コードのファイル数は 7、画像ファイル(アセット)は 1 です。
AboutMeApp ファイルの(アプリの構造などの)説明はありません。
AboutMeApp
SwiftUI アプリの標準的なコードです。
ContentView ビューをトップレベルで表示します。
オブザーバブルオブジェクトはありません。
3.1.3 タスク:タブ付きインターフェース
このタスクで説明するのは ContentView.swift です。
ステップ 2/5
body についてごく簡単に触れられていますが、文法的な解説はありません。
ステップ 3/5
TabView を使っています。
イニシャライザーは init(content:) で content: 引数の内容はトレイリングクロージャーで { の後に記述しています。
ステップ 5/5
.tabItem(_:) と Label も使っています。
Label は init(_:systemImage:) イニシャライザーです。
4つのビューをタブを使って切り替え、ひとつを表示します。
各ビューは独立したファイルになっています。
3.1.4 タスク:データ
このタスクで説明するのは Data.swift です。
ビューとデータを分けた本格的なアプリの構成です。
"Data" はコードファイル名です、このコードの型の名称ではありません。
ステップ 2/5
実際のデータ管理は struct Info を使います。
必要なデータをプロパティで管理することが説明されていますが、プログラミングを経験していなければこれだけの説明ではすんなり理解できそうもありません。
プロパティや配列はSwift言語の用語です。『Swift5初級ガイド』などで十分確認してください。
ステップ 3/5
Info( で始まっているコードは struct Info のデフォルトイニシャライザーです。
型やイニシャライザーについては SwiftUI ではなく Swift 言語の文法です。
ステップ 5/5
アセットの追加方法の説明があります。
自分の写真でかまいませんが、ここではウィキペディアからパブリックドメインの写真をダウンロードしてアセットに追加しました。
アセットでは(下画面のように)写真を表示できるのに、プレビューで写真を表示しない場合は、アセットの名称とプロパティに設定する文字列を確認してください。
3.1.5 タスク:"ホーム"タブ
このタスクで説明するのは HomeView.swift です。
最初に表示するタブ(TabViewが管理しているビューのひとつ)です。
たくさんの SwiftUI ビューを使っています。
それぞれ英文ドキュメントにリンクしています。
ステップ 2/10
VStack 型を使っています。
このコードは init(alignment:spacing:content:) イニシャライザーの alignment: と spacing: 引数は省略しデフォルト値を使っています。
content: 引数はトレイリングクロージャーで { } の中に記述しています。
ステップ 3/10
Text 型を使っています。
ここでは init(_:tableName:bundle:comment:) イニシャライザーの最初の引数以外は省略しデフォルト値を使っています。
ステップ 4/10
font(_:) .largeTitle
テキストの.fontWeight(.bold)で太さを指定しています。
fontWeight(_:) .bold は Font.Weight の中の一つです。
ステップ 5/10
Playgrounds のエディターでオートコンプリートを利用して、候補から選ぶ方法を説明しています。
ステップ 6/10
padding()でレイアウトを調整しています。
padding(_:_:) 引数は二つありますが、ふたつともデフォルト値が設定されていて省略しています。
ステップ 7/10
Image 型を使っています。
init(_:bundle:) イニシャライザーで、bundle: 引数は省略しています。
ステップ 8/10
resizable(capInsets:resizingMode:) 引数は二つありますが、ふたつともデフォルト値が設定されていて省略しています。
ステップ 9/10
aspectRatio(_:contentMode:) 【2022年1月30日 リンク先を修正しました】
最初の引数は省略されています、省略すると画像のアスペクト比を維持します。
ステップ 10/10
cornerRadius(10)で Imageビューを角丸にしています。
cornerRadius(_:antialiased:) 二つ目の引数 antialiased は省略しています。
3.1.6 タスク:"物語"タブ
このタスクで説明するのは StoryView.swift です。
ステップ 2/4
長文を表示するために ScrollView を使っています。
init(_:showsIndicators:content:) イニシャライザーで、最初の引数は省略して縦方向、showsIndicators: 引数は省略しています。
content: 引数はトレイリングクロージャーで { } の中に記述しています。
ステップ 3/4
Text ビューは長い文を表示する場合は複数行になります。
このコードだけでダイナミックタイプに対応で、実行時に文字サイズを好みのサイズに拡大または縮小できます。
3.1.7 タスク:"お気に入り"タブ
このタスクで説明するのは FavoritesView.swift です。
ステップ 2/4
VStack、HStack、ForEachを組み合わせています。
ステップ 3/4
ForEach の説明は最小限です。
詳しくは「SwiftUI初級脱出パッケージ」にある「SwiftUI でリスト表示」の「6 ForEach」を参照してください。
ステップ 4/4
Image 型を使っています。
resizable(capInsets:resizingMode:) 引数は二つありますが、ふたつともデフォルト値が設定されていて省略しています。
frame(minWidth:idealWidth:maxWidth:minHeight:idealHeight:maxHeight:alignment:) 引数はすべてデフォルト値が設定されているので省略可能です。
scaledToFit()
scaledToFill()
3.1.8 タスク:"面白い情報"タブ
このタスクで説明するのは FunFactsView.swift です。
ボタンのアクションで表示内容をランダムに切り替えるサンプルです。
ステップ 2/5
@State の説明がありますが、最小限です。
@State はとても重要なので、詳しくは「SwiftUI初級脱出パッケージ」にある「SwiftUIデータフロー入門」を参照してください。
ステップ 3/5
randomElement() は Array 型のメソッドです。
randomElement()はオプショナル(Optional)を返すので、コードの末尾にアンラップのための感嘆符を付けています。
ステップ 4/5
Button 型を使っています。
background(alignment:content:)
cornerRadius(_:antialiased:)
オプショナル(Optional)も クロージャ(Closure) も重要です(「クロージャー」とも書きます)。
こちらはSwiftの機能なので『Swift5初級ガイド』を参照してください。
3.1.9 「プロフィール」を実行
App名は「About Me」です。
タブの画面を合成しています。
🟢 3.2 ミームメーカー
サブタイトルが「並行処理でデータをダウンロードする」です。(英語タイトルは「Meme Creator」)
インターネットから画像を取得するサンプルなので、Swift 5.5の機能も使っていてコードの難易度は(特に初学者にとっては)高いです。
文字入力やスライダーによる文字サイズの変更、カラーピッカーによる文字色の変更も可能です。
3.2.1 概要
非同期でアプリの操作に影響なしに画像をダウンロードします。
インポートするフレームワークは SwiftUI のみです。
非同期で通信を行うので Swift と SwiftUI の要素をたくさん使っています。
機能は盛りだくさんですが説明は最小限です。
3.2.2 内容
プロジェクトの容量は 4.6MBです。
コードのファイル数は 5、画像(アセット)は2です。
3.2.3 タスク:Appデータの共有
このタスクで説明するのは MemeCreatorApp.swift です。
サイドバーでは拡張子「.swift」は省略されています。
ステップ 1/2
@StateObject
ObservableObject と environmentObject(fetcher) を使います。
これらのしくみも重要ですが詳しい説明はありません。
ステップ 2/2
environmentObject(_:)
ObservableObject は「SwiftUI初級脱出パッケージ」で読める「SwiftUIのデータフローその2」を参照してください。
3.2.4 タスク:パンダモデルの作成
このタスクで説明するのは Panda.swift です。
パンダモデルは独自に定義した struct Panda: Codable を指しています。
プロパティに説明と画像のURLを持っています。
このコードはビューではないのでプレビューも表示しません。
String 型は Swift Standard Library フレームワークですが import SwiftUI のみで利用可能です。
URL型は Foundation フレームワークですが、import SwiftUI のみで利用可能です。
struct PandaCollection: Codableは PandaCollectionFetcher クラスで使います。
配列は Swift では Array 型です。
3.2.5 タスク:パンダデータの取得
このタスクで説明するのは PandaCollectionFetcher.swift です。
ステップ 1/8
PandaCollectionFetcher クラスは ObservableObject でパンダの画像データを取得完了するとビューを再表示させるしくみです。
ステップ 2/8
@Published で公開値としているプロパティが二つあります。
@Published については「SwiftUIのデータフローその2」の「2-3 ビューを更新させるしくみ」を参照してください。
ステップ 3/8
async、await など Swift 5.5 の新しいキーワードも登場します。
ステップ 4/8
throws や try も Swift 言語のキーワードです。
ステップ 5/8
guard も Swift 言語のキーワードです。
guard let url = URL(string: urlString) else { return }
は URL 型のイニシャライザー init(string:) がオプショナルを返すので、値なしならリターンし、インスタンスが得られたらアンラップして定数 url に代入します。
ステップ 6/8
URLSession は Foundation フレームワークのクラスででデータのダウンロードで使います。
URLSession.shared.data(for: URLRequest(url: url)) は1行になっていますが、分解すると
shared は class var shared: URLSession で URLSession インスタンスを返すタイププロパティです。
data(for:) は data(for:delegate:) メソッドの二つ目の引数を省略したものです。
このメソッドは
func data(for request: URLRequest,
delegate: URLSessionTaskDelegate? = nil) async throws -> (Data, URLResponse)
で受診した データとレスポンス をタプルで返します。
URLSession、shared、data(for:delegate:)
ステップ 7/8
guard (response as? HTTPURLResponse)?.statusCode == 200 else { throw FetchError.badRequest }
HTTPURLResponse 型は HTTP のレスポンスに対応します。
statusCode プロパティ statusCode が 200 でなければ FetchError.badRequest を throw します。
as?、タプル、throws、オプショナルなどについては『Swift5初級ガイド』を参照してください。
ステップ 8/8
JSONDecoder も Foundation フレームワークのクラスです。
decode(_:from:) メソッド
3.2.6 タスク:非同期イメージの作成
このタスクで説明するのは LoadableImage.swift です。
ステップ 1/7
AsyncImage は iOS 15 から利用可能になった SwiftUI の新しいビューです。
ステップ 3/7
init(url:scale:transaction:content:) は AsyncImage のイニシャライザーで scale: と transaction: は省略でデフォルト、content: 引数はトレイリングクロージャーで記述しています。
クロージャーの引数 phage は AsyncImagePhase 型です。
ステップ 4/7
AsyncImagePhase 型の image プロパティはオプショナルです。
正常にダウンロードできればそのイメージのデータが得られます。
ステップ 5/7
if let は Swift 言語のオプショナルバインディングです。
正常に画像をダウンロードできた場合はそれを表示します。
説明文字列は VoiceOver などで使うために .accessibility(label:) に設定します。
shadow(color:radius:x:y:)
.accessibility(hidden:)
.accessibilityLabel(Text(imageMetadata.description))
VoiceOver は iOS macOS などで共通のアクセシビリティ機能です。
アクセシビリティ
ステップ 6/7
AsyncImagePhase 型の error プロパティはオプショナルです。
エラーの場合はアセットの画像と Text("Please try again.") を表示します。
ステップ 7/7
AsyncImage でイメージをダウンロードするまでの間は ProgressView() を表示します。
‼️ accessibility(hidden:) は iOS 15.2 で Deprecated です。
accessibilityHidden(_:) を使います。
システムアクセシビリティ機能からこのビューを非表示にするかどうかを指定します。
3.2.7 タスク:ミームメーカーの作成
このタスクで説明するのは MemeCreator.swift です。
ステップ 2/9
@EnvironmentObject については「SwiftUI初級脱出パッケージ」で読める「SwiftUIのデータフローその3」を参照してください。
ステップ 3/9
.task モディファイアー(修飾子)は iOS 15 から利用可能な新しいメソッドです。
この .task 修飾子のアクションで fetcher.fetchData() を使い JSON データをダウンロードします。
task(priority:_:)
ステップ 4/9
try? と await はどちらも Swift 言語のキーワードです。
ステップ 5/9
このビューは LoadableImage ビューを利用します。
ステップ 6/9
overlay で TextField ビューを使って文字入力します。
overlay(alignment:content:)
TextField、focused
ステップ 7/9
"Shuffle Photo" ボタンアクションでパンダのイメージをランダムに更新するコードです。
ステップ 8/9
"Add Text" ボタンで TextField のフォーカスを true にするとキー入力可能になります。
ステップ 9/9
文字が入力されると(文字列が空でなければ)Slider と ColorPicker を表示して、文字サイズと色を自由に設定します。
3.2.8 「ミームメーカー」を実行
実行直後の画面です。
App名は「Meme Creator」です。
写真を表示し、文字を入力し文字サイズと文字色を設定できます。
🟢 3.3 自分だけの物語を選択する
【2022年9月現在ダウンロードされる『自分だけの物語を選択する』が大幅に変わっています。】
【webで提供されている Choose Your Own Story(英文)はこの記事に対応するコードのままです。】
【2022年10月10日『別ものに変わった「自分だけの物語を選択する」』を公開しました】
サブタイトルが「ナビゲーションビューの基本を学ぶ」です。(英語タイトルは「Choose Your Own Story」)
3.3.1 概要
ナビゲーション(画面の切り替えです)やコンテンツのスクロール、データ配列からビューを表示するなど、アプリで頻繁に利用される SwiftUI の基本を学びます。
データを変更して、自分だけの物語を作ってください。
プロジェクトの容量は 3.5 MBです。
3.3.2 内容
コードのファイル数は 5、画像はありません。
‼️ ガイド本文に "StoryData" とありますが、コードには見当たりません。
‼️ たぶん "MyStory" と思われます。
コードだけリファクタリングし、説明テキストに反映が間に合わなかったのかも知れません。(日本語だけでなく英語に切り替えても "StoryData" と表示されています)
StoryApp
StoryApp はタスクに説明がありません。
SwiftUI アプリの標準的なメインです。
StoryView ビューをトップレベルで表示します。
オブザーバブルオブジェクトはありません。
3.3.3 タスク:自分だけの物語を作成する
このタスクで説明するのは MyStory.swift です。
ステップ 1/7
Story と StoryPage それに Choice は StoryModels ファイルで定義しているこのアプリ独自の型です。
MyStory.swift は21ページぶん(0 から 20)の巨大な配列です。
1ページのデータは StoryPage 型で物語データの text プロパティと、選択肢データの choices プロパティを持っています。
Choice 型は選択肢の説明文の text プロパティと、選択した場合に表示するページインデックスの destination プロパティのみを持つシンプルな struct です。
0番を例に説明します。
StoryPage(:choices:) は StoryPage 型のイニシャライザーです。
init(_ text: String, choices: [Choice]) {
引数が二つで最初の引数はラベルなしの物語文字列、二つ目の引数はラベル choices: 付きの Choice 型インスタンスの配列(ステップ 4/7で強調されている部分です)。
ステップ 3/7
引用符三つは複数行のテキストを囲みます。(ステップ 2/7で強調されている部分です)
StoryPage( // 0 ← 0番のページ
"""
Welcome to Choose Your Own Story
【0番ページ物語のテキストデータ】
You are the third to arrive, so there are many stations still available. Where do you sit?
""",
choices: [
Choice(text: "Front row!", destination: 1),
Choice(text: "Find somewhere in the middle", destination: 1),
Choice(text: "Back of the room", destination: 2),
]
), // 0番のページはここまで
ステップ 4/7
0番のページは三つの選択肢があります。
ステップ 5/7
各選択肢は Choice(text: "選択肢の説明文", destination: 飛び先ページインデックス)
選択肢を追加したり、独自の物語文章に差し替えたりしてください。
3.3.4 タスク:物語データのモデル
このタスクで説明するのは StoryModels.swift です。
ステップ 1/6
struct Story 内の subscript は Swift のキーワードです。
サブスクリプト(Subscripts)
story[2] などの記述に対応します。
ステップ 3/6
StoryPage は MyStory.swift で使っている型です。
デフォルトのイニシャライザーではなく最初の引数ラベルを省略した init(_ text: String, choices: [Choice]) { を定義しています。
3.3.5 タスク:ナビゲーションビューを作成する
このタスクで説明するのは StoryView.swift です。
ステップ 2/3
NavigationView は SwiftUI のビューです。
NavigationView について詳しくは「SwiftUI初級脱出パッケージ」で読める「SwiftUIの画面切替」を参照してください。
ステップ 3/3
StoryPageView(story: story, pageIndex: 0) で物語と選択肢を表示します。
story: 引数の story は MyStory ファイルで定義している
let story = Story(pages: [ の story 定数です。
今後も記事を増やすつもりです。 サポートしていただけると大変はげみになります。