프로젝트에 NotificationCenter 사용해보기

marisol👩🏻‍💻·2022년 6월 21일
0

프로젝트를 진행하면서 키보드가 텍스트뷰를 가리지 않도록 하는 기능을 구현할 때가 가끔있는데,
저번 프로젝트는 이해를 제대로 못하고 썼었는데, 이번 프로젝트때 제대로 알고 쓰기 위해 정리하려고 한다.

  • 키보드가 텍스트뷰를 가리지 않도록 하기
  • 앱이 백그라운드에 진입했을 때 데이터 저장하기

이렇게 2가지 상황에서 Notification Center를 사용해볼거다 🤓


🧐 Notification?!

공식문서 먼저 보는 습관..

정의를 보면
Notification은 등록된 관찰자에게 정보를 브로드캐스트할 수 있는 알림 발송 메커니즘이다 라고 되어 있는데,

여기서 포인트는

  • 등록된 관찰자에게 (addObserver)
  • 정보를 브로드캐스트 (post)

한다는 것이다.

어떤 이벤트에 대한 알림을 받기를 원하는 관찰자를 추가하면,
그 이벤트가 발생하면 알려주는 메커니즘 이라는 것 같다.

계속 공식문서를 읽어보면,

addObserver() 메서드를 통해 객체를 알림센터에 관찰자로 등록할 수 있다.
객체가 관찰자로 자신을 추가할 때, 수신해야 할 알림을 지정한다.
객체는 여러 다른 알림에 대한 관찰자로 등록하기 위해, addObserver() 메서드를 여러번 호출할 수 있다.
실행 중인 각 앱에는 기본 알림 센터가 있으며, 새 알림 센터를 만들 수도 있다.

그러니까 한 객체가 여러 알림을 받을 수도 있는 듯 하다!

💻 키보드가 텍스트뷰를 가리지 않도록 하기

키보드가 텍스트뷰를 가리지 않도록 하는 기능을 구현하기 위해 먼저 아래와 같이 가이드라인을 잡았다.

1️⃣ Observer를 추가해준다

  • 텍스트뷰를 가진 뷰

2️⃣ 어떤 이벤트가 발생했을 때 그 Observer에게 알림을 발송한다

  • 텍스트뷰를 터치했을 때 키보드가 올라오는 것
  • 텍스트뷰 이외의 화면을 터치했을 때 키보드가 내려가는 것

3️⃣ 알림을 받으면 텍스트뷰를 키보드 높이만큼 줄이거나, 원래 크기로 늘이기

NotificationCenter의 타입프로퍼티로 default가 있는데, 공식문서에서 말했던 기본 알림센터인것 같다.
이걸 써서 기본 알림센터에 Observer를 추가해준다.

private func addKeyboardObserver() {
	NotificationCenter.default.addObserver(self, 
    									   selector: #selector(keyboardWillShow), 
                                           name: UIResponder.keyboardWillShowNotification, 
                                           object: nil)
	NotificationCenter.default.addObserver(self, 
    									   selector: #selector(keyboardWillHide), 
                                           name: UIResponder.keyboardWillHideNotification, 
                                           object: nil)
}

addObserver 메서드에는 파라미터가 4개나 있는데, 하나씩 살펴보자면

  • observer: Observer로 등록할 객체
  • selector: 알림을 받으면 Observer가 수행하는 메서드
  • name: Observer에게 전달하기 위해 등록할 알림의 이름
    - Notification.Name의 타입프로퍼티로 keyboardWillShowNotification(키보드가 표시되기 직전에 post됨)와 keyboardWillHideNotification(키보드가 사라지기 직전에 post됨)가 있어서 그걸 사용했다.
  • object: Observer에게 보내는 객체

요렇게 된다.

텍스트뷰를 클릭하면 키보드가 올라오는데,
키보드가 올라오기 직전에 keyboardWillShowNotification이라는 이름의 Notification이 post되고
그러면 Observer로 등록한 뷰가 그 Notification을 받아서 #selector의 메서드를 실행하는 프로세스인 것 같다.

그럼 알림을 받았을 때 실행하는 keyboardWillShow와 keyboardWillHide에서는 어떤일이 벌어질까?!

keyboardWillShow에서는
1) userInfo (Notification과 관련된 값(keyboard)의 정보가 들어있는 딕셔너리 형태의 저장소)를 사용해서 키보드의 높이를 구함
2) textView의 height를 키보드의 높이만큼 줄임

keyboardWillHide에서는
1) 다시 textView의 height를 원래대로 늘임

이렇게 구현해보았다.

@objc private func keyboardWillShow(_ notification: Notification) {
	guard let userInfo = notification.userInfo,
    	  let keyboardFrame = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else {
          	return
    }
    
    let contentInset = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardFrame.height, right: 0.0)
    diaryTextView.contentInset = contentInset
    diaryTextView.scrollIndicatorInsets = contentInset
}

@objc private func keyboardWillHide() {
	let contentInset = UIEdgeInsets.zero
    diaryTextView.contentInset = contentInset
    diaryTextView.scrollIndicatorInsets = contentInset
}

여기서 키보드의 프레임을 구할 때 사용되는 keyboardFrameEndUserInfoKey는

"A user info key to retrieve the keyboard’s frame at the end of its animation."

애니메이션 마지막에 키보드의 프레임을 반환하는 user info key라고 한다.
그래서 이걸 key로 userInfo에서 키보드의 프레임을 구하는 것 같다!

💻 앱이 백그라운드에 진입했을때 데이터 저장하기

1️⃣ Observer를 추가해준다

  • CoreData에 변경사항을 저장하는 메서드를 가진 ViewController

2️⃣ 어떤 이벤트가 발생했을 때 그 Observer에게 알림을 발송한다

  • 앱이 백그라운드에 진입했을때

키보드 했을 때랑 똑같이 addObserver를 해준다.

NotificationCenter.default.addObserver(self, 
									   selector: #selector(saveDiary),
                                       name: Notification.Name.sceneDidEnterBackgroundNotification,
                                       object: nil)

(sceneDidEnterBackgroundNotification은 Notification.Name을 extension해서 만들어줬다)

그리고 알림을 발송하는 시점 == 앱이 백그라운드에 진입하는 시점이기 때문에
SceneDelegate의 sceneDidEnterBackground(_ scene: UIScene) 메서드에서 post를 해준다.

NotificationCenter.default.post(name: Notification.Name.sceneDidEnterBackgroundNotification,
								object: nil)

이러면 observer에서 알림을 수신했을때 #selector의 saveDiary를 실행해서 데이터를 저장할 수 있다!😎


참고자료

0개의 댓글