firebase의 firestore를 이용하여 사용자를 등록하고 사용자의 이메일과 택배 번호, 택배 회사에 관한 데이터를 입력시키는 작업을 진행했다.
해당 작업을 진행하면서 카카오, 애플, 이메일 회원가입을 각각 진행할 때 이메일이 같은 경우에 어떤 식으로 해당 이메일들을 구분해야 하는가에 대한 문제가 발생했다. 이 문제점은 아래 회원가입과 로그인 코드와 같이 Auth.auth().createUser(withEmail: email + "2", password: password)를 활용했다.
각각 로그인, 회원가입 시에 이메일 뒤에 구분할 수 있는 다른 문자열을 넣는 방식을 채택했다.
그리고 Create, update, delete는 firebase의 문서들을 참고하여 해결할 수 있었지만, read의 경우 현재 파이어베이스에 다음과 같이 이메일과 구조체 배열이 저장되어 있는데 이 구조체 배열을 불러오는것이 조금 어려웠다.

readTrackNumber()함수를 보면 let citiesDocument = try document.data(as: TrackInfo.self) 과 같은 로직이 존재하는데 해당 로직을 위해서는 FirebaseFirestoreSwift를 Import해주어야 한다.(이것 때문에 고생을 좀 했다..)
해당 함수를 실행시키면 미리 만들어놓은 TrackInfo모델에 해당 데이터가 들어가게 되고 변수인 trackInfo에 이를 할당해 view에서 사용하면 된다.
TrackInfo.swift
struct TrackInfo: Codable, Identifiable {
@DocumentID var id: String?
let email: String
var userTracksInfo: [Packages]?
var setEmail: [String:Any] {
return [
"email": self.email
]
}
enum CodingKeys: String, CodingKey {
case email = "email"
case userTracksInfo = "userTracksInfo"
}
}
struct Packages: Codable, Hashable {
var trackCompany: String
var trackNumber: String
var setTrackNumber: [String:Any] {
return [
"trackCompany": self.trackCompany,
"trackNumber": self.trackNumber
]
}
enum CodingKeys: String, CodingKey {
case trackCompany = "trackCompany"
case trackNumber = "trackNumber"
}
}
EmailAuthVM.swift
import SwiftUI
import Firebase
import Combine
import FirebaseFirestoreSwift
class EmailAuthVM: ObservableObject { // 사용자 Create 완료
@Published var freeboardTitle: String = ""
@Published var trackInfo: TrackInfo?
@Published var loginError: String = ""
@Published var signUpError: String = ""
@Published var pack = [Packages]()
@AppStorage("log_status") var logStatus = false
@Published var currentUser: Firebase.User?
let db = Firestore.firestore()
init() {
currentUser = Auth.auth().currentUser
}
// 로그인
func login(email: String, password: String) {
Auth.auth().signIn(withEmail: email + "2", password: password) { result, error in
if let error = error {
print("Error : \(error.localizedDescription)")
self.loginError = loginErrorhandler(error: error.localizedDescription)
return
}
self.loginError = ""
self.logStatus = true // contentview에서 home으로 갈지 login으로 갈지 결정해줌. 로그인 누르면 homeview로 넘어가도록 함
}
}
// 송장번호 추가
func addTrackNumber(trackNumber: String, trackCompany: String) { // 택배 create
print("현재 아이디: \(currentUser?.uid ?? "")")
let packages = Packages(trackCompany: trackCompany, trackNumber: trackNumber)
do {
try db.collection("users").document(currentUser?.uid ?? "").updateData([
"userTracksInfo": FieldValue.arrayUnion([packages.setTrackNumber])
])
} catch let error {
print("\(error)")
}
}
// 송장번호 하나 삭제
func deleteTrackNumber(trackNumber: String) {
let db = Firestore.firestore()
let trackInfoData: [String: Any] = [
"trackNumber" : trackNumber,
"trackCompany" : "대한통운"
]
DispatchQueue.main.async {
db.collection("users").document(self.currentUser?.uid ?? "").updateData([
"userTracksInfo" : FieldValue.arrayRemove([trackInfoData])
]) { error in
if let error = error {
print("Unable to delete userTracksInfo: \(error.localizedDescription)")
} else {
print("Successfully deleted userTracksInfo")
}
}
}
}
// 송장번호 읽어오기
func readTrackNumber() {
let docRef = Firestore.firestore()
.collection("users")
.document(currentUser?.uid ?? "")
docRef.getDocument { document, error in
if let error = error as NSError? {
self.errorMessage = "Error getting document: \(error.localizedDescription)"
}
else {
if let document = document {
do {
let citiesDocument = try document.data(as: TrackInfo.self)
self.trackInfo = citiesDocument
}
catch {
print(error)
}
}
}
}
}
// 회원탈퇴
func deleteUser() {
let user = Auth.auth().currentUser
user?.delete { error in
if let error = error {
// An error happened.
print(error)
} else {
// Account deleted. 데이터베이스에서 해당 회원 정보들 다 삭제해줘야 함.
self.db.collection("users").document(self.currentUser?.uid ?? "").delete() { err in
if let err = err {
print("Error removing document: \(err)")
} else {
print("Document successfully removed!")
}
}
print("현재 회원 삭제")
}
}
}
// 로그아웃
func logout() {
print("아직 로그인임\(currentUser)")
currentUser = nil
try? Auth.auth().signOut()
print("로그아웃되었습니다\(currentUser)")
logStatus = false
}
// 회원가입
func registerUser(email: String, password: String) {
Auth.auth().createUser(withEmail: email + "2", password: password) { result, error in
if let error = error {
print("Error : \(error.localizedDescription)")
self.signUpError = "이미 해당 이메일이 존재합니다"
return
}
guard let user = result?.user else { return } // 파이어베이스 유저 객체를 가져옴
let trackInfo = TrackInfo(email: email, userTracksInfo: nil)
if error == nil { // firebase db에 저장하는 방법
self.signUpError = "회원가입이 완료되었습니다"
self.currentUser = result?.user
self.db.collection("users").document(user.uid).setData(trackInfo.setEmail)
}
}
}
}
'iOS 개발 > SwiftUI' 카테고리의 다른 글
[SwiftUI] - Firebase firestore 객체 데이터 삭제 (0) | 2023.02.12 |
---|---|
[SwiftUI] - firebase 회원가입, 로그인 시 에러 처리 View에 적용하기 (0) | 2023.01.31 |
[SwiftUI] - Firebase Firestore 데이터 저장하기, Cannot convert value of type 'TrackInfo' to expected argument type '[String : Any] 오류 해결 (1) | 2023.01.23 |
[SwiftUI] - custom list item 만들기 (0) | 2023.01.17 |
[SwiftUI] - 설정 화면(View) 구현하기 (2) | 2023.01.07 |
firebase의 firestore를 이용하여 사용자를 등록하고 사용자의 이메일과 택배 번호, 택배 회사에 관한 데이터를 입력시키는 작업을 진행했다.
해당 작업을 진행하면서 카카오, 애플, 이메일 회원가입을 각각 진행할 때 이메일이 같은 경우에 어떤 식으로 해당 이메일들을 구분해야 하는가에 대한 문제가 발생했다. 이 문제점은 아래 회원가입과 로그인 코드와 같이 Auth.auth().createUser(withEmail: email + "2", password: password)를 활용했다.
각각 로그인, 회원가입 시에 이메일 뒤에 구분할 수 있는 다른 문자열을 넣는 방식을 채택했다.
그리고 Create, update, delete는 firebase의 문서들을 참고하여 해결할 수 있었지만, read의 경우 현재 파이어베이스에 다음과 같이 이메일과 구조체 배열이 저장되어 있는데 이 구조체 배열을 불러오는것이 조금 어려웠다.

readTrackNumber()함수를 보면 let citiesDocument = try document.data(as: TrackInfo.self) 과 같은 로직이 존재하는데 해당 로직을 위해서는 FirebaseFirestoreSwift를 Import해주어야 한다.(이것 때문에 고생을 좀 했다..)
해당 함수를 실행시키면 미리 만들어놓은 TrackInfo모델에 해당 데이터가 들어가게 되고 변수인 trackInfo에 이를 할당해 view에서 사용하면 된다.
TrackInfo.swift
struct TrackInfo: Codable, Identifiable {
@DocumentID var id: String?
let email: String
var userTracksInfo: [Packages]?
var setEmail: [String:Any] {
return [
"email": self.email
]
}
enum CodingKeys: String, CodingKey {
case email = "email"
case userTracksInfo = "userTracksInfo"
}
}
struct Packages: Codable, Hashable {
var trackCompany: String
var trackNumber: String
var setTrackNumber: [String:Any] {
return [
"trackCompany": self.trackCompany,
"trackNumber": self.trackNumber
]
}
enum CodingKeys: String, CodingKey {
case trackCompany = "trackCompany"
case trackNumber = "trackNumber"
}
}
EmailAuthVM.swift
import SwiftUI
import Firebase
import Combine
import FirebaseFirestoreSwift
class EmailAuthVM: ObservableObject { // 사용자 Create 완료
@Published var freeboardTitle: String = ""
@Published var trackInfo: TrackInfo?
@Published var loginError: String = ""
@Published var signUpError: String = ""
@Published var pack = [Packages]()
@AppStorage("log_status") var logStatus = false
@Published var currentUser: Firebase.User?
let db = Firestore.firestore()
init() {
currentUser = Auth.auth().currentUser
}
// 로그인
func login(email: String, password: String) {
Auth.auth().signIn(withEmail: email + "2", password: password) { result, error in
if let error = error {
print("Error : \(error.localizedDescription)")
self.loginError = loginErrorhandler(error: error.localizedDescription)
return
}
self.loginError = ""
self.logStatus = true // contentview에서 home으로 갈지 login으로 갈지 결정해줌. 로그인 누르면 homeview로 넘어가도록 함
}
}
// 송장번호 추가
func addTrackNumber(trackNumber: String, trackCompany: String) { // 택배 create
print("현재 아이디: \(currentUser?.uid ?? "")")
let packages = Packages(trackCompany: trackCompany, trackNumber: trackNumber)
do {
try db.collection("users").document(currentUser?.uid ?? "").updateData([
"userTracksInfo": FieldValue.arrayUnion([packages.setTrackNumber])
])
} catch let error {
print("\(error)")
}
}
// 송장번호 하나 삭제
func deleteTrackNumber(trackNumber: String) {
let db = Firestore.firestore()
let trackInfoData: [String: Any] = [
"trackNumber" : trackNumber,
"trackCompany" : "대한통운"
]
DispatchQueue.main.async {
db.collection("users").document(self.currentUser?.uid ?? "").updateData([
"userTracksInfo" : FieldValue.arrayRemove([trackInfoData])
]) { error in
if let error = error {
print("Unable to delete userTracksInfo: \(error.localizedDescription)")
} else {
print("Successfully deleted userTracksInfo")
}
}
}
}
// 송장번호 읽어오기
func readTrackNumber() {
let docRef = Firestore.firestore()
.collection("users")
.document(currentUser?.uid ?? "")
docRef.getDocument { document, error in
if let error = error as NSError? {
self.errorMessage = "Error getting document: \(error.localizedDescription)"
}
else {
if let document = document {
do {
let citiesDocument = try document.data(as: TrackInfo.self)
self.trackInfo = citiesDocument
}
catch {
print(error)
}
}
}
}
}
// 회원탈퇴
func deleteUser() {
let user = Auth.auth().currentUser
user?.delete { error in
if let error = error {
// An error happened.
print(error)
} else {
// Account deleted. 데이터베이스에서 해당 회원 정보들 다 삭제해줘야 함.
self.db.collection("users").document(self.currentUser?.uid ?? "").delete() { err in
if let err = err {
print("Error removing document: \(err)")
} else {
print("Document successfully removed!")
}
}
print("현재 회원 삭제")
}
}
}
// 로그아웃
func logout() {
print("아직 로그인임\(currentUser)")
currentUser = nil
try? Auth.auth().signOut()
print("로그아웃되었습니다\(currentUser)")
logStatus = false
}
// 회원가입
func registerUser(email: String, password: String) {
Auth.auth().createUser(withEmail: email + "2", password: password) { result, error in
if let error = error {
print("Error : \(error.localizedDescription)")
self.signUpError = "이미 해당 이메일이 존재합니다"
return
}
guard let user = result?.user else { return } // 파이어베이스 유저 객체를 가져옴
let trackInfo = TrackInfo(email: email, userTracksInfo: nil)
if error == nil { // firebase db에 저장하는 방법
self.signUpError = "회원가입이 완료되었습니다"
self.currentUser = result?.user
self.db.collection("users").document(user.uid).setData(trackInfo.setEmail)
}
}
}
}
'iOS 개발 > SwiftUI' 카테고리의 다른 글
[SwiftUI] - Firebase firestore 객체 데이터 삭제 (0) | 2023.02.12 |
---|---|
[SwiftUI] - firebase 회원가입, 로그인 시 에러 처리 View에 적용하기 (0) | 2023.01.31 |
[SwiftUI] - Firebase Firestore 데이터 저장하기, Cannot convert value of type 'TrackInfo' to expected argument type '[String : Any] 오류 해결 (1) | 2023.01.23 |
[SwiftUI] - custom list item 만들기 (0) | 2023.01.17 |
[SwiftUI] - 설정 화면(View) 구현하기 (2) | 2023.01.07 |