はじめに
初めまして,大学1年生のkigです.
大学の課題でSwiftを使用して作成したアプリを,春休み中にリリースするため,機能追加や改良を行いました.今回は,Swiftでのアプリ制作でよく使用したコードや,必須なコードを誰にでも分かりやすいように,自分のアウトプットも兼ねてまとめてみました.サンプルコードもあるので,ご活用ください.
SwiftUIの文字表示(Stack)やボタン,@State,var,画面遷移...などの基盤部分は,Rikuto Sato様の【総集編】【SwiftUI開発講座】ゼロからのSwiftUI開発!~3時間ぶっ通しで基本をマスターしよう~にて,とても分かりやすい解説をしてくださっているので,こちらと併せることで様々なコードを書くことができるようになると思います.
目次
- データの永続化1(AppStorage)
- データの永続化2(UserDefault)
- Viewを表示する瞬間に処理を実行する(.onAppear)
- ボタンタップ,画面遷移と同時に処理を実行(.simultaneousGesture)
- ◯秒ごとに実行(Timer)
- おまけ 広告をつける(参考サイトの紹介のみ)
1. データの永続化1(AppStorage)
ここでは,+ボタンを押すと1に1ずつ加算され,-ボタンを押すと,100から1ずつ減算されるアプリを作成しました.
import SwiftUI
struct ContentView: View {
//変数宣言
@State var up = 1
@State var down = 100
var body: some View {
VStack { //{}内を縦向きに表示する
HStack{ //{}内を横向きに配置
Text("\(up)") //変数oneを表示
.font(.system(size: 40)) //文字の大きさを指定
Button(action: {
//ボタンが押された時の処理
up += 1
}, label: {
//ボタンの見た目を記述
Text("+")
.font(.system(size: 40))
})
}
.padding() //1+ と -100の間に少しスペースを作る
HStack{
Button(action: {
down -= 1
}, label: {
Text("-")
.font(.system(size: 40))
})
Text("\(down)")
.font(.system(size: 40))
}
}
}
}
//ここから下は消しても問題ないため,次回から省略する(Xcode内のプレビューが消えるだけ)
#Preview {
ContentView()
}
このコードでは,1度アプリを閉じるとupとdowwnの値が初期値に戻ります(up = 1とdown = 100).ここで,AppStorageを使うことで,アプリを1度閉じて再度開いても,upとdownが初期値に戻らなくなります.変更部分は
...
struct ContentView: View {
//変数宣言
@State var up = 1
@State var down = 100
var body: some View {...
の変数宣言をしている部分(2行だけ)です.下のように書き換えます.
...
//変数宣言
@AppStorage ("upKey") var up = 1
@AppStorage ("downKey") var down = 100
...
@AppStorage ("キー値") var 変数名 = 値
で変数宣言を行います.すると,値とキー値(文字列)が結びつき,アプリが削除されるまで端末内に保存されます.
しかし
このAppStorageですが,何でもかんでも保存できるわけではなく,配列など一部対応していない型があります.ここで登場するのがUserDefaultです.
参考サイト:【SwiftUI】@AppStorageでデータを永続化(端末保存)する
2. データの永続化2(UserDefault)
アプリ制作に配列は必須だと思います.が,UserDefaultの使い方を調べ,理解するのが一番大変でした.(難しそうなコードや単語が多かった...) まず,1.のコードで配列を使用します.
import SwiftUI
struct ContentView: View {
//変数宣言
@State var number = [1, 100]
var body: some View {
VStack { //{}内を縦向きに表示する
HStack{ //{}内を横向きに配置
Text("\(number[0])")
.font(.system(size: 40)) //文字の大きさを指定
Button(action: {
//ボタンが押された時の処理
number[0] += 1
}, label: {
//ボタンの見た目を記述
Text("+")
.font(.system(size: 40))
})
}
.padding() //1+ と -100の間に少しスペースを作る
HStack{
Button(action: {
number[1] -= 1
}, label: {
Text("-")
.font(.system(size: 40))
})
Text("\(number[1])")
.font(.system(size: 40))
}
}
}
}
先ほどはupとdownという変数名でしたが,この2つの変数をnumber(Int型配列)に格納しました.見た目と動作は1.と全く同じです.では早速UserDefaultを使用して,配列を保存しましょう.
import SwiftUI
struct ContentView: View {
//変数宣言
@State var number = [1, 100]
var body: some View {
VStack { //{}内を縦向きに表示する
HStack{ //{}内を横向きに配置
Text("\(number[0])")
.font(.system(size: 40)) //文字の大きさを指定
Button(action: {
//ボタンが押された時の処理
number[0] += 1
//number全体を保存
UserDefaults.standard.set(number, forKey: "numberKey")
}, label: {
//ボタンの見た目を記述
Text("+")
.font(.system(size: 40))
})
}
.padding() //1+ と -100の間に少しスペースを作る
HStack{
Button(action: {
number[1] -= 1
//number全体を保存
UserDefaults.standard.set(number, forKey: "numberKey")
}, label: {
Text("-")
.font(.system(size: 40))
})
Text("\(number[1])")
.font(.system(size: 40))
}
.padding()
//ボタン追加
Button(action: {
//ボタンを押したら,保存されたデータを読み込み
guard let defaultNumber = UserDefaults.standard.array(forKey: "numberKey") as? [Int]
else{return}
number = defaultNumber
}, label: {
Text("保存されたデータを呼び出す")
.font(.system(size: 20))
})
}
}
}
+または-ボタンを押し,加算or減算したと同時に,Number全体をNumberKeyに保存します.
//number全体を保存
UserDefaults.standard.set(number, forKey: "numberKey")
UserDefaults.standard.set(保存したい変数名, forKey: "キー値")
でAppStorageのように,キー値と変数を結びつけます.
例えば,+を4回,-を4回押したとしましょう.するとnumberは[5, 96]となります.一方で,ボタンを押すごとにnumberは保存されるため,numberKeyに結びついている値も[5, 96]になっています.この時点では保存しかしていないため,1度アプリを閉じて再度アプリを開くと,numberは[1, 100]となります(numberKeyに結びついている[5, 96]は保存されています).そのため,保存した値をnumberに代入する必要があります.([1, 100] に[5, 96]を代入する)
//ボタンを押したら,保存されたデータを読み込み
//.arrayや[Int]は,保存したい値の型によって変更する必要がある
guard let defaultNumber = UserDefaults.standard.array(forKey: "numberKey") as? [Int]
else{return}
Nnmber = defaultNumber
「保存されたデータを呼び出す」ボタンを押すことでdefaultNumberに,端末に保存してある[5, 96]を代入し,numberにdefaultNumberを代入するイメージです.以上で配列の保存,読み込みを行います.
私がUserDefaultを使えるようになった際,参考にさせていただいた動画リンクも貼りますので,是非ご覧ください.
【初心者向け SwiftUI 】UserDefaults ってなに? ~ データを簡単に保存できる便利な方法を紹介します!
3. Viewを表示する瞬間に処理を実行する(.onAppear)
また先ほどのコードを再利用します.実行していただいた方は特に感じたかもしれませんが,2.のアプリは使いずらいと思います.例えば,ゲームで「オーブの数を更新する」なんてボタンありませんよね?こちらの操作がなくとも変数は更新されるのが一般的です.そこで,モディファイア「.onAppear」の登場です..onAppearはStackやViewのモディファイアとして使用することで,そのStack,Viewが表示される直前に好きな処理を行えるというものです.つまり!先ほどのコードにて,Numberの値を表示する直前に,Default_Numberの値を代入することで,ボタンを押さずにNumberの値を更新することができます.
import SwiftUI
struct ContentView: View {
//変数宣言
@State var number = [1, 100]
var body: some View {
VStack { //{}内を縦向きに表示する
HStack{ //{}内を横向きに配置
Text("\(number[0])")
.font(.system(size: 40)) //文字の大きさを指定
Button(action: {
//ボタンが押された時の処理
number[0] += 1
//number全体を保存
UserDefaults.standard.set(number, forKey: "numberKey")
}, label: {
//ボタンの見た目を記述
Text("+")
.font(.system(size: 40))
})
}
.padding() //1+ と -100の間に少しスペースを作る
HStack{
Button(action: {
number[1] -= 1
//number全体を保存
UserDefaults.standard.set(number, forKey: "numberKey")
}, label: {
Text("-")
.font(.system(size: 40))
})
Text("\(number[1])")
.font(.system(size: 40))
}
.padding()
}
.onAppear(){
//VStackが表示される直前に,保存されたデータを読み込み
guard let defaultNumber = UserDefaults.standard.array(forKey: "numberKey") as? [Int]
else{return}
number = defaultNumber
}
}
}
VStackに.onAppearを付け,VStackが表示される直前にNumberの値を更新する処理を行っています.これで,値の更新が自動で行われるようになりました.
4. ボタンタップ,画面遷移と同時に処理を実行(.simultaneousGesture)
ここでは,ボタンタップ,または画面遷移ボタンが押された時に処理を行うことができるコードを紹介します.
import SwiftUI
struct ContentView: View {
//変数宣言
@State var count = 0
var body: some View {
NavigationStack{
NavigationLink{
//ここに count += 1 と書くとエラーになる
NextView(NextViewCount: $count)
} label: {
Text("次の画面へ移動")
}
.simultaneousGesture(TapGesture().onEnded{
//次の画面に移動するボタンを押したら,Countに1を加算
count += 1
})
}
}
}
次に,遷移後の画面のコードです.
import SwiftUI
struct NextView: View {
//ContentViewから変数の値を引き継ぐ
@Binding var NextViewCount: Int
var body: some View {
Text("\(NextViewCount)")
.padding()
}
}
NavigationLinkの{}内に画面遷移処理以外(四則演算など)を記述するとエラーになります.そのため,NavigationLinkに以下のモディファイアをつけることで,画面遷移(ボタンが押される)と同時に,関数実行などの任意の処理を行うことができます.
.simultaneousGesture(TapGesture().onEnded{
//次の画面に移動するボタンを押したら,countに1を加算
count += 1
})
他のタップ処理の参考サイト:SwiftUIでのタップ処理の実装と応用
また,他の画面遷移時に処理を実行する方法として,3.の.onAppearを使用する方法もあります.この場合,NextView(遷移先の画面)を表示する直前にNextView_Countを+1することで実装できます.
5. ◯秒ごとに実行(Timer)
最後は,◯秒ごとに処理を行うコードです.時間計測などにも使用できます.
以下のコードでは,「開始」を押すと1秒おきにCountが+1され,「終了」を押すと,それが止まるアプリを書いています.
import SwiftUI
struct ContentView: View {
//変数宣言
@State var count = 0 //秒数
@State var timer: Timer?
@State var isRunning = false //タイマーが動いているか,動いていないか
var body: some View {
//秒数表示
Text("\(count)")
//タイマー開始
Button(action: {
timeCount()
isRunning = true
}, label: {
Text("開始")
})
//タイマーが動いているなら「開始」は押せない
.disabled(isRunning == true)
.padding()
//タイマー終了
Button(action: {
//タイマーを無効にする
timer?.invalidate()
timer = nil
isRunning = false
}, label: {
Text("終了")
})
//タイマーが動いていていないなら,「終了」は押せない
.disabled(isRunning == false)
}
//1秒ごとにcountに1を加算(Intervalの値を変更することで◯秒ごとに実行,なども可能)
func timeCount(){
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) {timer in
count += 1
}
}
}
タイマーが起動している間は「開始」ボタンが押せなくなっています.この理由は,タイマーが重複して起動してしまうのを防ぐためです.タイマーが重複して起動した場合,各タイマーはそれぞれが独立して処理を行うため,1秒に何回も加算されてしまったりします.動作が重くなってしまうため,この辺りはよく動作確認をしましょう.
6.おまけ 広告をつける
SwiftUIにてアプリに広告をつける際,参考にさせていただいたサイトを紹介させていただきます.
【SwiftUI】AdMobを使って広告を実装する方法!バナーViewの作成
【SwiftUI】リワード広告の表示
最後に
ここまでSwiftでアプリ制作に使用したコードをまとめました.各コードの使用方法を考えることで,実装できるものが増えると思います!
残りの春休みの時間はUnityを勉強し,作りたいゲームの構想もできているので,リリースに向けて1から頑張っていこうと思います.
宣伝にはなりますが,今回私が製作したアプリはAppStoreにて「Dot_Touch」というアプリ名でリリースしました.将来的にはDot_TouchもUnityで作り直せたらいいなと思います.
以上です,ご覧いただきありがとうございました!