Swift는 Objective-C와 같은 벤더를 가지고 있기 때문에 Objective-C의 후계자이다. 이것은 비슷하게 생기지도 않고 똑같이 동작하지도 않으며 비슷한 느낌이 들지 않는다. Objective-C에서 (메소드 이름처럼) 잘 동작했던 패러다임은 새로운 Swift 세계로 넘어오기 위해 천천히 바뀌고 있다. 예를들어 아래 메소드는 Objective-C에서 이런식의 긴 형태로 호출되었다.
[string dataUsingEncoding:NSUTF8StringEncoding];

Swift2.2에서는 다소 어색하게 바뀌었고

string.dataUsingEncoding(NSUTF8StringEncoding)

Swift3에서 이 메소드는 비로소 간결해졌다.

string.data(using: .utf8)

Swift3 버전의 메소드가 Swift에게 알맞는 것이고, 같은 의미에서 Objective-C 버전은 Objective-C 버전에 알맞는 것이다. 여러분의 메소드를 어떻게 Swift에 맞춰 사용할 수 있는지 다루는데 이 글이 도움을 줄 것이다.


우리 앱을 만들기 위해 사용하는 것들 중에 Swift하게 바꿔야하는 프레임워크나 언어적인 부분들이 있다. 오늘 나는 델리게이트 네이밍에대해 이야기하려 한다.

Swift에서 델리게이트는 Obejctive-C에서처럼 부드럽게 잘 바뀌지 않는다. Objective-C는 "sender"와 "receiver"에대해 굉장히 친숙하다. 애플의 Objective-C 문서에서는 이 용어를 자주 사용한다. 예를들어 UIResponer에있는 isFirstResponder 메소드 문서를 확인해 보아라.

receiver가 첫 응답자(first responder)인지 나타내는 불리언 값을 반환한다.
- (void)buttonTapped:(UIButton *)sender { }
델리게이트는 비슷한 방식으로 동작한다:: Objective-C에서 델리게이트 메소드의 첫 인자도 항상 sender였다. 이것이 왜 유용할까? 만약 receiver가 같은 타임의 여러 오브젝트 델리게이트라면 그것들을 구분해야할 것이다. 델리게이트는 첫번째 인자를 제공하면서 그것을 구분할 수 있게 해준다.

나는 Backchannel SDK 예제로 몇 클래스 이름을 간단히 해볼 것이다.

여기엔 두가지 타입의 델리게이트 메소드가 있는데, 첫번째는 이벤트가 일어났는지 나타낸다.
- (void)messageFormDidTapCancel:(BAKMessageForm *)messageForm;
Swift로 번역하면 다음과 같다.
func messageFormDidTapCancel(_ messageForm: BAKMessageForm)
이것은 더이상 Swift3에 알맞지 않다. Swift3에서는 불필요한 것(두번 나타난 messageForm)을 제거하고, 언더바를 사용해서 없에는게 아니라 자동으로 첫번째 인자 이름을 따른다.

두번째 타입의 델리게이트 메소드는 이벤트가 일어나고 거기에 몇 데이터를 가지고 있는지 나타낸다. 아래 예제를 보자.
- (void)messageForm:(BAKMessageForm *)messageForm didTapPostWithDraft:(BAKDraft *)draft;
- (void)messageForm:(BAKMessageForm *)messageForm didTapAttachment:(BAKAttachment *)attachment;
Swift3으로 번역하면 다음과 같다.
func messageForm(_ messageForm: BAKMessageForm, didTapPostWithDraft draft: BAKDraft)
func messageForm(_ messageForm: BAKMessageForm, didTapAttachment attachment: BAKAttachment)
흠, 좋지 않아 보인다. 왜 이 메소드를 둘다 messageForm이라 부르나? 또한 명사로 시작하는 메소드는 별로 좋지 않다. 보통 그 타입의 오브젝트를 반환할때 사용한다(NSStringdata(using:)를 생각해보면 Data를 반환한다). 여기서는 아무 메시지 형식 오브젝트도 반환하지 않을 것이다. 그 "메시지 형식"은 사실 첫번째 파라미터의 이름이다. 매우 혼란스러운 메소드 이름이 아닐 수 없다!

이 두가지 타입의 델리게이트 메소드는 그 줄 마지막에 "sender"를 보내고 동사를 앞으로 옮겨서 고칠 수 있다. 먼저 sender가 델리게이트를 알려주는 이벤트는 messageFormDidCancel대신 didTapCancel이다.
func didTapCancel(messageForm: BAKMessageForm)
굉장히 좋아졌다. 액션이 앞으로 오면서 메소드 이름이 되었다. 그리하여 메소드가 무슨 일을 하는지 더 명확해졌다. 내 생각엔 읽을때 좀 더 좋게 하기 위해서 파라미터 이름 대신에 전치사를 써도 괜찮을 것 같다.
func didTapCancel(on messageForm: BAKMessageForm)
이렇게 써보면서 아직까지는 전치사를 사용하기에 어색해보이는 상황을 발견하지 못했다. 그리고 다른 여러 상황에서도 "on", "for", "with", "in" 모두 유용하게 쓰인다는 것도 알아냈다. 사용자가 "on"형식을 탭 하면서 나는 "on"이 이곳에 적합하다고 생각한다.

이제 뒤에 데이터를 전달하는 델리게이트 메소드도 한번 보자. 동사를 앞으로 보내는게 도움이 될 것이고, 델리게이트 이름에 전치사로 바꾸는 것도 이런 메소드 타입을 깔끔하게 해준다. 아래 예제 대신
func messageForm(_ messageForm: BAKMessageForm, didTapPostWithDraft draft: BAKDraft)
좀 더 Swift하게 만들고
func didTapPost(with draft: BAKDraft, on messageForm: BAKMessageForm)
좀 더 바꾼다.
func didTap(attachment: BAKAttachment, on messageForm: BAKMessageForm)

이러한 규칙은 나를 빼고 누구도 보증하진 않지만 우리가 그런식으로 쓰면 현재 규칙보다 더 이해하기 쉬워질거라 생각된다. 더 나아가 아마 내 Swift 델리게이트 메소드를 이런 구조로 짜기 시작할 것이다.

UITableView의 델리게이트와 데이터소스 메소드를 보면서 이것이 나중엔 어떻게 생겼을지 생각해보자.
func numberOfSections(in tableView: UITableView) -> Int
numberOfSections는 이 스킴을 따르고 이미 꽤 좋아보인다.

그러나 아래 메소드는 그렇게 좋아 보이진 않는다.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
여기 좀 더 사랑스러운 방법이다.
func numberOfRows(inSection section: Int, in tableView: UITableView) -> Int
func cellForRow(at indexPath: IndexPath, in tableView: UITableView) -> UITableViewCell
func didSelectRow(at indexPath: IndexPath, in tableView: UITableView)

 


신고

WRITTEN BY
canapio
개인 iOS 개발, canapio