![見出し画像](https://assets.st-note.com/production/uploads/images/132747167/rectangle_large_type_2_69485e903e313c3b9e6661e3aff2c358.png?width=1200)
【じっくりSw1ftUI 31】実践編1〜第16章 SwiftUIの概要〜そもそもSwiftUIとは何ぞや❓👀
さてと、前回までで
導入編〜コードテンプレートの作りかた
基本文法編〜Playgroundを使ったSwiftコードの遊びかた
はまとめ終わったので、今回からいよいよ
実践編〜Xcodeを使ったSwiftUIフレームワークの組み込みかた
に入ってく〜〜〜🕺
でちょろっと書いたけど、Swiftの基本文法をいくらやって理解した気になったところで、
実際に、フレームワークを使った組み込みかたをやらないと、スマホアプリは作れないからね👀
(モディファイアやメソッドなんかで基本文法では出てきてないものが圧倒的に多いし!)
今までの記事でも繰り返し、
頭の中だけでコードを書くな
って言ってきてるけど、いくらシンタックスを理解していても、実際に作って動かしてみないと
繋がらないことばかりだからね!
ま、そんな難しくはないどころかむしろ、
簡単でサクサク作れる
ってヤツが多いんだけど、それはAppleがそーいった
シンプルでモダンでインタラクティブな設計思想
で、
UIKitからSwiftUIにさらにフレームワークを進化させてくれてるだけ
CやJava、Objective-CなんかでiOSアプリを作ってみれば凄さとか
世界標準の最先端とは何か
が見れるんじゃないかな。
過去の他の記事でも、Javaは
one write, everywhere
って開発当初の設計思想だけを鵜呑みにして盲信してる日本のロートルかレガシーエンジニアリングで止まってる自称、エンジニアさんが多いけど、
カッターナイフ=切ることは確かにできる
👉料理にしろ、大木を切るにしろカッターナイフでやる人はいない
って言ってきてるんだけど、
Javaでもスマホアプリは作れるから〜〜〜
全部Javaでやろうとするのは、
肉を切るのに、肉切り包丁を使わない
大木を切るのに、チェーンソーを使わない
ようなものだし、山口県の下関市から、自動車や鉄道がある時代に、走れば一緒だから〜〜〜わざわざ三輪車で富士山麓に向かってるようなもの
船があるのに、泳げるからって泳いでいるようなもの
👉効率悪すぎでしょ👀
同じように、
マイクロソフトのエクセルやアクセスなんかでマクロを組むならVBA
iOSアプリを開発するのであれば、XcodeでSwiftUIやUIKit
Androidアプリを開発するのであれば、AndroidStudioでKotlin
って感じで、
専用のプラットフォームをきちんと習得しようね〜〜〜
さてと、では早速、今回の、SwiftUIの概要に移るけど、
今回はSwiftUIのあくまでも概要だからあんまりコードは書かないかな!
今回も、オイラの学習記録なんてどうでもいいって人は
でまんま載ってるみたいだからそっちでも読んでね〜〜〜
第16章をじっくり読んでく
まずは、
SwiftUIの歴史
から入ってんね👀
SwiftUIは2019年のWWDCで発表
アプリの基本システムによる開発の全体的に新しいアプローチとして刷新
よりシンプルに、より早く、よりバグが少なくのスローガンの下、よりリアルタイムにテストもできるようにライブプレビューも搭載
日本の現代人って歴史性って素養が乏しいせいか、過去の他の記事
なんかで書いたこともあるんだけど、対象の
プログランミング言語
プラットフォーム
フレームワーク
なんかがいつできたかなんかを知ろうともせずに、今現在主流になってる言語が「何十年も前から全部あった」って錯覚してる人が多いんだよね
👉結果、Swiftなんて開発されて10年、オープンソース化されてまだ10年経っていないし、SwiftUIなんて2019年のWWDCで発表されたくらいでまだ5年も経っていないのに、9年くらい前に、
Swiftでスマホアプリ開発経験3年以上
みたいなアホかと思う求人を何件も見たことあるしね。
(いやいや、12年前はアップル内部ですらいないでしょ🤣その言語とか開発環境がいつできたかすら学ばず、知らずにアホ丸出しな求人票出してる現場とか優秀な人ほど来るわけないじゃん。
その求人票みた瞬間に、この現場が普段どんな現場か「あ、察し。炎上しかしてないだろうな」しかないからね)
👉こーゆー箇所は、
「目先の自分の作業には関係ない。使えれば(作れれば)一緒」
で、すっ飛ばしちゃう人も多いんだけど、
自分が扱ってるとか学んでるプログラミング言語とか開発環境なんかの前提知識くらいは読み飛ばさずに知っておこうね〜〜〜。いずれ恥をかくだけなので。
断言してもいいけど、ここをすっ飛ばす人とか疎かにする人で、大成した人はいない。(10年以上、いろんな現場を見てきたけど、本当に一人も見たことない)
30年以上VBAのエンジニアしてるのに、VBAが何の略かすら知らない人なんて山ほど見たことあるし〜〜〜
さてと、本題に戻って〜〜〜
UIKitとインターフェースビルダー
UIKitもSwiftUIもライブラリの中にあるフレームワークのひとつ
Xcodeにはインターフェースビルダーと呼ばれるツールが搭載されてる
インターフェースビルダーはアプリの各画面を作るための強力なツール
アトリビュート検証なんかもできるように配置してる
縦向きか横向きかといったものまで含め、位置とかサイズまでコンポーネントが各シーンの振る舞いを定義する機能も備えてる
つまり、ユーザーの行動(イベント)に応じて、動的にアプリの表示が柔軟に変わるようにコンポーネントは設計されてる
上記を網羅しながら、開発の各段階で必要と予想される
コンパイラ
シミュレーター
実機テスト
なんかもできるように工夫されてる
ってことが言いたいみたいね👀
基本文法SwiftUI
これまでのインターフェースビルダーやUIKitにおけるアプローチとは違う
シーンを作り上げるために、レイアウトの詳細やコンポーネントの表示などの詳細を手動でデザインしていく方法を採る
SwiftUIは、シンプルで直感的な文法で、レイアウトを描写できるようにした
別の言い方をすれば、複雑なレイアウトビルダーなんかの心配なしに、操作画面を表現できるってこと。これは、レイアウト自体が、スタックやフォーム、リストと言ったレイアウトマネージャ機能も構成してるってことを述べていて、「ボタンに文字を表示させる」、「ラベルに色を付ける」、「タップで何かの処理をさせる(イベント)」みたいに、アトリビュートを設定するモディファイアを使えるようになったことを意味してるが、複雑で入り組んだ詳細な位置なんかについては、SwiftUIで機械的に制御されたレイアウトが実現可能。
これらのビューの階層構造は非常にシンプルで、小さなコンポーザーとサブビューを使い回すことを想定してるので、複雑なビューでも簡単に作ることができる。
プレビューキャンパスを使っているので、レイアウトの宣言もテストもリアルタイムでレイアウトの表示を確認できる。
また、ライブプレビューを使うことで、シミュレーターや実機テストで実行する必要もない。
データ駆動SwiftUI
SwiftUIが発表される前だと、必要だったデータ駆動させるためのユーザーによる手法が不要になった。
これまでだと、例えばボタンをタップさせた際のデータとの連動には、特殊な手法をユーザーで設定する必要があったが、データと密接に繋がっているSwiftUIではそんなものがいらなくなり、操作画面とアプリの裏側のデータの架け橋になるロジックを書けばいいだけになった。
👉複雑な処理を自分で書く必要がなくなり、バインドさせるだけでデータベースと連動でき、反応もよくなった。
SwiftUIかUIKitか
トレードオフの関係じゃない
👉どっちを使うかはその時々で選べばいいだけの話。
そんなことよりも重要なのは、
いずれのフレームワークもまだ成熟してない=進化し続けている
SwiftUIだけで実現できない機能もまだまだあるので、UIKitやインターフェースビルダーとの統合も必要になる可能性がある
ってこと。
まとめ
ちょっと大上段からSwiftUIをこの章では語りすぎたから、これ以降でもっとSwiftUIの深いところ(essentails:本質)を探求してくぜ!
関連マガジン
UIKit
の
【気ままにUIKit】シリーズ
で、(CoreData以外は)去年どっぷりやってるから、UIKitがどんなもんか知りたい人はそちらを覗いてみてね〜〜〜〜
さてと次回は、
SwiftUIで実際に開発する準備について説明した
第17章:SwiftUI モードでの Xcode 15 の使用
に入ってく〜〜〜🕺
実は、導入編ですでにやってることの方が多いかもね👀💦
記事公開後
![](https://assets.st-note.com/img/1709439790800-jzxRjobjAj.png?width=1200)
![](https://assets.st-note.com/img/1709439801793-dH3iMQxsHV.png?width=1200)
![](https://assets.st-note.com/img/1709439813506-blb2aODBTI.png?width=1200)
![](https://assets.st-note.com/img/1709439824263-XtjTDydr01.png?width=1200)
ちょっとこの前の
コードをまとめすぎると、
プレビューが重くなりすぎるな💦👀
ちょいとまとめやすいように章ファイルごとに分けてみるか。
で、コードテンプレート改修版完成!
やはりコードベースなんでそんなに時間も掛からんかったね👀
これがUIKitだったら涙目だったろうな😱
ひとつにまとめすぎると、プレビューがめちゃくちゃ遅くなるってのは罠だったわ!💦
章単位くらいで小分けにしておこう
以下、サンプルコードとファイル構成
import SwiftUI
import WebKit
//iOSApp17DevelopmentEssentialsCh14.swift
//ビュー管理構造体
struct ListiOSApp17DevelopmentEssentialsCh14: Identifiable {
var id: Int
var title: String
var view: ViewEnumiOSApp17DevelopmentEssentialsCh14
}
//遷移先の画面を格納する列挙型
enum ViewEnumiOSApp17DevelopmentEssentialsCh14 {
case Sec1
case Sec2
}
//各項目に表示するリスト項目
let dataiOSApp17DevelopmentEssentialsCh14: [ListiOSApp17DevelopmentEssentialsCh14] = [
ListiOSApp17DevelopmentEssentialsCh14(id: 1, title: essentialsChapter14_1SubTitle, view: .Sec1),
ListiOSApp17DevelopmentEssentialsCh14(id: 2, title: essentialsChapter14_2SubTitle, view: .Sec2)
]
struct iOSApp17DevelopmentEssentialsCh14: View {
var body: some View {
VStack {
Divider()
List (dataiOSApp17DevelopmentEssentialsCh14) { data in
self.containedViewiOSApp17DevelopmentEssentialsCh14(dataiOSApp17DevelopmentEssentialsCh14: data)
}
.edgesIgnoringSafeArea([.bottom])
}
.navigationTitle(essentialsChapter14NavigationTitle)
.navigationBarTitleDisplayMode(.inline)
}
//タップ後に遷移先へ遷移させる関数
func containedViewiOSApp17DevelopmentEssentialsCh14(dataiOSApp17DevelopmentEssentialsCh14: ListiOSApp17DevelopmentEssentialsCh14) -> AnyView {
switch dataiOSApp17DevelopmentEssentialsCh14.view {
case .Sec1:
return AnyView(NavigationLink (destination: Essentials14_1()) {
Text(dataiOSApp17DevelopmentEssentialsCh14.title)
})
case .Sec2:
return AnyView(NavigationLink (destination: Essentials14_2()) {
Text(dataiOSApp17DevelopmentEssentialsCh14.title)
})
}
}
} #Preview {
iOSApp17DevelopmentEssentialsCh14()
}
//Essentials14_1.swift
struct Essentials14_1: View {
var body: some View {
VStack{
TabView {
Essentials14_1Code()
.tabItem {
Image(systemName: codeImageTab)
Text(codeTextTab)
}
Essentials14_1Points()
.tabItem {
Image(systemName: pointImageTab)
Text(pointTextTab)
}
Essentials14_1WEB()
.tabItem {
Image(systemName: webImageTab)
Text(webTextTab)
}
}
}
}
} #Preview {
Essentials14_1()
}
struct Essentials14_1Code: View {
var body: some View {
ScrollView{
Text(codeEssentials14_1)
}
}
} #Preview {
Essentials14_1Code()
}
struct Essentials14_1Points: View {
var body: some View {
ScrollView{
Text(pointEssentials14_1)
}
}
} #Preview {
Essentials14_1Points()
}
struct Essentials14_1WebView: UIViewRepresentable {
let searchURL: URL
func makeUIView(context: Context) -> WKWebView {
let view = WKWebView()
let request = URLRequest(url: searchURL)
view.load(request)
return view
}
func updateUIView(_ uiView: WKWebView, context: Context) {
}
}
struct Essentials14_1WEB: View {
private var url:URL = URL(string: urlEssentials14_1)!
var body: some View {
Essentials14_1WebView(searchURL: url)
}
} #Preview {
Essentials14_1WEB()
}
//Essentials14_2.swift
struct Essentials14_2: View {
var body: some View {
VStack{
TabView {
Essentials14_2Code()
.tabItem {
Image(systemName: codeImageTab)
Text(codeTextTab)
}
Essentials14_2Points()
.tabItem {
Image(systemName: pointImageTab)
Text(pointTextTab)
}
Essentials14_2WEB()
.tabItem {
Image(systemName: webImageTab)
Text(webTextTab)
}
}
}
}
} #Preview {
Essentials14_2()
}
struct Essentials14_2Code: View {
var body: some View {
ScrollView{
Text(codeEssentials14_2)
}
}
} #Preview {
Essentials14_2Code()
}
struct Essentials14_2Points: View {
var body: some View {
ScrollView{
Text(pointEssentials14_2)
}
}
} #Preview {
Essentials14_2Points()
}
struct Essentials14_2WebView: UIViewRepresentable {
let searchURL: URL
func makeUIView(context: Context) -> WKWebView {
let view = WKWebView()
let request = URLRequest(url: searchURL)
view.load(request)
return view
}
func updateUIView(_ uiView: WKWebView, context: Context) {
}
}
struct Essentials14_2WEB: View {
private var url:URL = URL(string: urlEssentials14_2)!
var body: some View {
Essentials14_2WebView(searchURL: url)
}
} #Preview {
Essentials14_2WEB()
}
//タイトル
let essentialsChapter14NavigationTitle = "第14章"
let essentialsChapter14Title = "第14章 コレクション:配列と辞書(ディクショナリ)"
let essentialsChapter14_1SubTitle = "第1節 配列"
let essentialsChapter14_2SubTitle = "第2節 辞書(ディクショナリ)"
//コード
let codeEssentials14_1 = """
/**:-------------------
Essentials 第14章 配列
---------------------*/
//型指定なし
var fruitsBaskets14_1 = ["🍏","🍌","🍇","🍓"]
//型指定あり
var fruitsBaskets14_2:[String] = ["🍈","🍍","🍋","🍉"]
//インスタンス
var fruitsBaskets14_3 = [String]()
var fruitsPrices14_4 = [Float]()
//インスタンスに初期値を設定
var fruitsBaskets14_5 = [String](repeating: "りんご", count: 3)
//実行
print(fruitsBaskets14_5.count)
//配列を結合
var fruitBaskets14_6 = fruitsBaskets14_1 + fruitsBaskets14_2
//実行
print(fruitBaskets14_6.self)
//条件分岐
if fruitsBaskets14_3.isEmpty {
print("値が何もないぞ👀")
} else {
print("値があるぞ👀")
}
//りんごにアクセス
print(fruitsBaskets14_1[0])
//バナナにアクセス
print(fruitsBaskets14_1[1])
//シャッフル
let shuffledFruitsBaskets14_7 = fruitBaskets14_6.shuffled()
print(shuffledFruitsBaskets14_7.self)
//ランダム
let randomFruitsBaskets14_8 = shuffledFruitsBaskets14_7.randomElement()
print(randomFruitsBaskets14_8!.self)//強制アンラップして〜〜
//要素に桃を追加
fruitsBaskets14_2 += ["🍑"]
//実行
print(fruitsBaskets14_2.self)
//結合のやつをまんま実行
print(fruitBaskets14_6.self)
//結合し直してあげる
var combinedFruits14_9 = fruitsBaskets14_1 + fruitsBaskets14_2
print(combinedFruits14_9.self)
//りんごとバナナの間にもう一個🍑入れてみよう
combinedFruits14_9.insert("🍑", at: 1)
print(combinedFruits14_9)
//最後の🍑を削除
combinedFruits14_9.removeLast()
print(combinedFruits14_9)
//さっきの🍑も削除
combinedFruits14_9.remove(at: 1)
print(combinedFruits14_9)
//反復
for fruits in combinedFruits14_9 {
print(fruits)
}
//いったん全要素を削除
combinedFruits14_9.removeAll()
print(combinedFruits14_9)
//8個の要素を追加
for n in 0...8 {
combinedFruits14_9.insert("🍑", at: 0)
}
print(combinedFruits14_9.self)
//いったん全要素を削除
combinedFruits14_9.removeAll()
//元に戻す
combinedFruits14_9 = fruitsBaskets14_1 + fruitsBaskets14_2
print(combinedFruits14_9)
//キーワードを使って
combinedFruits14_9.forEach{
print($0)
}
//八百屋
var yaoya14_10:[Any] = ["🍏",123]
var yaoya14_11:[Any] = ["🍏",123,"🍌",200]
var yaoya14_12:[Any] = ["🍏","🍌",123,200]
//繰り返しで出力
yaoya14_12.forEach{
print($0)
}
for item in yaoya14_12 {
print(item)
}
//キャスト〜〜〜
//for item in yaoya14_12 {
// print(item as!Int * 100)
//}
"""
let codeEssentials14_2 = """
/**:-------------------
Essentials 第14章 辞書
---------------------*/
var yaoya14_13:[Int: String] = [1:"🍏",2:"🍌",3:"🍇",4:"🍓",5:"🍈",6:"🍍",7:"🍋",8:"🍉"]
print(yaoya14_13[2]!)
//キーと値を分けた配列を結合
var yaoyaKeys14_14 = [1,2,3,4,5,6,7,8]
var yaoyaValues14_14 =
["🍏","🍌","🍇","🍓","🍈","🍍","🍋","🍉"]
var yaoya14_14 = Dictionary(uniqueKeysWithValues: zip(yaoyaKeys14_14, yaoyaValues14_14))
print(yaoya14_14)
print(yaoya14_14.sorted(by: <))
//1から順に番号を振るだけ
var yaoya14_15 = Dictionary(uniqueKeysWithValues: zip(1..., yaoyaValues14_14))
print(yaoya14_15)
var sortedYaoya14_16 = yaoya14_15.sorted{$0.key < $1.key }
print(sortedYaoya14_16)
for element in sortedYaoya14_16 {
print("\\(element.key):\\(element.value)")
}
//個数
print("項目数は、\\(sortedYaoya14_16.count)だぜ!")
//キーが3の値を呼び出し
print(yaoya14_13[3]!)
//存在しないキーにアクセスしてみると、、、
print(yaoya14_13[9,default:"木梨(キーなし)さん"])
//🍑ちゃんを逆に9キーを作って追加してみる
yaoya14_13[9] = "🍑"
print(yaoya14_13[9,default:"木梨(キーなし)さん"])
print(yaoya14_13)
//🍑から🍐へ
yaoya14_13.updateValue("🍐", forKey: 9)
print(yaoya14_13[9,default:"木梨(キーなし)さん"])
print(yaoya14_13)
//🍐を値のみ削除
yaoya14_13[9] = ""
print(yaoya14_13[9,default:"木梨(キーなし)さん"])
print(yaoya14_13)
//値が空欄判定を行い、空欄の場合はキーごと削除
if yaoya14_13[9] == "" {
yaoya14_13[9] = nil
print(yaoya14_13[9,default:"木梨(キーなし)さん"])
print(yaoya14_13)
}
//7キーを削除
yaoya14_13.removeValue(forKey: 7)
print(yaoya14_13)
//キーと値を使って商品番号と商品名を表示
for (key,value) in yaoya14_13 {
print("商品番号\\(key)は、\\(value)です")
}
//ソートしたヤツで試すと、、、
for (key,value) in sortedYaoya14_16 {
print("商品番号\\(key)は、\\(value)です")
}
"""
//ポイント
let pointEssentials14_1 = """
①配列の数え方(位置)は、プログラミング言語によりけりなんだけど、
左から0始まり : 左から1個目が0 👈 Swiftとか最近のはこっち
左から1始まり : 左から1個目が1 👈 COBOLとかはたしかこっち
て違いがあるから気をつけてね👀
②要素の追加をした後は、どっちの値を結果として出したいのか
で処理の順序を変える
👉追加前のままでいいか、追加後を含めたいか
③理由は簡単で、
let = 定数で定義しているから
配列に関しても、その後も変更される可能性がある場合は、
基本、変数=varで定義してあげる
④今までの処理で、
追加/挿入/削除/繰り返し
で結構、配列の値を変更してしまっているんだけど、みて貰えばわかるけど、オイラは、
結合後の配列しか使ってないよね?
これはなぜかと言えば、
結合元の配列さえ残しておけば、すぐに元に戻すことができるから
⑤「クライアントさんなんて、DBとか配列なんてよくわかってない」
「まだここの値段が決まってないんだけど、先にアプリを作って欲しい」
なんかで
こんなデータをCSVやLogなんかで出して要求してくるなんてザラ
だから、
応急的にやる時にはAnyを使うパターンもある
↓
規則性が分かってから、データを整理してわかりやすい配列や辞書にしてあげる
⑥頭の中だけでコードは書かずに、必ずコードを書いたら想定通りに動かした方がいい
"""
let pointEssentials14_2 = """
ここでポイント①
ユニークなキーで補完していて、キーには、以下の型しかできないみたいね
・String
・Int
・Double
・Bool
ま、やったことがある人間からしたら、「そりゃそーだし、それだけありゃ十分だろ」って感じなんだけど、やったことがない人にはイメージが湧かないだろうから
"""
//URL
let urlEssentials14_1 = "https://note.com/m_kakudo/n/nb2031fc09971"
let urlEssentials14_2 = "https://note.com/m_kakudo/n/n034b91bea871"
![](https://assets.st-note.com/img/1709446957205-wS7QmdrAOd.png?width=1200)
次回からコイツをコピーして新しいファイルに貼り付けて、
章ごとにビューを増やそう。
っと、書いてなかったので、今回のコード💦
import SwiftUI
import WebKit
//iOSApp17DevelopmentEssentialsCh16.swift
//ビュー管理構造体
struct ListiOSApp17DevelopmentEssentialsCh16: Identifiable {
var id: Int
var title: String
var view: ViewEnumiOSApp17DevelopmentEssentialsCh16
}
//遷移先の画面を格納する列挙型
enum ViewEnumiOSApp17DevelopmentEssentialsCh16 {
case Sec1
}
//各項目に表示するリスト項目
let dataiOSApp17DevelopmentEssentialsCh16: [ListiOSApp17DevelopmentEssentialsCh16] = [
ListiOSApp17DevelopmentEssentialsCh16(id: 1, title: essentialsChapter16SubTitle, view: .Sec1)
]
struct iOSApp17DevelopmentEssentialsCh16: View {
var body: some View {
VStack {
Divider()
List (dataiOSApp17DevelopmentEssentialsCh16) { data in
self.containedViewiOSApp17DevelopmentEssentialsCh16(dataiOSApp17DevelopmentEssentialsCh16: data)
}
.edgesIgnoringSafeArea([.bottom])
}
.navigationTitle(essentialsChapter16NavigationTitle)
.navigationBarTitleDisplayMode(.inline)
}
//タップ後に遷移先へ遷移させる関数
func containedViewiOSApp17DevelopmentEssentialsCh16(dataiOSApp17DevelopmentEssentialsCh16: ListiOSApp17DevelopmentEssentialsCh16) -> AnyView {
switch dataiOSApp17DevelopmentEssentialsCh16.view {
case .Sec1:
return AnyView(NavigationLink (destination: Essentials16()) {
Text(dataiOSApp17DevelopmentEssentialsCh16.title)
})
}
}
} #Preview {
iOSApp17DevelopmentEssentialsCh16()
}
//Essentials16.swift
struct Essentials16: View {
var body: some View {
VStack{
TabView {
Essentials16Points()
.tabItem {
Image(systemName: pointImageTab)
Text(pointTextTab)
}
Essentials16WEB()
.tabItem {
Image(systemName: webImageTab)
Text(webTextTab)
}
}
}
}
} #Preview {
Essentials16()
}
struct Essentials16Points: View {
var body: some View {
ScrollView{
Text(pointEssentials16)
}
}
} #Preview {
Essentials16Points()
}
struct Essentials16WebView: UIViewRepresentable {
let searchURL: URL
func makeUIView(context: Context) -> WKWebView {
let view = WKWebView()
let request = URLRequest(url: searchURL)
view.load(request)
return view
}
func updateUIView(_ uiView: WKWebView, context: Context) {
}
}
struct Essentials16WEB: View {
private var url:URL = URL(string: urlEssentials16)!
var body: some View {
Essentials15WebView(searchURL: url)
}
} #Preview {
Essentials16WEB()
}
//タイトル
let essentialsChapter16NavigationTitle = "第16章"
let essentialsChapter16Title = "第16章 SwiftUIの概要"
let essentialsChapter16SubTitle = "第1節 SwiftUIの概要"
//ポイント
let pointEssentials16 = """
◾️SwiftUIの歴史
1 SwiftUIは2019年のWWDCで発表
2 アプリの基本システムによる開発の全体的に新しいアプローチとして刷新
3 よりシンプルに、より早く、よりバグが少なくのスローガンの下、よりリアルタイムにテストもできるようにライブプレビューも搭載
◾️UIKitとインターフェースビルダー
1 UIKitもSwiftUIもライブラリの中にあるフレームワークのひとつ
2 Xcodeにはインターフェースビルダーと呼ばれるツールが搭載されてる
3 インターフェースビルダーはアプリの各画面を作るための強力なツール
4 アトリビュート検証なんかもできるように配置してる
5 縦向きか横向きかといったものまで含め、位置とかサイズまでコンポーネントが各シーンの振る舞いを定義する機能も備えてる
6 つまり、ユーザーの行動(イベント)に応じて、動的にアプリの表示が柔軟に変わるようにコンポーネントは設計されてる
7 上記を網羅しながら、開発の各段階で必要と予想される
・コンパイラ
・シミュレーター
・実機テスト
なんかもできるように工夫されてる
◾️基本文法
1 これまでのインターフェースビルダーやUIKitにおけるアプローチとは違う
2 シーンを作り上げるために、レイアウトの詳細やコンポーネントの表示などの詳細を手動でデザインしていく方法を採る
3 SwiftUIは、シンプルで直感的な文法で、レイアウトを描写できるようにした
4 別の言い方をすれば、複雑なレイアウトビルダーなんかの心配なしに、操作画面を表現できるってこと。これは、レイアウト自体が、スタックやフォーム、リストと言ったレイアウトマネージャ機能も構成してるってことを述べていて、「ボタンに文字を表示させる」、「ラベルに色を付ける」、「タップで何かの処理をさせる(イベント)」みたいに、アトリビュートを設定するモディファイアを使えるようになったことを意味してるが、複雑で入り組んだ詳細な位置なんかについては、SwiftUIで機械的に制御されたレイアウトが実現可能。
5 これらのビューの階層構造は非常にシンプルで、小さなコンポーザーとサブビューを使い回すことを想定してるので、複雑なビューでも簡単に作ることができる。
6 プレビューキャンパスを使っているので、レイアウトの宣言もテストもリアルタイムでレイアウトの表示を確認できる。
7 また、ライブプレビューを使うことで、シミュレーターや実機テストで実行する必要もない。
◾️データ駆動
1 SwiftUIが発表される前だと、必要だったデータ駆動させるためのユーザーによる手法が不要になった。
2 これまでだと、例えばボタンをタップさせた際のデータとの連動には、特殊な手法をユーザーで設定する必要があったが、データと密接に繋がっているSwiftUIではそんなものがいらなくなり、操作画面とアプリの裏側のデータの架け橋になるロジックを書けばいいだけになった。
3 👉複雑な処理を自分で書く必要がなくなり、バインドさせるだけでデータベースと連動でき、反応もよくなった
◾️SwiftUIかUIKitか
トレードオフの関係じゃない
👉どっちを使うかはその時々で選べばいいだけの話。
そんなことよりも重要なのは、
1 いずれのフレームワークもまだ成熟してない=進化し続けている
2 SwiftUIだけで実現できない機能もまだまだあるので、UIKitやインターフェースビルダーとの統合も必要になる可能性がある
ってこと。
まとめ
ちょっと大上段からSwiftUIをこの章では語りすぎたから、これ以降でもっとSwiftUIの深いところ(essentails:本質)を探求してくぜ!
"""
//URL
let urlEssentials16 = "https://note.com/m_kakudo/n/n42b079fa8508"
この記事が気に入ったらサポートをしてみませんか?