iOS/CoreData

[CoreData] CoreData 변경을 감지해보자.

여성일 2024. 5. 16. 14:35
728x90
NotificationCenter

NotificationCenter는 iOS에서 이벤트를 전파하는 데 사용되는 중요한 클래스이다. 이 클래스를 사용하면 여러 객체 간 이벤트를 효율적으로 전달하고 처리할 수 있다.

 

✅ 이벤트 전파 : 특정 이벤트가 발생했을 때 관련된 모든 객체에게 이를 알리는 역할을 한다. 이벤트는 이름 또는 식별자를 가지며, 이벤트가 발생했을 때 해당 이벤트에 등록된 모든 관찰자에게 알린다.

 

✅ 이벤트 등록과 해제 : addObserver(:selector:name:object:) 메소드를 사용해서 특정 이벤트에 대한 관찰자를 등록하고, removeObserver(:) 메소드를 사용하여 관찰자를 해제한다. 이를 통해 관찰자가 더 이상 필요하지 않을 때 메모리 누수를 방지할 수 있다.

 

✅ 이벤트 처리 : 이벤트가 발생하면 NotificationCenter는 등록된 관찰자에게 해당 이벤트를 전달한다. 관찰자는 이를 처리하기 위해 지정된 셀렉터 또는 클로저를 실행한다.

 

✅ 동기 및 비동기 이벤트 전달 : 기본적으로 이벤트는 동기적으로 전달되지만, DispatchQueue를 사용하여 비동기적으로 처리할 수 있다.

 

➡️ NotificationCenter는 주로 앱 내에서의 통신이나 상태 변화 등을 처리하는 데 사용된다. 예를 들어, 앱 내에서 데이터의 변경을 감지하거나, 사용자 인터페이스의 상태를 업데이트하는 등의 작업에 사용될 수 있다.

 

구현하기
private func setupNotificationObservers() {
    NotificationCenter.default.addObserver(self, selector: #selector(handleCoreDataChange), name: NSNotification.Name.NSManagedObjectContextDidSave, object: nil)
}
    
@objc private func handleCoreDataChange() {
    print("변경이 감지 되었습니다.")
 }

1. NotificationCenter 클래스의 싱글톤 인스턴스인 default을 사용하여 NotificationCenter에 엑세스 한다.

2. addObserver 메소드를 호출하여 관찰자를 등록한다.

✅ self : 관찰자를 등록하는 객체.

✅ selector : 이벤트가 발생했을 때 호출될 메소드의 셀렉터

✅ name : 관찰할 이벤트의 이름이다.

      📚NSManagedObjectContextDidSave : CoreData에서 NSManagedObjectContext가 변경되었음을 나타내는 노티피케이션이다.

✅ object : 이벤트를 발생시키는 객체를 지정한다.

 

따라서 이 코드는 NSManagedObjectContextDidSave 노티피케이션을 관찰하고, 이벤트가 발생했을 때 handleCoreDataChange를 호출하여 해당 이벤트를 처리한다. 이를 통해 CoreData의 변경을 감지하고 처리할 수 있다.

 

진행 중인 프로젝트에서 CoreData의 변경을 감지하는 것을 적용해보았다. 사용자가 책 기록을 추가하면 변경을 감지하여 다시 데이터를 fetch하여 UI를 Update하도록 하는 코드이다. 

 

물론 이대로 사용해도 상관 없지만, 내 프로젝트는 Rx를 기반으로 하고 있다. Rx로 CoreData의 변경을 감지하는 코드를 구현해보자.

 

private func setupObservers() {
    NotificationCenter.default.rx.notification(.NSManagedObjectContextDidSave, object: NSManagedObjectContext)
        .subscribe(onNext: { notification in
            print("변경이 감지되었습니다.")
        })
        .disposed(by: disposeBag)
 }

NotificationCenter.default.rx.notification(.NSManagedObjectContextDidSave:Object:)를 사용하여 NSManagedObjectContextDidSave의 변경을 관찰하고, 이를 구독하여 변경을 처리한다.

 

CoreData Manager에서 관리하기

CoreData의 변경을 감지해야하는 곳이 많아지면 어떻게 해야할까? 똑같은 코드를 계속 작성 할 필요는 없다. CoreData Manager에 변경을 감지하는 메소드를 구현하여 필요한 곳에서 사용하면 된다.

 

class CoreDataManager {
    static let shared = CoreDataManager() 
    private let notificationCenter: NotificationCenter
    
    private init() {
        notificationCenter = NotificationCenter.default
    }
    
    private var coreDataChangeHandler: (() -> Void)?
    
    func observeCoreDataChanges(_ handler: @escaping () -> Void) {
        coreDataChangeHandler = handler
        notificationCenter.addObserver(self, selector: #selector(handleCoreDataChanges(_:)), name: NSNotification.Name.NSManagedObjectContextDidSave, object: nil)
    }
    
    @objc private func handleCoreDataChanges(_ notification: Notification) {
        coreDataChangeHandler?()
    }
}

핸들링을 클로저로 하여 사용하고자 하는 곳에서 핸들링을 구현하면 된다.

 

실제로 프로젝트에 적용한 모습이다.

 

이제 Rx로 구현하는 방법을 알아보자.

class CoreDataManager {
    static let shared = CoreDataManager()
    
    private let notificationCenter = NotificationCenter.default
    
    func observeCoreDataChanges() -> Observable<Void> {
        return Observable.create { observer in
            let token = self.notificationCenter.addObserver(forName: NSNotification.Name.NSManagedObjectContextDidSave, object: nil, queue: nil) { _ in
                observer.onNext(())
            }
            
            return Disposables.create {
                self.notificationCenter.removeObserver(token)
            }
        }
    }
}

구현하는 방법은 많지만 내가 구현한 방법은 위와 같다. CoreData의 변경을 감지하는 NotificationCenter를 사용해서 Observable을 생성한다. NotificaionCenter는 NSManagedObjectConextDidSave 노티피케이션을 관찰하고, 해당 노티피케이션이 발생하면 onNext이벤트를 방출한다. 메모리 누수를 방지하기 위해 addObserver에서 반환 된 token을 사용하여 옵저버를 제거한다.

 

실제로 적용한 모습이다. 구독하여 핸들링을 처리하면 된다.