iOS/UIKit

[iOS / UIKit] Notification과 Delegate으로 Data를 주고받는 것에 관하여

TDCIAN 2023. 4. 10. 14:05

안녕하세요!

 

앞서 두 글을 소개한 바 있습니다!

 

(1) Notification을 활용하여 ViewController 간 Data 전달하기

https://tdcian.tistory.com/355

 

[iOS / UIKit] Notification을 활용하여 ViewController간 Data 전달하기

안녕하세요~ 오늘은 Notification을 활용하여 두 ViewController 사이에 Data를 주고받는 방식을 한 번 알아봅시다! 모달 방식으로 보여지는 SendingViewController의 텍스트필드에 내용을 입력하고 'Send Data'

tdcian.tistory.com

 

 

(2) Delegate을 활용하여 ViewController간 Data 전달하기 

https://tdcian.tistory.com/356

 

[iOS / UIKit] Delegate을 활용하여 ViewController간 Data 전달하기

안녕하세요~ 오늘은 Delegate을 활용하여 두 ViewController 사이에 Data를 주고받는 방식을 한 번 알아봅시다! 모달 방식으로 보여지는 SendingViewController의 텍스트필드에 내용을 입력하고 'Send Data' 버튼

tdcian.tistory.com

 

 

 

 

두 방식의 장단점에 대해 ChatGPT에게 한 번 물어봤습니다

 

 

 

Q. 두 UIViewController가 데이터를 주고 받을 때 Delegate을 활용하는 방식과 Notification을 활용하는 방식 사이의 장점과 단점을 설명해 줘

 

A. Delgate와 Notification은 모두 UIViewController 간 데이터를 주고받을 때 활용되는 방식입니다.

각각의 방식에는 장단점이 있습니다.

 

Delegate 패턴의 장점

- 콜백 함수로 처리되기 때문에, 다른 객체의 메서드를 호출하지 않아도 되며, 객체 간의 결합도를 낮출 수 있습니다.

- Delegate 메서드의 이름과 파라미터를 명확히 정의해두기 때문에 코드 가독성이 좋습니다.

- Delegate를 구현하려면 Delegate 프로토콜을 정의하고, 이를 채택하는 클래스에서 Delegate 메서드를 구현해야 합니다. 이렇게 되면 데이터 전달 코드가 클래스 내부에 포함되어 있기 때문에 컴파일 타임에 오류를 검출할 수 있습니다.

 

Delegate 패턴의 단점

- Delegate를 사용하려면 Delegate 프로토콜을 정의해야 하므로, 불필요한 코드량이 늘어날 수 있습니다.

- Delegate는 단방향으로만 데이터를 전달할 수 있습니다. 즉, Delegate 메서드를 구현한 클래스에서는 호출자가 전달한 데이터를 변경할 수 있지만, 호출자는 Delegate 메서드를 구현한 클래스의 데이터를 변경할 수 없습니다.

 

Notification 패턴의 장점

- Notification은 다수의 객체에게 데이터를 전달할 수 있기 때문에 유용합니다.

- Notification은 Delegate와 달리 중간에 데이터를 변경할 수 있는 여러 가지 변형 방식이 있어서 조금 더 유연한 데이터 전달 방식을 구현할 수 있습니다.

- Notification은 객체 간의 결합도를 낮출 수 있습니다. 즉, 데이터를 전달하는 객체와 받는 객체가 직접적으로 연결되어 있지 않아도 데이터를 전달할 수 있습니다.

 

Notification 패턴의 단점

- Notification은 Delegate보다 데이터 전달의 구체성이 낮기 때문에 코드 가독성이 떨어지는 경우가 있습니다.

- Notification은 런타임에 객체 간에 데이터를 전달하기 때문에, 컴파일 타임에 오류를 검출할 수 없습니다. 따라서 Notification을 사용할 때에는 객체 간의 데이터 전달 구조를 신중하게 구성해야 합니다.

 

 

 

Q. 두 UIViewController가 데이터를 주고 받을 때 Delegate을 활용하는 방식과 Notification을 활용하는 방식 사이의 공통점과 차이점을 설명해 줘

 

A. Delegate와 Notification 패턴은 모두 UIViewController 간 데이터를 주고받을 때 활용되는 방식입니다. 공통점과 차이점은 아래와 같습니다.

 

공통점

- UIViewController 간 데이터를 주고 받을 때 사용됩니다.

- 데이터를 전달하는 객체와 받는 객체가 각각의 인터페이스를 가지고 있습니다.

 

차이점

- Delegate는 객체 간의 일대일 통신 방식이며, Notification은 객체 간의 일대다 통신 방식입니다.

- Delegate는 호출하는 측이 Delegate를 구현한 객체의 메서드를 직접 호출하며, Notification은 Notification Center를 통해 데이터를 전달합니다.

- Delegate도 객체 간의 결합도를 낮출 수 있지만, Notification이 결합도를 낮추는 효과가 더 큽니다.

- Delegate는 컴파일 타임에 오류를 검출할 수 있지만, Notification은 런타임에 오류가 발생할 가능성이 있습니다.

- Delegate는 단방향 통신 방식이며, Notification은 양방향 통신 방식입니다.

 

 

 

Q. 왜 Delegate보다 Notification이 결합도를 낮추는 효과가 더 큰지 설명해 줘

 

A. Delegate를 사용하면 더 많은 커플링(결합도)이 발생할 수 있습니다. 이는 Delegate를 사용하는 객체 A가 객체 B에 직접적으로 연결되어 있기 때문입니다. 그렇기 때문에 객체 B가 변경되면 객체 A도 변경될 가능성이 높아지며, 이로 인해 코드 유지보수성이 떨어질 수 있습니다.

 

반면, Notification은 런타임 시점에 발생하기 때문에, 객체 간의 직접적인 연결 없이도 객체의 상태 변화를 알 수 있습니다. 이는 객체 간의 결합도를 낮출 수 있고, 유연한 아키텍처를 구성할 수 있습니다. 객체 A가 객체 B와 Notification을 통해 통신하면, 객체 B가 변경되어도 객체 A는 직접적인 변경 없이도 Notification을 통해 이를 알 수 있으며, 이로 인해 코드 유지보수성이 향상됩니다.

 

따라서, Notification은 객체 간의 결합도를 낮추는 효과가 더 큽니다. 하지만, Notification을 남발하면 코드를 이해하기 어려워질 수 있으며, 코드의 흐름 파악이 어려워질 수도 있습니다. 따라서 Notification을 사용할 때에는 적절한 사용이 필요합니다.

 

 

 

Q. 왜 Notification은 런타임에 오류가 발생할 가능성이 있는 것인지 설명해 줘

 

A. Notification은 런타임에 오류가 발생할 가능성이 있는 이유는, Notification Center를 통해 데이터를 전달하기 때문입니다.

 

Notification Center는 하나의 전역 객체로 사용되며, Notification을 보내는 객체와 Notification을 받는 객체 사이에 직접적인 연결이 없어서, 런타임에 올바른 객체가 Notification을 받았는지 여부를 확인하기 어렵기 때문입니다. 이러한 이유로 Notification Center를 사용할 때에는 Notification의 이름과 데이터를 올바른 타입으로 정의하고, 올바른 객체에서 Notification을 보내고 받는지 확인하는 것이 중요합니다.

 

또한 Notification Center는 Notification을 전송할 때, Notification을 받을 수 있는지 여부를 런타임에 확인하는 과정이 있습니다. 따라서 Notification을 보내는 측에서는 Notification을 전송하기 전에 Notification을 받을 수 있는지 여부를 미리 확인해야 합니다. 이를 위해서는 Notification을 받을 객체에서 Notification을 등록하는 작업이 필요합니다. 만약 등록하지 않은 객체에게 Notification을 보내면 런타임 오류가 발생할 수 있습니다.

 

 

 

Q. Notification이 런타임에 오류가 발생하게 되는 Swift 코드와, 오류 발생을 방지하는 Swift 코드를 보여줘

 

A. Notification이 런타임에 오류가 발생할 수 있는 경우는 다양한 경우가 있지만, 그중 대표적인 경우로는 Notification을 등록한 후 해당 객체가 메모리에서 해제될 때 Notification을 해제하지 않는 경우입니다. 이런 경우, Notification이 발생하면 객체가 메모리에서 해제되어 존재하지 않는 객체를 참조하게 되어 오류가 발생합니다. 다음은 이러한 오류를 발생시키는 Swift 코드의 예시입니다.

let notificationCenter = NotificationCenter.default

class MyObserver {
	init() {
    	notificationCenter.addObserver(
        	self, 
            selector: #selector(handleNotification(_:),
            name: Notification.Name("MyNotification"),
            object: nil
        )
    }
    
    deinit {
    	/* 
        Notification을 해제하지 않는 경우
        앱 실행 중에 MyObserver 인스턴스가 해제되면서 
        Notification Center에 등록한 객체가 해제되지 않은 상태로 남게 됩니다.
        이후 MyObserver가 생성되지 않은 상황에서 해당 Notification이 발생하면, 
        존재하지 않는 객체를 참조하게 되어 오류가 발생합니다.
        */
    }
    
    @objc func handleNotification(_ notification: Notification) {
    	print("Received Notification")
    }
}

// MyObserver 인스턴스를 생성합니다.
let observer = MyObserver()

// Notification을 보냅니다.
notificationCenter.post(
	name: Notification.Name("MyNotification"),
    object: nil
)

위 코드에서는 'MyObserver' 클래스를 정의하고, 'init()' 메서드에서 Notification을 등록합니다.

그리고 'deinit()' 메서드에서 Notification을 해제하지 않습니다.

이로 인해, 'observer' 객체가 메모리에서 해제되면서 Notification Center에 등록한 객체가 해제되지 않은 상태로 남게 되며,

이후 해당 Notification이 발생하면 오류가 발생합니다.

 

이를 방지하기 위해서는, Notification을 등록한 객체가 메모리에서 해제될 때 반드시 Notification을 해제해 주어야 합니다.

다음은 이러한 오류를 방지하는 Swift 코드의 예시입니다.

let notificationCenter = NotificationCenter.default

class MyObserver {
    init() {
        notificationCenter.addObserver(
        	self, 
            selector: #selector(handleNotification(_:)), 
            name: Notification.Name("MyNotification"), 
            object: nil
        )
    }

    deinit {
        // Notification을 해제합니다.
        notificationCenter.removeObserver(self)
    }

    @objc func handleNotification(_ notification: Notification) {
        print("Received Notification")
    }
}

// MyObserver 인스턴스를 생성합니다.
let observer = MyObserver()

// Notification을 보냅니다.
notificationCenter.post(
	name: Notification.Name("MyNotification"), 
    object: nil
)

위 코드에서는 'deinit()' 메서드에서 Notification을 해제하는 코드가 추가되었습니다.

이제 'observer' 객체가 메모리에서 해제되면서 Notification Center에 등록한 객체도 함께 해제됩니다.

 

 

출처: ChatGPT