SwiftUI + MVVM + Realm で iOS アプリを開発

## 内容
- SwiftUI を利用したアプリを開発
- アーキテクチャは MVVM を利用
- データの永続化に Realm を使用

## 開発したアプリ
メモアプリ

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199441/8fda8a53-3ac0-c7bb-bda2-c66dc8bed6de.png" width="200">


## 開発環境
### ハードウエア
|項目||
|---|---|
|PC| MacBook Air(M1,2020） メモリ：16GB ストレージ：1TB |
|実機 | iPhoneSE（2nd Generation 128GB iOS 15.3.1） |
|PCと実機を接続する|[USB-C Digital AV Multiportアダプタ](https://www.apple.com/jp/shop/product/MUF82ZA/A/usb-c-digital-av-multiport%E3%82%A2%E3%83%80%E3%83%97%E3%82%BF)|

### ソフトウエア
|項目||
|---|---|
|言語|Swift 5.5.2|
|IDE|Xcode Ver 13.2.1|
|DB|Realm|
|DB管理|Realm Studio|
|バージョン管理|GitHub|

※ Realm は GitHub の Swift Package Manager を利用して導入

### コード （一部）
```swift:Model
import Foundation
import RealmSwift

class Memo: Object,Identifiable {
    @objc dynamic var text = ""
    @objc dynamic var postedDate = Date()
}

extension Memo {
    private static var config = Realm.Configuration(schemaVersion: 1)
    private static var realm = try! Realm(configuration: config)
    
    static func findAll() -> Results<Memo> {
        realm.objects(Memo.self)
    }
    
    static func add(_ memo: Memo) {
        try! realm.write {
            realm.add(memo)
        }
    }
    
    static func delete(_ memo: Memo) {
        try! realm.write {
            realm.delete(memo)
        }
    }
    
    static func delete(_ memos: [Memo]) {
        try! realm.write {
            realm.delete(memos)
        }
    }
}
```

```swift:ViewModel
import Foundation

class MemoViewModel: ObservableObject {
    @Published var memos: [Memo] = Array(Memo.findAll())
    
    func add(text: String){
        guard !text.isEmpty else { return }
        let memo = Memo()
        memo.text = text
        self.memos.append(memo)
        Memo.add(memo)
    }
}

```

```swift:View
import SwiftUI
import RealmSwift

struct ContentView: View {
    @EnvironmentObject var memoVM: MemoViewModel
    @State var enteredText: String = ""
    
    var body: some View {
        var memos = memoVM.memos.sorted { $01.postedDate < $1.postedDate }
        
        NavigationView {
            VStack {
                HStack {
                    TextField("Enter Text", text: $enteredText)
                        .padding(7)
                        .border(.gray)
                        .cornerRadius(5)
                    
                    Button(action: {
                        addMemo(text: enteredText)
                    },label: {
                        Text("Add")
                            .bold()
                    }
                    )
                        .buttonStyle(.borderedProminent)
                }
                .padding()
                
                List(memos){ memo in
                    VStack(alignment: .leading){
                        Text(memo.text)
                        Text((memo.postedDate.description))
                            .font(.subheadline)
                            .foregroundColor(.gray)
                    }
                }
                .navigationTitle("Memo")
            }
            
        }
    }
    
    private func addMemo(text: String){
        memoVM.add(text: text)
    }
}

struct ContentView_Previews: PreviewProvider {
    
    static var previews: some View {
        ContentView()
            .environmentObject(MemoViewModel())
    }
}
```

## 備考
Realm Studio を利用するとデータを確認可能
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199441/af02b20a-ca58-efce-e6c0-9c6055319451.png" width="300">


## 参考資料
https://tech-blog.rakus.co.jp/entry/20210331/swift