Skip to content

Commit 03943da

Browse files
authored
docs: Delegate 학습내용 추가 (#70) (#75)
1 parent 85f2ab1 commit 03943da

1 file changed

Lines changed: 188 additions & 0 deletions

File tree

세나/Swift 문법/Delegate.md

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
>[!question]
2+
>GQ1. Delegate란 무엇인가
3+
>GQ2. 어떻게 쓰는 것인가
4+
>GQ3. 어디에 쓰이는 건가
5+
6+
## Description
7+
8+
- 객체 간의 1:1 위임(위탁) 관계를 만들어 특정 작업이나 이벤트 처리를 다른 객체에 '위임'하는 방식
9+
-> 한 객체가 해야 할 일부 작업을 대신 **다른 객체에게 맡기는** 디자인 패턴
10+
- 메서드 자체를 인자로 넘겨주는 '형식'
11+
- 델리게이트를 통해 메서드를 매개변수로 전달 할 수 있다
12+
- **함수가 아니라 "형식" 임**!!
13+
14+
> A 객체가 특정 상황이 발생하면 B 객체에게 '이거 좀 처리해줘'라고 부탁하는 방식
15+
16+
+ 언제 쓰일까?
17+
+ UI 이벤트 처리
18+
+ 비동기 작업 처리
19+
20+
+ 목적
21+
+ 객체 간 결합도를 낮추고(loosely coupled),
22+
+ 역할을 분리하여 유지보수를 쉽게 하기 위함
23+
24+
1. 역할 분리 - 이벤트 발생하는 객체와 처리하는 객체를 분리할 수 있음
25+
2. 재사용성 증가 - 동일한 클래스를 다양한 상황에서 활용 가능
26+
3. 결합도 낮춤 - 직접적인 의존 관게가 줄어 유연성이 높아짐
27+
28+
## 주요 기능
29+
30+
+ 동작 흐름
31+
1. 프로토콜 정의
32+
: "이런 함수들을 구현해야 함"라는 약속을 정의
33+
```swift
34+
protocol MyButtonDelegate: AnyObject {
35+
    func buttonDidTap()   // 위임할 함수
36+
}
37+
```
38+
39+
2. 델리게이트 변수 선언
40+
: 이벤트를 위임할 객체를 담을 변수(weak var delegate) 선언
41+
```swift
42+
lass MyButton {
43+
    weak var delegate: MyButtonDelegate?  // 반드시 weak(순환 참조 방지)
44+
    func tap() {
45+
        print("버튼이 눌렸습니다.")
46+
        delegate?.buttonDidTap()  // 델리게이트에 위임
47+
    }
48+
}
49+
```
50+
+ ~~weak에 대해 알아봐야 될 것 같다.. (순환 참조도..)~~
51+
52+
3. 프로토콜 채택 및 구현
53+
: 다른 클래스에서 해당 프로토콜을 채택하고, 실제 동작을 구현
54+
```swift
55+
class ViewController: MyButtonDelegate {
56+
    func buttonDidTap() {
57+
        print("ViewController에서 버튼 눌림 이벤트 처리!")
58+
    }
59+
}
60+
```
61+
62+
4. 이벤트 발생 시 delegate 호츨
63+
: 주체 객체는 이벤트가 발생하면 delegate의 함수를 호출
64+
```swift
65+
let button = MyButton()
66+
let vc = ViewController()
67+
button.delegate = vc
68+
button.tap()
69+
// 출력:
70+
// 버튼이 눌렸습니다.
71+
// ViewController에서 버튼 눌림 이벤트 처리!
72+
```
73+
74+
## 코드 예시
75+
76+
+ MPC(Multipeer Connectivity)에서의 Delegate 사용
77+
+ 흐름
78+
MultipeerConnectivity 내부 이벤트
79+
80+
MPCManager(MCSessionDelegate로 콜백 받음)
81+
↓ (자체 프로토콜 델리게이트 호출)
82+
View/ViewModel (UI 업데이트 or 데이터 처리)
83+
84+
1. 프로토콜 정의
85+
```swift
86+
protocol MPCManagerDelegate: AnyObject {
87+
func connectedPeersChanged(_ peers: [MCPeerID])
88+
func didReceive(message: String, from peer: MCPeerID)
89+
}
90+
```
91+
92+
2. MPCManager 클래스
93+
- MCSessionDelegate 등 MPC 기본 델리게이트를 채택해 **이벤트를 수신**
94+
- 내부에서 **자신이 만든 delegate에게 이벤트를 다시 전달**
95+
```swift
96+
import MultipeerConnectivity
97+
98+
class MPCManager: NSObject, ObservableObject {
99+
weak var delegate: MPCManagerDelegate?
100+
101+
private let myPeerID = MCPeerID(displayName: UIDevice.current.name)
102+
private var session: MCSession!
103+
104+
override init() {
105+
super.init()
106+
session = MCSession(peer: myPeerID, securityIdentity: nil, encryptionPreference: .required)
107+
session.delegate = self
108+
}
109+
}
110+
111+
// MARK: - MCSessionDelegate
112+
extension MPCManager: MCSessionDelegate {
113+
func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
114+
print("Peer 상태 변경: \(peerID.displayName), state: \(state.rawValue)")
115+
DispatchQueue.main.async {
116+
self.delegate?.connectedPeersChanged(session.connectedPeers)
117+
}
118+
}
119+
120+
func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
121+
if let message = String(data: data, encoding: .utf8) {
122+
DispatchQueue.main.async {
123+
self.delegate?.didReceive(message: message, from: peerID)
124+
}
125+
}
126+
}
127+
128+
// 나머지는 기본 구현
129+
func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {}
130+
func session(_ session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, with progress: Progress) {}
131+
func session(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL?, withError error: Error?) {}
132+
}
133+
```
134+
135+
3. ViewModel 또는 ViewController에서 델리게이트 채택
136+
```swift
137+
class WaitingRoomViewModel: ObservableObject, MPCManagerDelegate {
138+
@Published var connectedPeers: [MCPeerID] = []
139+
@Published var receivedMessages: [String] = []
140+
141+
private var mpcManager = MPCManager()
142+
143+
init() {
144+
mpcManager.delegate = self
145+
}
146+
147+
func connectedPeersChanged(_ peers: [MCPeerID]) {
148+
connectedPeers = peers
149+
}
150+
151+
func didReceive(message: String, from peer: MCPeerID) {
152+
receivedMessages.append("\(peer.displayName): \(message)")
153+
}
154+
}
155+
```
156+
157+
4. SwiftUI View에서 ViewModel와 바인딩
158+
```swift
159+
struct WaitingRoomView: View {
160+
@StateObject private var viewModel = WaitingRoomViewModel()
161+
162+
var body: some View {
163+
VStack {
164+
Text("참여자: \(viewModel.connectedPeers.map { $0.displayName }.joined(separator: ", "))")
165+
List(viewModel.receivedMessages, id: \.self) { msg in
166+
Text(msg)
167+
}
168+
}
169+
}
170+
}
171+
```
172+
173+
-> MPCManager가 혼자 모든 일을 하지 않고, "이런 이벤트가 일어나면 너가(ViewModel) 대신 처리해줘" 라고 **부탁**하는 메커니즘 (이벤트 전달자 역할)
174+
+ 비유
175+
+ MPCManager = 비서
176+
+ Delegate = 상사
177+
-> 비서가 알려주고 상사가 직접 처리
178+
179+
180+
>[!Answer]
181+
>델리게이트 = '대신 처리해주는 대리인'
182+
183+
184+
## Keywords
185+
+ 파생된 키워드들을 작성
186+
187+
## References
188+
- 참고한 레퍼런스를 작성 (예 : Apple의 공식 문서)

0 commit comments

Comments
 (0)