学習記録

プライベートで学習した内容の備忘録

iOSアプリを作るためにSwift UIを勉強していて気になったところ

自分が直感でわからなかったところ、忘れてしまっていたところを主に残しておく

文字列埋め込み

以下のようにバックスラッシュと()を使用して、変数を埋め込める ※Macでは「option + ¥」でバックスラッシュを入力可能

let name = "taro"
print("\(name)さん こんにちは!")

デバッグログ出力

print("xxx")で出力可能。

(メニューの「View」→「Debug Area」→「Activate Console」でConsoleが開き、そこで出力が確認できる)

import SwiftUI


struct ContentView: View {
  
  var body: some View {
    VStack {
      Button(action: output){
        Text("call")
      }
    }
  }
  func output() {
    print("Hello World") 
  }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

データモデルの作り方

  1. 「File」→「New」→「File...」→「Data Model」を選択

  2. 任意の名前を付ける

  3. 画面下部の「Add Entity」でEntityを作成する

  4. Atrributes欄の「+」ボタンを押下して、Attributeを追加する

※個人的な理解としてはEntityがテーブル、Attributesがカラムである認識

データモデルの使い方

  1. Persistenceを扱うファイルを作成する

適当にswiftファイルを作成してPersistenceを扱う構造体を作成する

import CoreData ⭐️

struct PersistenceController {
  // NSPersistentContainerを定義する
  let container: NSPersistentContainer
  
  init() {
    // 引数にはModel Fileの名前を入れる
    container = NSPersistentContainer(name: "MyCoreDataModel") ⭐️
    
    container.loadPersistentStores(completionHandler: {(storeDescription, error) in
      if let error = error as NSError? {
        fatalError("error = \(error), userInfo = \(error.userInfo)")
      }
    })
  }
}
  1. エントリポイントでPersistenceを扱う構造体から「viewContext」を取得して、Viewの環境変数に入れる
import SwiftUI

@main
struct WorkingApp: App {
  let persistenceController = PersistenceController()
  
  var body: some Scene {
      WindowGroup {
        ContentView()
          .environment(\.managedObjectContext, persistenceController.container.viewContext) ⭐️
      }
  }
}
  1. viewContextの取り出し

呼び出し先の「ContentView」では以下のように実装する

struct ContentView: View {
  @Environment(\.managedObjectContext) var viewContext ⭐️環境変数から「viewContext」を取り出し

  var body: some View {
    VStack {     
      SubView().environment(\.managedObjectContext, viewContext) ⭐️他のViewを呼び出す際にも、同じようにそのViewの環境変数にセットすればviewContextを渡せる
    }
  }
  1. DBへのアクセス

「@FetchRequest(sortDescriptors: [])」でソート方法を指定(※空配列を指定する場合は、指定なしとなる) FetchedResultsで「Entity」を指定して変数を定義する

truct SubView: View {
  @Environment(\.managedObjectContext) var viewContext
  @FetchRequest(sortDescriptors: []) ⭐️
  var humans: FetchedResults<HumanData> ⭐️HumanDataというEntityを作成した場合の例
  
  
  var body: some View {
    List {
      ForEach(humans) { human in
        Text(human.name!) ⭐️値取り出し
      }
      Button(action: addHuman) {
        Text("add") ⭐️追加ボタン
      }
      Button(action: deleteHuman) {
        Text("delete") ⭐️削除ボタン
      }
    }
  }

  func addHuman() {
    let newHuman = HumanData(context: viewContext) ⭐️新しいレコードを作成する
    newHuman.name =  "テストマン"
    
    do {
      try viewContext.save() ⭐️保存
    } catch {
      print("error")
      fatalError("失敗")
    }
  }
  
  func deleteHuman() {
    
    for human in humans {
      viewContext.delete(human) ⭐️該当のレコードを削除
    }
    do {
      try viewContext.save() ⭐️保存
    } catch {
      print("error")
      fatalError("失敗")
    }
  }

HStack VStack

HStack: 横並び VStack: 縦並び

for

こんな感じで記述する(1...10とすれば1~10まで回せる) ※以下の例は9まで表示

for i in 1..<10 {
    print(i)
}

Swift UIのForEach

Listにネストして以下のように使用できる

struct ForEachPractice: View {
    var body: some View {
      List {
        ForEach(0...10) { num in
          Text("\(num) !")
        }
      }
    }
}

Viewの更新

参考:SwiftUIの機能 @State, @ObservedObject, @EnvironmentObjectの違いとは| 開発者ブログ | 株式会社アイソルート

@State

@Stateを使用すると、その変数の更新時にViewが更新される

import SwiftUI

struct StatusPractice: View {
  @State var test = "xxx" ⭐️ struct内では、@Stateを使用しなければ値を変更できないぽい
    var body: some View {
      VStack {
        Button(action: {self.test = "yyy"}) {
          Text("call")
        }
        Text(test)
      }
    }
}

@ObservedObject

@ObservedObjectを使用すると、クラスの特定の変数(@Publishedをつけた変数)の更新を検知してViewが更新される

struct ObservedObjectPractice: View {
  @ObservedObject var testData = TestData(v: "xxx") ⭐️@ObservedObjectを使用
  
    var body: some View {
      VStack {
        Button(action: {self.testData.value = "yyy"}) {
          Text("call")
        }
        Text(testData.value)
      }
    }
}

class TestData: ObservableObject { ⭐️ObservableObjectを継承
  @Published var value: String ⭐️@Publishedをつけた変数が更新されるとViewが更新される
  init (v: String) {
    self.value = v 
  }
}

@EnvironmentObject

@EnvironmentObjectを使用すると、@ObservedObjectと同様にクラスの特定の変数の変更を検知してViewが更新される @ObservedObjectとの違いは、複数のViewで共通のインスタンスを参照できる(アプリ全体の共通プロパティとして扱われるよう)

つまり、アプリ全体で共通のプロパティとなります。

以下の例ではContentView1、ContentView2でもxxx→yyyに変更されることが確認できる

import SwiftUI
truct EnviromentObjectPractice: View {
  @EnvironmentObject var testData: TestData ⭐️@EnvironmentObjectを使用
  var body: some View {
    VStack{
      Button(action: {self.testData.value = "yyy"}){
        Text("call")
      }
      Text("ParentView: \(testData.value)")
      ContentView1()
      ContentView2()
    }
  }
}

class TestData: ObservableObject {
  @Published var value: String ⭐️@Publishedをつけた変数が更新されるとViewが更新される
  init (v: String) {
    self.value = v
  }
}

struct ContentView1:View {
  @EnvironmentObject var testData: TestData
  
  var body: some View  {
    Text("ContentView1: \(testData.value)")
  }
}
struct ContentView2:View {
  @EnvironmentObject var testData: TestData
  
  var body: some View  {
    Text("ContentView2: \(testData.value)")
  }
}

struct EnviromentObjectPractice_Previews: PreviewProvider {
    static var previews: some View {
      EnviromentObjectPractice().environmentObject(TestData(v:"xxx")) ⭐️「environmentObject」で呼び出し側から値を指定する
    }
}