PUROGU LADESU

ポエムがメインのブログです。

【Swift】Firebase用のモデルをstructで作成

Firebase用のモデルをstructで作成

  • 必須のフィールドには初期値を設定しないことで初期化の時点で入力漏れを防ぐ。
  • nullを許容する場合Optional型にする。その場合分岐が必要。
  • nullの場合はNSNull()を入れる。RDBみたいにNullを格納するというよりNull型になる。
  • FirebaseFirestore.GeoPoint 、FirebaseFirestore.Timestampなどは読み込み時と保存時にSwiftの型から変換する。
  • enumは保存時はrawValueを入れて、読み込み時はenumに戻す。
struct User {
    var uid: String
    var name: String
    var imageUrl: String = ""
    var memberClass: MemberClass = .free
    var createdAt: Date?
    var currentLocation: CLLocationCoordinate2D?

    // String型にすれば勝手にrawValueがcaseと同じになる
    enum MemberClass: String {
        case free
        case paid
    }

    // 最低限の項目で初期化する
    init(uid: String, name: String) {
        self.uid = uid
        self.name = name
    }
   
    // Firebaseから取り出す場合
    init(_ uid: String, data: [String: Any]) {
        self.uid = uid
        name = data["name"] as? String ?? ""
        imageUrl = data["imageUrl"] as? String ?? ""
        if let memberClassString = data["memberClass"] as? String {
            // stringをenumに変換
            if let memberClass = MemberClass(rawValue: memberClassString) {
                self.memberClass = memberClass
            }
        }
        if let geopoint = data["currentLocation"] as? FirebaseFirestore.GeoPoint {
            currentLocation = CLLocationCoordinate2DMake(geopoint.latitude, geopoint.longitude)
        }
        if let dataCreatedAt = data["createdAt"] as? FirebaseFirestore.Timestamp {
            createdAt = dataCreatedAt.dateValue()
        }
    }
    
    // Firebaseに入れる場合
    var dictionary: [String: Any] {
        var dictionary = [String: Any]()
        dictionary["name"] = name
        dictionary["imageUrl"] = imageUrl
        dictionary["memberClass"] = memberClass.rawValue
        if let currentLocation = currentLocation {
            dictionary["currentLocation"] = FirebaseFirestore
                        .GeoPoint(latitude: Double(currentLocation.latitude),
                                  longitude: Double(currentLocation.longitude))
        } else {
            dictionary["currentLocation"] = NSNull() // Nullの場合
        }
        dictionary["createdAt"] = FieldValue.serverTimestamp()
        return dictionary
    }
}

使い方

  • Firebaseから取り出す場合の初期化関数initを用意する。User(document.documentID, data: document.data()) でstructに値が格納される。
docRef.getDocument { (document, error) in
  if let document = document, document.exists {
      let data = document.data() ?? [:]

          user = User(document.documentID, data: data)

  } else {
      print("User not found")
  }
  • Firebaseに入れる場合にdictionaryを返す関数を[String: Any]で用意する。setData(user.dictionary)でdictionaryに変換して取り出せる。
let docRef = firestore.collection("Users").document()
docRef.setData(user.dictionary) { error in
    if let error = error {
        print("Error updating document: \(error)")
        
    } else {
        print("Document added with ID: \(docRef.documentID)")
    }
}