본문 바로가기
Xcode/Swift - PlayGround

PlayGround) Firebase 2부 (파싱&수정&삭제)

by 후르륵짭짭 2020. 8. 9.
728x90
반응형

안녕하세요 후르륵짭짭 입니다.

이번에는 FIreBase를 이용해서 

데이터를 파싱하고 수정하고 삭제 하는 방법에 대해서 다뤄 볼려고합니다!!

 

** 데이터 파싱 **

hururuek-chapchap.tistory.com/53

 

PlayGround) FireBase 알아가기 1부 (설치&읽기&저장)

안녕하세요 후르륵짭짭 입니다. 이번에는 FireBase를 이용해서 서버개발자 없이도 데이터를 읽고 저장하는 방법에 대해서 알아보도록 하겠습니다. 일단 FireBase는 Goolge 것 입니다 ㅎㅎㅎㅎ 그래서

hururuek-chapchap.tistory.com

1부에서 마지막의 Student 데이터를 파싱 해보도록 하겠습니다.

headDB.child("Student").observeSingleEvent(of: .value){ snapShot in
	print(snapShot.value)
}

이 코드를 보시면 일단 headDB에서 Student Key 값을 가져오는 것을 확인 할 수 있습니다.

그리고 observeSingleEvent 를 사용해서 하나의 객체 밑에 있는 모든 데이터를 가져오도록 하겠습니다.

따라서 여기서는 "Student" 객체 밑에 모든 데이터를 가져오게 되는 겁니다.

그리고 출력 해보도록 하겠습니다.

그럼 위에 처럼 데이터가 내려오긴 하지만 알수 없는 형태로 내려오는 것을 확인 할 수 있습니다. 

처음에는 배열 형태로 받을 수 있는 했는데,,, 안돼서,,, 다른 방법을 사용했습니다.

바로 JSONSerialization 을 이용했습니다. JSONSerialization은 JSON 데이터를 읽고 변화시켜주는 함수 인데,,,

초기에 사용하고 최근에는 많이 사용한 적이 없던 친구 입니다.

let data = try JSONSerialization.data(withJSONObject: snapShot.value!, options:.prettyPrinted)

이렇게 JSONSerialization을 이용해서 snapShot.value를 Data 객체로 만들어 줍니다. 

왜냐하면 예전에 HTTP 통신에서 이용한 것 처럼 Codable을 이용해서 데이터를 파싱 하기 위해서 입니다.

struct Student : Codable{
    
    let id : String?
    let major : String
    var lector : [Lector]
    
    var toDictionary : [String : Any]{
        
        let lectorDictionary = lector.map { (element) -> [String : Any] in
            return element.toDictionary
        }
        
        return ["major" : major , "lectors" : lectorDictionary]
    }
    
    enum CodingKeys : String , CodingKey {
        case id
        case major = "major"
        case lector = "lectors"
    }
    
    
    static var id : Int = 0
    
}

struct Lector : Codable {
    let teacher : String
    let name : String
    
    var toDictionary : [String : Any] {
        return ["teacher" :teacher, "name" : name]
    }
}

그래서 이렇게 기존에 만들어 놨던 구조체를 Codable로 만들어 줬습니다.

(참고로 CodingKeys 는 구조체의 인스턴스와 데이터 이름이 다를 경우 mapping 해주는 것 입니다. 그런데 다른 이름도 될 줄 알았는데 무조건 CodingKeys로 해야되는거 같습니다.)

        headDB.child("Student").observeSingleEvent(of: .value) { (snapShot) in
//            print(snapShot.value)
            do{
                let data = try JSONSerialization.data(withJSONObject: snapShot.value!, options:.prettyPrinted)
                print(data)
                let decoder = try  JSONDecoder().decode([Student].self, from: data)
                print(decoder)
                self.studentInfo = decoder
            }
            catch let error{
                print("-> Error : \(error.localizedDescription)")
            }
            
 
        }

이제 아래 코드 처럼 해줘서 데이터를 파싱 할 수 있습니다. JSONDecode() 객체에 decode 메소드를 이용해서 data를 분석 해줍니다. 그런데 데이터가 배열이기 때문에 [Student]로 파싱 해주도록 해줍니다.

이렇게 하면 데이터가 파싱 됩니다.

 

** 데이터 수정 - 싱글데이터 **

이제 데이터 수정을 배워 보도록 하겠습니다.

데이터 수정을 해주기 위해서는 updateChildValues 를 사용해서 변경할 수 있습니다.

   func updateFireBaseSingleData(){
        headDB.updateChildValues(["Int" : 1995])
        headDB.updateChildValues(["String" : "updateNicK"])
        headDB.updateChildValues(["Array" : ["Python" , "Machine Learning"] , "Dictionary" : ["name" : "Steven", "Year" : 1995] ])
    }

이렇게 headDB에 특정 객체를 지정 해주지 않아기 때문에 모든 데이터가 대상이 됩니다.

그리고 이렇게 "딕셔너리"형태로 변경이 가능 합니다. [ "찾을 객체" : 변경할 값 ] 으로 변경 할 수 있습니다.

위에 처럼 하나씩 변경이 가능 할 뿐만 아니라 마지막 처럼 여러개의 값도 변경이 가능합니다.

그러면 아래 처럼 변경이 됩니다.

 

** 데이터 수정 **

 위에서 studentInfo : [Student]에 이제 FIrebase에서 받은 데이터가 존재 할 겁니다. 그래서 이 값의 일부를 변경하도록 하겠습니다.

    func updateStudentInfo(){
       
        guard studentInfo.count != 0 else {return}
        
        studentInfo[0].lector = [Lector(teacher: "자료구조", name: "박정흠") , Lector(teacher: "소프트웨어 공학", name: "오재원")]
        
        let changedValue = studentInfo.map({ (studnetInfo) -> [String : Any] in
            return studnetInfo.toDictionary
        })
        
        headDB.updateChildValues(["Student" : changedValue])
        
    }

이렇게 studentInfo가 비어 있지 않다면 다음 값을 넘어가도록 했습니다.

그리고 studentInfo[0].lector를 변경해줍니다. 

studentInfo는 지금 배열의 갯수가 2개 이니, 이 전체 배열을 Dictionary 형태로 변경하도록 하겠습니다.

그러면 studentInfo[0] = ["major" : major , "lectors" : lectorDictionary] 이렇게 들어가 있을 것이고 

studnetInfo[1] 에도 마찬가지로 ["major" : major , "lectors" : lectorDictionary] 이렇게 되어 있을 겁니다.

이제 이것을 위에서 배운 것 처럼 headDB 바로 밑단에 존재하는 객체 중에 "Student"를 찾아서 값을 모두 변경 하도록 했습니다.

그러면 이렇게 변경이 되는 것을 확인 할 수 있습니다.

하지만 이렇게 변경하는것은 약간 위험함이 보입니다. ㅎㅎㅎㅎㅎ

 

그래서 하나씩 접근하여 변경 할 수도 있습니다.

    func updateStudentInfoLector(){
        
        guard studentInfo.isEmpty == false else {return}
        
        let changedLector = [Lector(teacher: "Maching Learing", name: "강호철")]
        
        let chagedValue = changedLector.map { (singleLector) -> [String : Any] in
            return singleLector.toDictionary
        }
        
        headDB.child("Student").child("0").updateChildValues([ "lectors" : chagedValue])

    }

이렇게 변경할 강의만 changedLector에 넣고 

child로 하나씩 내려가서

headDB -> Student -> 0 -> lectors 

를 변경하도록 했습니다.

이렇게 변경하니 좀더 안정적이게 변경 되는 느낌이였습니다.

(참고로 Firebase에 child()로 내려갈 때 그 값이 딕셔너린의 Key 값인지 , 배열의 index인지 상관 없이 내려 갈 수 있습니다.)

 

이러한 방법이 또 한 딕셔너리로 변경하는 것이 귀찮다 싶으면 

 headDB.child("Student").child("1").child("lectors").child("1").updateChildValues(["name" : "자료구조"])

이렇게 특정 위치를 직접 찾아서 변경해줄 수 있습니다.

하지만 이러한 방법은 너무나 위험합니다.

왜냐하면 실수로 잘못 변경하게 된다면 사용자의 데이터가 모두 변경될 위험성이 너무 높기 때문입니다.

 headDB.child("Student").child("0").updateChildValues(["major" : "정보통신전자" , "lectors" : ["name" : "네이버"] ])

만약 위에 처럼 해줬다면 특정 위치의 데이터가 날아갈 수도 있습니다.

이렇게 모든 데이터의 구조가 변경 되는 위험이 생깁니다.

따라서 직접 특정 지역을 찾아서 변경하는 방식은 위험하니 추천 하진 않습니다.

 

** 데이터 삭제 **

데이터 삭제는 쉽습니다 . Firebase에.removeValue()를 사용해서 특정 위치의 값을 삭제 시켜주면 됩니다.

    func removeStudentInfo(){
        headDB.child("Student").removeValue()
    }

이렇게 특정 위치인 "Student" 개체를 removeValue 했을 경우에,

모든 Student 데이터가 삭제되는 것을 확인 할 수 있습니다.

어렵지 않죠??? ㅎㅎㅎㅎ

 

지금까지 FireBase를 이용해서 데이터를 삭제하고 변경하고 읽고 추가하고

여러가지 방법에 대해서 배웠습니다.

아직 저도 익숙하진 않아서,,, 모르는 부분이 많은데,, 추후 지속적으로 업데이트 하도록 하겠습니다.

감사합니다.

모두 즐코코코코코 하세요!

728x90
반응형

댓글