# FireBase for SwiftUI小纸条（二）



## 创建FireBase中的Realtime Database实例

首先我们需要在FireBase项目管理控制台中找到Realtime Database：

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1660946175699/p-PsIpZaJ.png align="left")

点击创建数据库，选择一个数据库所处的位置：

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1660946252390/Ir8Dc-bkG.png align="left")

接下来需要为数据库设置安全规则，因为我们是用来测试，先设置为测试模式，将来再考虑安全规则：

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1660946643933/dlpHLbd5v.png align="left")

这样就完成了一个实时数据库实例的创建了。当你创建完成一个数据库实例后，需要得到你新的Xcode的GoogleService-info.plist文件。首先点击项目概览右侧的项目设置：

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1660951559978/Mx_B3Q4Q7.png align="left")

然后向下滚动，可以看到你的应用：

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1660951791757/VoeXH5Y9e.png align="left")

这里可以下载到更新后的plist文件，如果更新到Xcode后，你会发现这个plist文件里有一个DATABASE_URL的条目出现：

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1660951873985/_GoIr2DxC.png align="left")


## 为你的项目加入Realtime Database支持

首先按照[FireBase for SwiftUI小纸条（一）](https://blog.hdcola.one/firebase-for-swiftui-1)初始化你的项目。如果你之前已经创建好了，但是没有在项目中勾选上Realtime Database所需要的`FirebaseDatabase`和`FirebaseDatabaseSwift`条目，哪么你可以在项目中自己去添加：

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1660949069685/imCxDa4JB.png align="left")

## 写入数据

### 简单写入

写入一个数据其实非常简单，与我们向一个属性set一样。首先，我们写一个ViewModel，为View提供支持：

```
import Foundation
import FirebaseDatabase
import FirebaseDatabaseSwift

class WriteViewModel: ObservableObject{
    private let ref = Database.database().reference()
    
    func writeNewValue(value: String){
        ref.setValue(value)
    }
}
```

我们使用`Database.database().reference()`得到去操作数据库的一个接口引用实例，然后调用`ref.setValue(value)`来将数据存储至实时数据库。setValue支持写入字符串（NSString）、数字（NSNumber）、字典（NSDictionary）和数组（NSArray）。

接下来，我们准备一个View来让我们在App里操作write行为：

```
import SwiftUI

struct WriteView: View {
    @StateObject var vm = WriteViewModel()
    @State var content: String = ""
    
    var body: some View {
        VStack{
            Text("Write Content")
            TextEditor(text: $content)
                .border(.black)
            Button{
                vm.writeNewValue(value: content)
            }label: {
                Text("Push")
            }.buttonStyle(.borderedProminent)
        }
        .padding()
    }
}
```

来看看效果吧：

![write.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1661000768310/H_Y58R4RQ.gif align="left")

### 自动创建子节点

在Realtime Database数据库中存储的是一个JSON，但是为了不大规模的处理全量数据，引入了节点的概念，我们可以先来试试自动创建子节点的感觉，修改下ViewModel：

```
import Foundation
import FirebaseDatabase

class WriteViewModel: ObservableObject{
    private let ref = Database.database().reference()
    
    func writeNewValue(value: String){
        ref.childByAutoId().setValue(value)
    }
}
```

通过`childByAutoId()`我们可以得到一个新的唯一子节点，效果如下：

![childByAudoId.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1661002665267/iirzHV3qM.gif align="left")

### 指定节点写入数据

如果想要向自己指定的子节点写入数据，只需要指定节点名称就好：

```swift
ref.child("Game1").setValue(value)
```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1661002965630/9IO0nRmmr.png align="left")

### 多级子节点

如果想要多级子节点，其实也非常方便：

```swift
ref.child("Game1").child("user1").setValue(value)
```

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1661003106286/Sdm3Pismu.png align="left")

### 写入对象

只需要将一个class支持序列化成JSON，哪么我们就可以非常简单的将一个对象存入实时数据库中了。首先，我们准备一个class定义，并扩展它可以序列化成为JSON：

```swift
class User: Encodable{
    var username: String = ""
    var level: Int = 1
}

extension Encodable{
    var toDictionary: [String: Any]?{
        guard let data = try? JSONEncoder().encode(self) else{
            return nil
        }
        return try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any]
    }
}
```

再将写入改为以下代码：

```swift
        let user = User()
        user.username=value
        ref.child(user.username).setValue(user.toDictionary)
```

你会看到这样的结果：

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1661003981216/ApJyL_a_L.png align="left")

### 写入数组

如果我们想将User变为一个数组，如何存入数据库中呢？只需要一个数组即可，但是因为User是一个class，并不是一个JSON的基础数据类型，所以我们还是需要借助toDictionary来存储：

```swift
        var users = [Any]()

        for i in 1...3{
            let user = User()
            user.username="\(value)\(i)"
            user.level=i
            users.append(user.toDictionary as Any)
        }
        ref.childByAutoId().setValue(users)
```

存入的数值就像这样：

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1661030400389/QTwYFcPtH.png align="left")

## 附

Firebase的变动是非常频繁的，文档里也会遇到很多不足，但是比起苹果的文档，已经好了很多了。这里留下一些我自己也常用到的页面（不确定是不是一直有效，如果有问题请告诉我）：

- Firebase官方有关写入的说明文档：https://firebase.google.com/docs/database/ios/read-and-write?authuser=0
- 选择数据库：Cloud Firestore 或 Realtime Database： https://firebase.google.com/docs/database/rtdb-vs-firestore
- Database 类参考： https://firebase.google.com/docs/reference/swift/firebasedatabase/api/reference/Classes/Database?authuser=0
- DatabaseReference类参考： https://firebase.google.com/docs/reference/swift/firebasedatabase/api/reference/Classes/DatabaseReference?authuser=0
- 
