iOSのアプリをつくる
iOS App Dev with SwiftUI Tutorials | Apple Developer Documentationをやる
iOS App developmentでググると出てくるStart Developing iOS Apps (Swift): Build a Basic UIはSwiftUI準拠ではない
SwiftUIでiOSのアプリを作る
Compositanal API
簡単なビューを組み合わせて複雑なビューを作る
気に食わなければレイアウトを自分でくめる
dataが変更されたら自動的にviewも変更される
このチュートリアルでつくるアプリはスクラム向けのアプリ
次のことが学べる
SwiftUIの基礎
Viewの作り方
ナビゲーション
データの渡し方
状態管理
永続化
ドローイング
音声の録音
SwiftUI and Xcode Essentials
Using Stacks to Arrange Views
https://gyazo.com/bdc3e1ec51d4ccd639e538273f7f447d
Xcodeで新規プロジェクトを作る
iOS > App templateを選ぶ
https://gyazo.com/1b2be5831da7d1a04c390bbc57d4f440
SwiftUIでインタフェースを組むと指定する
The template includes a starter file for your root view, ContentView.swift, and a file that defines the entry point for your app, ScrumdingerApp.swift.
特に指定はないがOrganization identifierを適当に入力する
アプリを作る団体(または個人)の名前。個人で作る場合は自分の名前、企業で作る場合は企業名を入れることが多い
2016 https://www.atmarkit.co.jp/ait/articles/1601/08/news059_2.html
プロジェクトができたのでGitHubにアップしたい
2021/1/14 XcodeとGithubの連携をしたのでまとめる。
この方法でXcodeからアップした
ただしプロジェクト作成時にすでにgitのrepositoryはつくられていた
実行するとこうなる
https://gyazo.com/1cce33db3da3b5b92f911344154af84c
プログレスバーを作る
デフォルトでSwiftUIのファイルは2つのstructからなる
1. Viewプロトコルに従う構造体
Viewを返すbody propertyを要求する
2. viewをcanvasに表示する
Opaque Result Type some
ProgressViewに差し替える
エミュレータでみてみる
https://gyazo.com/ea7929ecba1b01f55c7924ca8a5d92e3
エミュレータがなくてもopt + cmd + enterで出るcanvasで結果を確認することができる
縦にレイアウトをしたいのでVStackを追加する
関数クリックでやるのか
cmd + shift + lでUIのライブラリを出すことができる
システムがフォントとして使うイメージ
SF Symbols
https://developer.apple.com/sf-symbols/
Label("300", systemImage: "hourglass.bottomhalf.fill")
https://gyazo.com/714bb11866bdd61497e2c67a4a8a278e
.accessibilityElement(children: .ignore)をつけたりつけなかったりするのはなぜ?
Accessibility
https://github.com/kadoyau/Scrumdinger/pull/1/files#r582203796
https://gyazo.com/83987109121c4e83e1d08789dde3a1b6
縦方向にはSpacerを入れていないのにVScapeにHaeder(HSpace)/Circle/footer(HScpace)が均等になる
Views
Creating a CardView
参加ユーザーを出すCardViewをつくる
Modelsグループを作る
https://gyazo.com/669369969bd450050561d9fda6083180
Scrumdinger以下に作成する
Model以下にDairyScrumのモデルを作成する
extension (Swift)
kadoyau.icon extensionを使うことで、ビューに仮のデータを受け渡して、Previewしながら作れるのは感心した
Previewにextensionで作成したデータを渡している
https://gyazo.com/5d641f18a2208dba666232380dfe9300
Color
A Color is a late-binding token: SwiftUI only resolves it to a concrete value just before using it in a given environment.
https://developer.apple.com/documentation/swiftui/color
You must import SwiftUI because it defines the Color structure
https://developer.apple.com/tutorials/app-dev-training/creating-a-cardview Q2の解説
トラブル:scrum.colorで色が指定されない
別途Assets.xcassetsに定義する必要がある(手順にかいてない)
https://gyazo.com/2791081f4c25e84d56cf68f8aaf441fa
参考:https://qiita.com/tasogarei/items/ccda7e31912579a9ce45
SwiftUIでCardViewをつくる
kadoyau.iconこのチュートリアル、どこにディレクトリを作ってファイルを作成するかの説明が基本的にない
完成品ファイルから読むしかない
.leadingって何を表しているの?
A VStack arranges child views in a vertical line and takes an alignment argument to position views along the horizontal axis.
【Swift】SwiftUIのAlignment Guide まとめ - Qiita
https://gyazo.com/f63d9b7a9759c87fb552f8a77b37a4ac
label/imageに使われているSF Symbolはスケールできる
トラブル:Color+Codable.swiftがないと色がつけられない
このファイルの作り方や説明がない
extension Color: codableとは?
Color型をextension (Swift)で拡張している
型をCodableにする
// MARKは便利なコメント
https://gyazo.com/43b5620e04454c6dd0a73dfd667de6fc
When using this syntax (plus // TODO: and // FIXME:), you can get some extra information to show up in the quick jump bar.
xcode - Swift: Understanding // MARK - Stack Overflow
CardViewができた
https://gyazo.com/5d9857c31132af192048a69764847ddb
Displaying Data in a List
Listは単一のスクロールカラムに整列されたデータの行を表示するcontainer view
https://developer.apple.com/documentation/swiftui/list
この章でやること
ユーザーのデイリースクラムのサマリをListに表示する
ListをAppのメイン画面にする
ForEach Viewを使ってDailyScrum objectの配列から動的に行を生成する
The List initializer in this step accepts a ViewBuilder as its only parameter. So, you can add rows with the same syntax you’ve been using with other container views such as HStack and VStack.
Entityを一意に定める:Identifiable protocol
id要素がないとコンパイルエラーになる
UUID型のidを追加する
Xcodeでstubを作成するとObject identifier型のidが生成される
structのinitializerを作成する
https://docs.swift.org/swift-book/LanguageGuide/Initialization.html
\.はkeypath
SwiftUIで出てくるバックスラッシュの意味を調べる - しめ鯖日記
起動画面をScrumViewに設定する
SwiftUI appはApp protocolに従った構造を定義することで作成できる
The app’s body property returns a Scene that contains a view hierarchy representing the primary user interface for the app.
https://gyazo.com/cd8d2b4e040f51a494078359e582bcbb
XCodeのSimulatorでiPhoneの機種を変更する
Navigation and Modal Presentation
Creating a Navigation Hierarchy
UIのモックが組めたので、viewの間のナビゲーションを作成する
https://gyazo.com/c9b216638e6d18e96da0da0c8c1dc2ef
list →detail→timer
Navbarをつける
NavigationView container
ボタンやタイトルをつける場所が確保される
NavigationView is a container view that presents a stack of views in a navigation hierarchy.
NavigationLinkをつけるとdisclosure indicatorが自動でつく
https://gyazo.com/b0a3697918df3dc839065b407a598e4a
NavigationView内でNavigationLinkを使うと、別のビューに飛べる&戻れるように自動的にNavigationしてくれる
https://gyazo.com/7eda26cd56a45e53626436e293fc41a2
kadoyau.iconVIewのpreviewでもNavigationViewを追加しないと当然反映しないのがちょっと罠
飛んだ先の詳細なビューを作っていく
モックを作る
displays the name of a scrum, meeting duration, card color, and attendee list.
Listを追加してSectionにHStackを追加していく
.listStyle(InsetGroupedListStyle())でlistのsyleを変更する
https://developer.apple.com/documentation/swiftui/liststyle
いろいろある
https://gyazo.com/fa20c388df6dc9a7fd2904388702c7e8
参加者リストを追加
ナビゲーションを作る
NavigationLinkでLabelをwrapしてdestinationのviewを指定すると、Labelをタップでdestinationのviewに遷移する
完成画面
https://gyazo.com/cdedeed27db084967127ce01235eae73
Quiz
Navigation modifiers, such as title and bar items, are added to child views and propagated to the parent NavigationView.
たしかに、NavigationViewの内側のView要素につけているのに、親のNavigationViewにpropagateしてる
https://github.com/kadoyau/Scrumdinger/pull/4/files#r583597440
App (NavigationViewでScrumViewをwrapしてる)> ScrumView > DetailView(返すViewでnavigation titleをつけてる)
Creating the Edit View
学ぶこと
データの編集、更新
Editするview
slider
text field
color picker
navigationを経由したデータの受け渡し
コード
Data型をNested typeとして宣言
すべての変数に初期値を渡しておくとコンパイラが自動的に引数なしのinitializerをつくる
Initialization — The Swift Programming Language (Swift 5.4)
.でextensionのstatic varにアクセスできる
code:swift
extension Color {
static var random: Color {
// make a new color
}
}
extension DailyScrum {
struct Data {
var color: Color = .random // call a static rundom
}
}
Edit Viewの作成
viewからmutateするために@State wrapperをプロパティに適用する
bindingできるようになる。@Stateをつけないと変数に$をつけられない
ReactのuseStateのようなものでビューが状態を持つ
SwiftUIは@Stateをobserveしていて再描画する
kadoyau.icon Reactと同じ
You can use the @State property wrapper to define the source of truth for value types.
どういう意味?
binding
https://gyazo.com/f9c794a299604434fa27f4a4a008bd78
参加者の追加
https://gyazo.com/6af02711188c77edead73dbea7640650
既存の参加者の表示
新たな参加者の追加
非入力時に追加ボタンを押させない
スワイプで削除
アクセシビリティの追加
color pickerはButtonなのでButtonを言わせないように.accessibilityLabel(Text("Color picker"))とする
Detail ViewでEditを押すとEdit Viewをモーダルとして出すようにする
Modality - App Architecture - iOS - Human Interface Guidelines - Apple Developer
Use a full-screen modal view for immersive content — such as videos, photos, or camera views — or a complex task that benefits from a full-screen presentation, such as marking up a document or editing a photo.
ユーザインターフェイスのデザインのヒント - Apple Developer
https://gyazo.com/635d2ae5c26f1ef0a5603f3e6f821073
tapするとisPresentがtrueになり、trueになるとfullScreenCoverでEditViewが呼び出される
編集画面ができた
https://gyazo.com/39de8d63a721751c0a18c2d1dfb48f20
Question
Slider(value: $itemCount, in: 5...20, step: 5.0)
Passing Data
Passing Data with Bindings
異なるViewで共有される状態へのbindingを利用して、編集昨日をつける
親のビューの状態によって子のビューの状態を変更する
Reactで、親がstateをもって、そのstateを変更するfunctionを子に渡すのに近い
あるいはVueの双方向バインディング
https://github.com/kadoyau/Scrumdinger/pull/6
Pass the Edit View a Binding to Scrum Data
EditViewが親のDetailViewから渡されたデータをmutateできる
source of trutのreferenceを共有するためにbindingを使う
.constantを使うとハードコードされたimmutableな値のbindingを作成できる。previewに便利
Pass the Detail View a Binding to a Scrum
ScrumViewはDetailViewの状態が変更されたら状態を変更する必要がある
ここでもBindingをすることになる
Specifying Argument Labels
private func binding(for scrum: DailyScrum) -> Binding<DailyScrum> {
forという名前のscrum
https://docs.swift.org/swift-book/LanguageGuide/Functions.html
Pass the List View a Binding
Open ScrumsView in Live Preview mode and try editing a scrum. Why are your changes discarded when you tap Done?
Previewは.constantでimmutableな値をbindingしているので変更されない
実際に動くときは@Stateでmutableな値を渡す
private func binding(for scrum: DailyScrum) -> Binding<DailyScrum> でやってるのが結構複雑
@Binding var scrums: [DailyScrum]であり、$scrumsはvalid
$scrumsはBinding<[DailyScurm]>(たぶん)
ForEachで分解して$をつけてBindingにすることはできない
https://gyazo.com/ec0484b25e0c1c1352385a324f087a1c
のでindexを取得して$scrums[index]として返すことでBinding<DailyScums>
https://gyazo.com/c8ee50735cdc044aaf8830e560a26418
State Management
Managing State and Life Cycle
このアプリは、scrumが変化しても情報を提供する
scrumのstateを管理するために、ライフサイクルメソッドを使ってモデルを制御する
https://github.com/kadoyau/Scrumdinger/pull/7
やること
display meeting time an progress in views
integrate with AVFoundation to play audio when the scrum’s state changes.
Create an Overlay View
見た目をマシにする
ZStackをつかってForegroundに色を置く
scrumのbindingを使ってカラーを設定
https://gyazo.com/b0e59da62b5cd9a1c1f3e6d4e35e2bb0
Extract the Meeting Header
分割するとコードが小さくなってメンテしやすくなる
やること
extract the meeting header into its own view
create properties to pass a meeting’s elapsed and remaining time
update the logic of the progress view and accessibility labels
ヘッダーの分割をしたときに要素が小さいのでプレビューで過剰に大きく見えてしまう。.previewLayout()でこれを防ぐ
https://gyazo.com/cb3d35332ad79fa85fe337cd0a509d11
こうしても、Live previewの場合は中央表示になる
https://gyazo.com/b6fa823b5207d714c06e540b39b9e7e9
Add Design Elements to the Meeting Header
PregressVIewのスタイルを独自のものに差し替える
https://gyazo.com/0fe5a2d3662e13492e668ede9b984400
黒い縁がついた
マージンがついた
砂時計の位置が変わった
Add a State Object for a Source of Truth
ここで天下り的にScrumTimerクラスが与えられる。中身の解説はないのでブラックボックス
@State to create a source of truth for value type models.
@StateObject to create a source of truth for reference type models that conform to the ObservableObject protocol
Wrapping a property as a @StateObject means the view owns the source of truth for the object.
Wrapping a reference type property as a @StateObject keeps the object alive for the life cycle of a view.
@StateObject先のクラスのライフサイクルを呼び出し元のクラスに一致させる
これをつかわないと、タイマーは進まなかった
@Published
Publishing a property with the @Published attribute creates a publisher of this type. You access the publisher with the $ operator, as shown here:
https://developer.apple.com/documentation/combine/published
publisher?
Declares that a type can transmit a sequence of values over time.
A publisher delivers elements to one or more Subscriber instances.
https://developer.apple.com/documentation/combine/publisher
The starter project includes the ScrumTimer class, a model which conforms to ObservableObject. You’ll use @StateObject to declare an instance of this class in the meeting view.
Add Life Cycle Events
viewを呼び出したり消したりしたときにタイマーをストップ/再開する
Extract the Meeting Footer
Closure (Swift)
https://gyazo.com/5d3699a3de330eed6c4fdf27d777c0db
Trigger Sound with AVFoundation
時間切れになったら音を鳴らす
AVFoundationを使うと音を扱うことができる
BundleのURLのファイルが取得できない
Bundleはリソースとコードを隠蔽したもの
リソース管理の何がベストプラクティスなのかわからない
リソースアクセスを型付けするのには SwiftGen/R.swiftがでてくる
https://gyazo.com/92b454f0f34c0d32d6d6ef0d40265073
このファイルに https://github.com/kadoyau/Scrumdinger/pull/7/files#diff-e1c631f6452a75d5a5ce0b88d6e3cbfb76a007eccdaa72eb2ca227f4e0229a93R7 でアクセスできる
時間切れの数秒後に音がなるのはなぜ?
Updating App Data
@state, binding, source of truthの復習
add a view to create new daily scrum meetings
update the meeting timer to keep track of past meetings.
Both of these features will modify the shared data that’s displayed in multiple views in the app.
https://github.com/kadoyau/Scrumdinger/pull/8
Use EditView to Create a New Scrum
+ボタンで新しいスクラムをつくるようにする
https://gyazo.com/14373ccfacdc14c80d722bdc1e61ee29
@Stateした変数を別のViewに渡して、そこの変更を親のViewで使うという連携
Add Scrum History
Historyを追加する
historyのリストをDetailViewで表示する
Date型のDateをいい感じに表示する
Text(date, style: .date)
https://developer.apple.com/documentation/swiftui/text/datestyle
https://gyazo.com/45dd25bac99d32bdc5dfe6d70ea62435
Persistence
Persisting Data
データが永続化されてないからアプリおとしたら消えちゃう
add Codable conformance for the app’s models and write methods to load and save scrums.
Add Codable Conformance
Codable is a type alias that combines the Encodable and Decodable protocols. When you implement these protocols on your types, you can use the Codable API to easily serialize data to and from JSON.
CodableをつけていくだけでCodableにできるが、Colorはできないので自前実装する
Color isn’t Codable by default. The Color+Codable extension implements the init(from:) and encode(to:) methods that are necessary to make Color conform to Codable.
Create a Data Model
ObservableObject
Any view observing an instance of ScrumData will re-render when the @Published variable value changes.
FileManager
shared objectという概念があるらしい
The FileManager class provides convenient access to a shared file manager object that is suitable for most types of file-related manipulations.
https://developer.apple.com/documentation/foundation/filemanager
do catch
データモデルをつくり、ドキュメントフォルダを開いてたりデータのURLを取得するメソッドを生やす
scrum.dataとして保存されそう
Add a Method to Load Data
scrum.dataからscrumsを展開する
バックグラウンドのキュー(FIFO)にタスクをつむことができる
DispatchQueue.global(qos: .background)
qosはQuality of service
background tasksは優先度が最も低いタスク
キューの処理は非同期を指定することができる
You use a weak reference to self inside the closure to avoid a retain cycle.
DEBUGブロックは開発のときだけ呼ばれる
Add a Method to Save Data
scrumをディスクに保存する
Load and Save Data
You’ll load data when the app’s root view appears on screen and save data when the app becomes inactive.
A property wrapper that reads a value from a view’s environment.
@environment
Scene Phase
If you read the phase from inside a View instance, you obtain a value that reflects the phase of the scene that contains the view.
https://developer.apple.com/documentation/swiftui/scenephase
実際にscrumsがどこにあるか確認する
Bundle IDを調べて
https://gyazo.com/3eef75eb745271c5a0bfbea439e8d545
アプリを起動中に以下のコマンドを実行
code:zsh
$ xcrun simctl get_app_container booted dev.kadoyau.sample-scrumdinger.Scrumdinger data
/Users/kadoyau/Library/Developer/CoreSimulator/Devices/B2D6D227-CE04-400A-81EF-389A991F6F01/data/Containers/Data/Application/4C30568E-CD88-4A79-A24E-D91FA0BBA796
このディレクトリがrootで、Documents以下にscrums.dataがある
https://gyazo.com/9e4ffd47cff571c96cf660e6fd2f2905
https://gyazo.com/02ec93ea063b0a018b9cd4c66119c6c3
変更がアプリをバックグラウンドにしても永続化している
Quiz
ビューがクラスをobservingしているとき、クラスの変数が変わったらビューを再評価するためにはどうすればいい?
クラスをObservableObjectにしてそのクラスの変数を@Publishedにする
An ObservableObject includes a publisher that emits before any of its @Published properties changes.
https://developer.apple.com/documentation/swiftui/view/onchange(of:perform:)
An inactive scene doesn’t receive events and should free any unnecessary resources.
Drawing
Drawing the Timer View
Create the Meeting Timer View
Recording Audio
Transcribing Speech to Text
Wrapping Up
SwiftUI/Swiftに初めて触れた感想
iOS開発わからないことリスト