[ios] Notification의 활용

감자·2020년 12월 11일
0

why?

작업을 하면서 서버로부터 데이터가 읽어오고 이렇게 읽어온 데이터를 활용하여 특정 작업을 할 수 있게 해줄 필요가 있었다. 평소에는 Delegate패턴을 이용해서 처리를 해주었는데 이번 프로젝트에는 collectionViewCell 안에 CollectionView를 구성하고 또 그 CollectinView의 Cell 안에 새로운 ColletionView를 구성하고 거기에 Cell을 배치하는 좀 복잡한 view를 구성하였다. 이러한 구성에서 Delegate패턴을 활용하는게 너무 귀찮았다. 그래서 어떤 방법이 있을까 고민하다. Notification을 활용하기로했다.

what?

1.Notification의 종류

  • Notification : 일반적으로 사용하는데 사용하는 Notification
  • Local Notification : 특정 시간에 알림 날라오게 하는데 활용하는 Notification
  • Remote Notification : 앱에서 알림이 날라오게 할 때 사용하는 Notification

2. Notification이란?

  • 객체들 간에 주고받는 메세지
  • 모든 앱들을 싱글톤의 NotificationCenter객체를 가짐
  • 앱 내에 객체들이 주고받는 메세지인 Notification은 NSNotification타입의 구조체이고 이 구조체 안에 name , userInfo 등의 변수들이 있음
  • NOtificaton이 NotificationCenter에 Dispatch Table에 들어오때 해당 Notification이 들어왔음을 알려줄 Observer가 없으면 자동으로 삭제된다.(그렇기 때문에 Notification을 post하기 전에 Obsever를 먼저 걸어주어야 정상적으로 작동한다.)

3.Notification의 실행로직

  • sender객체에서 Notification을 생성 후 NotificationCenter에 보낸다.
  • 특정 Notification이 들어오면 실행하고싶은 로직은 addObserver메소드르르 이용해 NotificationCenter객체에 등록한다.
  • sender객체에서 보낸 Notification이 NotificationCenter객체의 Dispatch Table에 저장된다.
  • 저장된 Notification을 활용하는 Observer들에게 Notification이 들어왔음을 알려준다.
  • Observer실행

how?

나는 서버로부터 데이터를 비동기적으로 받아오고 데이터를 다 받아오게 되면 mainCollectionView에 reloadData메소드를 통해 하위 CollectionView를 reload하고 데이터를 서버를 통해 들어온 데이터를 Cell에 적용 시켜줄려고한다.

class MainContainerViewController: UIViewController {
    var selectedIndexPath : Int?
    var sendRecentQuestionInfoArr : [QueryDocumentSnapshot]?
    let maxOfRecentQuetionInerCell = 3

    override func viewWillAppear(_ animated: Bool) {
   NotificationCenter.default.addObserver(self, selector: #selector(recentQuestionInfoProcess(notification:)), name: .newValueDidInput, object: nil)
        defer {
            DispatchQueue.global().async {
                self.receivedQuetionInfoFromFireStore(numOfMaxIndex: self.maxOfRecentQuetionInerCell)
            }
        }
    }
    

메인 VC에서 NotificationCenter에 Obsever를 등록하고 보내고자하는 Notification을 Post한다.

    
 func receivedQuetionInfoFromFireStore(numOfMaxIndex: Int?){
        // fireStore에서 userInfo 받아오는 로직짜기 (아직 적용 x)
        var db = Firestore.firestore()
        var uid = Auth.auth().currentUser?.uid
        let docRef = db.collection("questions").order(by: "date", descending: true)
        var recentQuestionInfosTempArr = [QueryDocumentSnapshot]()
        docRef.getDocuments() { (querySnapshot, err) in
            if let err = err {
                print("Error getting documents: \(err)")
                
            } else {
                // 여기서 받은 fireStore에서 Data를 이용해 notification을 만들고 notificationCenter에 post하기!
                for data in 0...numOfMaxIndex!{
                    recentQuestionInfosTempArr.append((querySnapshot?.documents[data])!)
                }
                NotificationCenter.default.post(name: .newValueDidInput, object: nil, userInfo: ["data":recentQuestionInfosTempArr])
            }
        }
    }

서버로부터 데이터를 받아오면서 데이터가 전부 들어오면 NotificationCenter로 Notification을 Post한다.

    extension MainContainerViewController{
    @objc func recentQuestionInfoProcess(notification: NSNotification){
        guard let data = notification.userInfo?["data"]  as? [QueryDocumentSnapshot] else{
            return
        }


        print("--recentQuestionInfoProcess observer run : \(data)--")
        self.sendRecentQuestionInfoArr = data
        DispatchQueue.main.async {
            self.mainCollectionView.reloadData()
        }
    }
    

NotificationCenter에 Notification이 들어오면 Obsever가 실행할 메소드이다. userInfo를 통해 받은 데이터를 VC에 저장하고 VC에 가장 상위 collectionView를 reloadData함으로써 하위 collectionView 및 cell들을 자동으로 reloadData하게 만들었다.

class MainContainerQuestionCollectionViewCell: UICollectionViewCell{
  @IBOutlet weak var inerCollectinView: UICollectionView!
  func selectedCell(indexOf: Int) {
      print("delegate Test")
      self.delegate?.selectedCell(indexOf: indexOf)
  }
  
  var delegate:MainContainerQuestionDelegate?
  var recentQuestionInfosArrs : [QueryDocumentSnapshot]?
  
  override func awakeFromNib() {
      super.awakeFromNib()
      print("-----MainContainerQuestionCollectionViewCell call awaketFromNib------")

      
  }
}

서버에서 읽어온 데이터를 cell의 var recentQuestionInfosArrs : [QueryDocumentSnapshot]? 에 저장하도록 해주게 만들어주고 하위 Cell에 적용할 때 변수에 들어온 데이터를 이용하게 함

   func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MainContainerQuestionContentCollectionViewCell", for: indexPath) as? MainContainerQuestionContentCollectionViewCell else {
            return UICollectionViewCell()
        }
        let row = indexPath.row

        guard var data = self.recentQuestionInfosArrs else{
            print("data checking!!!")
            return cell
        }
        if data.count == 0 {
            cell.labelToHeadLine.text =  ""
            cell.labelToDate.text = ""
            cell.labelToContents.text = ""
            cell.labelToLocation.text = ""
        }
        else{
            cell.labelToHeadLine.text = data[row]["title"] as? String ?? ""
            cell.labelToDate.text = data[row]["date"] as? String ?? ""
            cell.labelToContents.text = data[row]["contents"] as? String ?? ""
            cell.labelToLocation.text = data[row]["questions"] as? String ?? ""
        }
        return cell
    }

recentQuestionInfosArrs가 비어있는지 안 비어있는지 확인하고 비어있다면 기본셀을 반환하고 데이터가 들어있으면 해당 데이터를 Cell 반영할게 해주었다.

result


-데이터가 안들어왔을 때 기본 Cell 반환한 모습-


-데이터가 들어오면 Cell에 적용한 모습-

0개의 댓글