[iOS] App Development

[iOS] 기본 개념 정리 #4 : DarkMode, UITextFieldDelegate, Protocol, Delegate Design Pattern

ddgoori 2021. 11. 2. 19:51

* iOS 개인 프로젝트 시작 전 기본 개념 복귀 차원으로 내용을 정리합니다.

DarkMode

  1. SF Symbols
  2. iOS 13 부터 다크모드가 사용가능하다
  3. 심볼이나 텍스트를 시스템 컬러로 사용하면 다크모드 사용이 가능하다.
  4. 만약 커스텀 컬러를 원한다면? Assets 에서 Color Set을 추가하고 라이트모드, 다크모드일 시에 컬러를 커스텀으로 설정가능
  5. 커스텀 컬러는 색상 선택 시 팔레트에 저장을 해야한다.

 

 

vector이미지를 사용시 Assests에서 이미지 클릭 후 인스펙터에서 설정해줘야할 것

  1. 벡터이미지 사용시(PDF등) Preserve Vector 체크해주고
  2. 인스펙터에서 single scale로 설정
  3. Appearance에서 Any, Light, Dark로 바꾸면 다크모드 라이트모드도 개별로 설정가능

 

 

UITextField / UITextFieldDelegate를 사용해야한다. 

  1. 오브젝트 라이브러리에서 사용 가능
  2. 인터페이스 스타일(다크/라이트)에 따라 다르게 디폴트로 적용되어있음
  3. Text Input Traits도 인스펙터에서 설정가능
    1. Secure Text Entry등 (비밀번호 설정시)
    2. 첫글자 대문자 설정 중
  4. 컨트롤 클릭 드래그하여 Outlet으로 선언
  5. Seatch 버튼 컨트롤 클릭 드래그하여 IBAction func 선언
  6. seatchTextField.text 
  7.  시뮬레이터 -> 커맨드 K 누르면 키보드 나옴
  8. 그렇다면 Go?버튼을 눌렀을 때 동작하는 function 만드려면? 키보드에서 엔터눌렀을 시 동작하도록 하는 법!
  9. UITextField Delegate를 사용해야한다!
    1. 뷰컨 class에 UITextFieldDelegate 추가
    2. viewDidLoad에 아래 코드추가
    3. 기존에 IBOutlet으로 변수 설정한 searchTextField: UITextField를 
    4. searchTextField.delegate = self 로 해줘야함 => 이것도 UITextFieldDelegate 해줘야 가능함
    5. 야 뷰컨! 유저가 타이핑해~ 야 뷰컨아 다른데 타입해~ 야 뷰컨아 유저가 타입멈췄어!
    6. self는 현재의 뷰컨을 말하는것임
    7. 헤이 뷰컨~ 유저가 리턴키 눌렀는데 뭐해?
    8. 이제 사용자가 엔터를 누르면 textFieldShouldReturn을 실행한다.
    9. 그리고 textFieldShouldReturn은 return true를 해야하는데, 텍스트필드가 리턴할 권한이 이제서야 생김, return true를 해야 유저가 리턴을 엔터하는 것이 허락되는 것임!

 

  1. searchTextField.endEditing(true)로 해주면 키보드가 들어감
    1. 이런 것들은 searchPressed 검색버튼 눌렀을 때의 IBAction이나
    2. textFieldShouldReturn 키보드로 엔터버튼 눌렀을 때의 func 에 넣어주면됨
  2. 키보드가 들어갈 때, 텍스트필드 비워주기 
    1. 야 뷰컨! 유저가 에디팅 멈췄어! 하고 알려줌
    2. func textFieldDidEndEditing에 
    3. seatchTextField.text = "" 로 설정해주면 됨
  3. textFieldShouldEndEdting 야 뷰컨아 유저가 delselect 텍스트 필드 했어! 어떻게 할까? 
    1. if textField.text != "" // 만약에 유저가 아무것도 타이핑안했으면 return true => should end edting 해라! 라고 하는게 return true 이고 textFieldShouldEndEdting에서 트루를 반환하면 textFieldDidEndEdting function이 trigger됨
    2. 그게 아니라면 textField.placeholder = "type something"
      1. 텍스트 필드 선택했어, 그리고 아무것도 입력하지 않은체 go 누르거나 서치버튼 누르면 type something이 place holder로 바뀜. textFieldShouldEndEditing에서 false를 리턴하기 때문에 textFieldDidEndEdting도 작동안함
      2. return false => user has to write sth! // textfield edting을 멈추면 안된다는 말임 // textFieldDidEndEdting도 trigger되지 않음
    3. 이때 리턴 트루와 폴스를 하는 의미는?
    4.  아래의 func를 보면 우리는 어디서도 이 function들을 호출하고 있지 않다. 그럼 어떻게 호출되는 것일까?
      1. 심지어 textField.placeholder를 보면 IBOutlet으로 선언한 searchTextField도 아님 
      2. 그럼 어떻게 호출되는 것일까?
      3. textField가 아래 메소드를 호출하는 것이다.
      4. 마치 IBAction을 보면 sender 즉, UIButton이 터치이벤트를 감지해 IBAction을 trigger시키는 것처럼
      5. seatchTextField.delegate = self를 했기 때문에 이렇게 설정한 어떤 텍스트 필드에 한해서 아래 메소드들이 이벤트를 감지하고 실행하는 것이다. 텍스트필드 파라미터를 패스하는 것이다. 

 

Delegate은 protocol을 사용한 것이다. 프로토콜은 무엇인가?

  1. 증명서라고 생각해라!
  2.  struct나 class가 프로토콜을 adopting하면 해당 클래스나 스트럭트에 자격이 생긴다는 것
  3. 아래 class 상속 예시를 보자.
    1. 펭귄은 Bird이지만 fly할 수 없다. 즉, 펭귄은 상속받지 말아야할 것 까지 부모로부터 상속을 받은 것이 문제
    2. 모든 새는 날 수 있지만, 펭귄은 날 수가 없다.
    3. airplane은 알을 품을 수 없다. 하지만 fly function때문에 상속받다가 원치않는 function까지 상속받게 된다.
    4. 그렇다면?
    5. protocol로 선언한다!

 

protocol 사용법

  1. protocol은  { } 불가능하고,구현 불가능
  2. 다른 클래스들에 독립적으로 구현해야할 것은 protocol로 구현한다. 인터페이스 같기도하군.
  3. 아무튼 이렇게 껍데기만 구현해놓고
  4. class Eagle: Bird, CanFly {
  5.  
  6. }
  7. 위 코드처럼 CanFly 프로토콜을 상속받는다. 상속Inheritance 이라기보단 adopting이라고 표현함
  8. 원래는 Bird에 canFly가 있어서 Bird에 한정된 Function만 실행이 되었다.
  9. 그런데 프로토콜로 따로 빼놓고, 필요한데에 프로토콜을 어답팅하고, 해당 클래스에서 구현해주면된다.
  10. 예를들면, Eagle은 날개를 파닥거리며 날도록, AirPlane의 경우엔 엔진으로 날도록, 펭귄은 해당 프로토콜 안받으면 된다. Bird만 상속받으면 된다.
  11. 여러 클래스에 공통적으로 들어가지만, 내부 구현은 독자적으로 따로 해줘야할 때 프로토콜을 사용하는 건가봄!
  12. 프로토콜은, class와 struct에 모두 사용 가능하다

  1. 그래서 아래처럼 flyingObject의 파라미터 타입을 CanFly 프로토콜로 설정할 수 있다!
  2. 그럼 무슨 일이 일어나느냐? CanFly 프로토콜을 Adopting한 것만 객체만 실행이된다. 왜냐면 CanFly 프로토콜 내부에 fly 함수가 구현되어 있기 때문에, fly()가 있는 객체만 실행할 수 있다.

MyEagle과 MyPlane은 CanFly 프로토콜을 어답팅 했기 때문에 flyingObject로 파라미터로 들어갈 수 있음 

struct FlyingMuseum에서 flyingDemo의 파라미터 타입을 CanFly 프로토콜 타입으로 정했기 때문

그대신 펭귄은 CanFly 프로토콜을 adopting하지 않았기 때문에 파라미터로 들어갈 수 없음

 

아래처럼 AirPlane이 Bird가 가진 CanFly를 상속받고 싶어도, 알을 품는다던지 그런 function은 만족하지 않기 때문에 상속받을 수가 없다. 게다가 펭귄은 날수도 없는데 Bird라는 이유만으로 불필요한 function까지 상속받고 있다.

 

이럴때 필요한 것이 프로토콜이다.

 

 

CanFly를 프로토콜로 선언해서 독자적으로 필요한 곳에 어답팅해서 증명서 발급하듯이 사용하면 된다.

 

 

프로토콜은 다중 adopting 가능하다.

그대신 superClass상속 우선 선언 후 프로토콜을 상속받아야한다.

 

UITexFieldDelegate도 프로토콜이고, 그래서 그 내부에 있는 함수의 구현은 adopting한 클래스 내부에서 하는 것이다.

 

 

The Delegate Design Pattern

  1. MVC 배웠는데 왜 이걸 또 배우나용? 디자인패턴은 문제를 해결하는 방법임!
  2. 예를 들어 템플릿코드를 만들고 싶다고 하자 UITextField를 예시로 들어보자. 프로퍼티와 모든 메소드들을 만들어주는 템플릿이지.
  3. 언제 텍스트필드가 편집이 멈추는지 알고 싶어
  4. 그럼 아래와 같이 구현해야하는데,, 사용자가 어떤 뷰컨을 만들지 어떻게 알고 객체를 미리 템플릿에 만들어 놓겠냐! 그것이 문제임
  5. 어떤 클래스를 사용해도 UITextField관련된 이벤트액션을 알게하고 싶다는 것이다.
  6. 해결 방법    ==>   프로토콜 데이터타입만 맞춰주면 내부에 있는 메소드 사용할 수 있다.
  7. 그럼 뷰컨에서 어떻게 아는걸까?
    1. let textField = UITextField() 로 UITextField() ==> 템플릿이지 // 타입으로 우선 만들었고
    2. 그 변수에다가 delegate을 해줬음, 현재 view를 이런식으로. textField.delegate = self ==> 하는 순간 UITextFieldDelegate라는 UITextField내부에 있는 delegate변수가 곧 뷰컨이 되어버림 ex)WeatherViewController
    3. 어떻게 이게 가능한걸까? 뷰컨에서 UITextFieldDelegate을 상속받았기 때문이다..!!!! 그래서 UITextField 템플릿의 델리게이트 타입과 일치하기 때문에 가능한것이다. 그래서 해당 뷰컨에서 일어나는 UITextField 관련된 액션을 iOS가 다 알아차리고 액션과 관련된 function 구현시 해당 이벤트 발생시 해당 function을 실행하도록 알아챌 수 있는 것이다.
    4. UITextField는 템플릿이기 때문에 그냥 UITextFieldDelegate프로토콜을 따르기만한다는 것만 알면됨
    5. 그래서 뷰컨에서 UITextFieldDelegate를 adopting하고, 그 다음에 textField.delegate = self로 해주면 됨
      1. 현재 뷰컨 self에서 일어나는 일을 textField.delegate에 대입함으로서 관련된 이벤트 함수를 사용할 수 있게 되는 것이지