Skip to content

Latest commit

 

History

History
184 lines (150 loc) · 9.75 KB

File metadata and controls

184 lines (150 loc) · 9.75 KB

이 글은 Bob the Developer 의 Protocol Oriented Programming View in Swift3 에 대한 번역입니다.

Swift3에서 Protocol Oriented Programming 으로 만든 View

많은 클래스를 만들지 않으면서 button, label, imageView 들을 살아 움직이게 하는(animate) 방법을 배웁니다.

POP를 배우는 것은 백과사전/블로그에서 보물을 찾는 것과 같습니다.

2017년 3월 20일 최종 갱신됨.

실천이 없는 지식은 이빨이 있지만 우유만 마시는 것과 같다는 말을 들어 보셨을 겁니다.
여러분은 "좋습니다. 이론은 충분합니다. 앱에서 어떻게 POP를 시작할 수 있죠?" 🤔 라고 물으실 겁니다.

저는 여러분이 Completion Handlers 를 충분히 이해하고 있으며, Protocol 을 이용해서 기초적인 구현을 하실 수 있다고 가정합니다.   만약 이런 것들과 친숙하지 않으시다면, 아래의 저의 글들과 동영상들을 보고 오시기를 정중히 요청드립니다.

사전 필수 사항:

Clojure 걱정 없어요 파트 2:Completion Handlers (Medium)
Protocol Oriented Programming 에 대한 소개(Medium)
Protocol Oriented Protocol 시리즈 (YouTube )

배우게 될 것

여러분은 UIButton, UILabel 그리고 UIImageView 와 같은 UI 컴포넌트들을 살아 움직이게 하기(animate) 위해서 Protocol 을 사용하는 방법을 배울 겁니다. 저는 전통적인 방법들 과 POP 방식의 차이점을 보여드릴 겁니다.

UI

demo 앱은 "우리 집 파티에 오신 걸 환영합니다."("Welcome to My House Party")라고 불립니다. 저는 이앱을 제가 여러분을 저희 집 파티에 초대했는지 아닌지를 확인하기 위해서 이 앱을 만들었습니다. 여러분은 초대 코드를 입력하셔야 합니다. 이 앱에는 로직이 없습니다. 만약 여러분이 버튼을 누르신다면, 그럼에도 불구하고 살아 움직일(animate) 것입니다. 움직이는 4개의 컴포넌트가 있습니다. passcodeTextField, loginButton, errorMessageLabel 그리고 profileImageView.

두가지 애니메이션이 있습니다.: 1.빠르게 진동하기(Buzzing) 2.튀어나오기(Poping(Flash))

완성된 프로젝트

내려 놓는 것에 대해서 걱정하지 마세요. 당장 저와 함께 그냥 물처럼 흐르세요. 만약 여러분이 참을성이 없으시다면, 그냥 스크롤하고 소스 코드를 다운로드 받으시고 그냥 무시하실 수도 있습니다.

뒤로 돌아 가 봅시다.

실제 앱에서의 POP의 힘을 완전히 파악하기 위해서, 정통적인 방법과 비교해봅시다. 여러분이 UIButton 과 UILabel 을 살아 움직하게(animate) 하고 싶다고 합시다. 두 클래스를 상속하고 그것에 메소드를 추가할 수도 있을 겁니다.

class BuzzableButton: UIButton {
 func buzz() { // Animation Logic }
}
class BuzzableLabel: UIButton {
 func buzz() { // Animation Logic }
}

그럼, 로그인 버튼에 탭할 때 진동하게("buzz") 합시다.

@IBOutlet wear var errorMessageLabel: BuzzableButton!
@IBOutlet wear var loginButton: BuzzableLabel!
@IBAction func didTapLoginButton(_ sender: UIButton) {
 errorMessageLabel.buzz()
 loginButton.buzz()
}

우리가 반복하고 있는 것을 알 수 있으신 가요? 애니메이션 로직은 최소한 5줄입니다. 그리고 extension 을 이용하는 "더 나은" 방법이 있습니다. UILabelUIButtonUIView 에 속하기 때문에, 다음을 추가할 수 있습니다.

extension UIView {
 func buzz() { // Animation Logic }
}

그래서, BuzzableButtonBuzzableLabelbuzz 를 포함합니다. 이제, 우리는 더이상 반복하지 않아도 됩니다.

class BuzzableButton: UIButton {}
class BuzzableLabel: UIButton {}
@IBOutlet wear var errorMessageLabel: BuzzableButton!
@IBOutlet wear var loginButton: BuzzableLabel!
@IBAction func didTapLoginButton(_ sender: UIButton) {
 errorMessageLabel.buzz()
 loginButton.buzz()
}

좋습니다. 그러면 POP는 왜? 🤔

보셨던 것과 같이, "유효한 코드를 입력해주세요"("Please enter valid code 😂") 라고 말하는 errorMessageLabel 은 또한 애니메이션이 한가지 더 있습니다. 나타났다가 사라집니다. 그래서 전통적인 방법으로는 어떻게 하나요?

이것에 대해서는 두가지 방법이 있습니다. 먼저, 다시 UIView 에 다른 메소드를 추가해 주세요.

// Extend UIView
extension UIView {
 func buzz() { // Animation Logic }
 func pop() { // UILabel Animation Logic }
}

하지만, 만약 UIView에 메소드를 추가하면, pop 메소드가 UILabel 를 포함한 다른 UIComponent들에도 가능하게 될 겁니다. 불필요한 함수를 상속하게 됩니다. 그리고 UIComponent들이 기본적으로 비대해집니다.

두번째 방법은 UILabel 을 상속(Subclass)하는 겁니다.

// Subclass UILabel
class BuzzableLabel: UILabel {
 func pop() { // UILabel Animation Logic }  
}

잘 작동합니다. 하지만, 이름을 보는 것만으로도 어떤 클래스인지 알수 있도록, class 이름을 BuzzablePoppableLabel 로 바꾸고 싶을 수 있습니다.

이제, label이 무엇을 하는지 명확히 하기 위해서 UILabel 에 메소드를 하나 더 추가 하고 싶다면, class 이름을 BuzzablePoppableFlashableDopeFancyLovelyLabel 같은 것으로 변경해야 할지도 모르겠습니다. 이것 지속 가능한 방법이 아닙니다. 물론, 너무 멀리 가긴 했습니다.

프로토콜 지향 프로그래밍(Protocol Oriented Programming)

좋습니다. 상속(subclassing)은 충분합니다. Protocol 부터 만들어 봅시다. 빠르게 진동하기(Buzzing) 먼저.

애니메이션을 위한 코드는 쾌 길고 모바일 앱에서 선천적으로 지원되는 것이 아니기 때문에 넣지 않았습니다.

protocol Buzzable {}
extension Buzzable where Self: UIView {
 func buzz() { // Animation Logic}
}

그럼 이제, Buzzable protocol을 준수하는(conform) UIComponent들은 연관된 buzz 메소드를 가지게 될 겁니다. extension 과 다르게(extension UIView 로 메소드를 추가하는 것과는 다르게) 이 protocol을 준수하는(conform) 것들만 이 메소드를 가지게 될 겁니다. 또한, where Self: UIView 는 이 protocol 이 <'UIView 로 부터 상속된 컴포넌트' 혹은 'UIView'>에 대해서만 준수되어야(conformed)한다는 것을 나타내기 위해서 사용합니다.

자, 그겁니다. Buzzable 을 loginButton, passcodeTextField, errorMessageLabel 그리고 profileImageView 에 적용합시다. 하지만, 잠시만 기다리세요. Poppable은 어떤가요?

네, 똑같습니다.

protocol Poppable {}
extension Poppable where Self: UIView {
 func pop() { // Pop Animation Logic }
}

이제 현실로 만들 시간입니다.

class BuzzableTextField: UITextField, Buzzable {}
class BuzzableButton: UIButton, Buzzable {}
class BuzzableImageView: UIImageView, Buzzable {}
class BuzzablePoppableLabel: UILabel, Buzzable, Poppable {}

class LoginViewController: UIViewController {
  @IBOutlet weak var passcodTextField: BuzzableTextField!
  @IBOutlet weak var loginButton: BuzzableButton!
  @IBOutlet weak var errorMessageLabel: BuzzablePoppableLabel!
  @IBOutlet weak var profileImageView: BuzzableImageView!

  @IBAction func didTabLoginButton(_ sender: UIButton) {
    passcodTextField.buzz()
    loginButton.buzz()
    errorMessageLabel.buzz()
    errorMessageLabel.pop()
    profileImageView.buzz()
  }
}

POP에서 좋은 점은 상속 없이도 다른 UIComponent에 pop 을 추가할 수 있다는 점입니다.

class MyImageView: UIImageVIew, Buzzable, Poppable

이제, 준수하는 protocol들에 기반한 가능한 메소드들과 클래스를 설명하는 각각의 protocol 의 이름을 이미 알기 때문에, class 이름이 좀 더 유연해질 수 있습니다.

요약

더이상 필요없는 상속(Subclass)

유연한 클래스 이름

Swift 개발자로서 따라 잡은 느낌.

다음 단계

이 글이 200개의 좋아요를 받고 여러분이 POP를 UITableView 와 UICollectionView에 적용하는 방법을 배우기를 원하신다면, Medium에서 저를 팔로우해주세요!

최후 발언

여러분이 뭔가 새로운 것을 배우셨기를 바랍니다. 그렇다면, 긍정의 표시로 ❤️ 를 탭해주세요. 이 구현이 유용하셨다면, 전 세계의 iOS 개발자들이 Protocol Oriented View 들을 하도록 공유해주세요. Protocol Oriented View 들은 코드를 더 간결하게 하면서, 모듈화 할 수 있게 합니다. 토요일 밤 8시(미국 동부 표준시)에 다시 봐요! 더 많이 배우고 싶고, 더 많이 받고 싶으시다면, 여기 저의 메일링 리스트에 가입하세요.

자료들

소스 코드

iOS 개발자를 위한 자료 페이지

감사합니다.