[iOS Study] 델리게이션과 텍스트 입력 |
출처 : 아론 힐리가스의 iOS 프로그래밍
-
UITextField 인스턴스는 사용자가 텍스트를 수정할 수 있게 해준다.
-
UIResponder 는 UIKit 프레임워크에 존재하는 추상 클래스이다.
다음 세 클래스는 UIResponder 의 하위 클래스이다.
UIView, UIViewController, UIApplication
UIResponse 는 이벤트를 제어하는 메소드들을 정의한다.
이벤트에는 터치 이벤트, 흔들기와 같은 모션 이벤트, 재생/정지와 같은 원격 제어 이벤트 등이 있다.
하위 클래스들은 이런 이벤트에 응답하기 위해 각각에 따라 이들 메소드를 재정의한다.
-
UIWindow 는 다른 이벤트들에 응답할 객체를 가리키는 퍼스트 리스폰더 (first response, 최초 응답자) 라는 포인터를 가지고 있다.
예를 들어, 사용자가 텍스트 필드를 선택하면 윈도우는 firstResponder 포인터를 그 텍스트 필드로 옮긴다.
모션 이벤트와 원격 제어 이벤트는 퍼스트 리스폰더 객체에 전달된다.
-
텍스트 필드나 텍스트뷰가 firstResponder 가 되면 키보드가 나타난다.
그리고 최초 응답자 상태를 잃게 되면 키보드는 사라진다.
이들 뷰 중 하나를 퍼스트 리스폰더로 만들길 원하면 becomeFirstResponder 메소드를 그 뷰에 보낸다.
그러면 키보드가 나타날 것이다.
키보드가 사라지길 바란다면 resignFirstResponder 메시지를 보내면 된다.
-
대다수의 뷰들은 퍼스트 리스폰더가 되길 거부한다.
현재 선택된 텍스트 필드나 텍스트뷰에서 포커스를 빼앗고 싶어하지 않는다.
예를 들어, UISlider 인스턴스는 터치 이벤트를 제어하지만 퍼스트 리스폰더 상태를 전혀 허용하지 않는다.
-
키보드의 형태는 UITextInputTraits 라는 UITextField 의 프로퍼티 집합에 따라 결정된다.
-
UITextFiled 는 키보드 설정에 관해 다음과 같은 설정값들을 가지고 있다.
* returnKeyType
우하단의 Return 으로 표시되는 글씨를 다른 글씨로 변하게 한다.
실질적인 타입 변경이 아닌 글씨변경의 개념이라 action 이 달라지지는 않는다.
return 키에 대한 기능은 스스로 구현해야 한다.
* autocapitalizationType
대문자 쓰기를 어떻게 할지 정한다.
잘 사용되지 않는다.
단어에 적용, 문장에 적용, 모든 글자에 적용이 있다.
* autocorrectionType
알 수 없는 단어를 추천하고 교정한다.
이 값은 YES 나 NO 로 설정된다.
* enablesReturnKeyAutomatically
YES 나 NO 로 설정하며,
YES 로 설정하면 입력한 텍스트가 없을 때 비활성화된다.
텍스트를 입력하는 순간 리턴키는 다시 활성화된다.
* keyboardType
키보드의 형태를 정한다.
가능한 형태에는 ASCII 키보드, 이메일 주소 키보드, 숫자패드, URL 키보드 등이 있다.
* secureTextEntry
YES 로 설정하면 텍스트 필드가 비밀번호 필드처럼 동작한다.
입력하는 텍스트를 숨긴다.
-
델리게이션 패턴(Delegation pattern) 은 자신의 객체 중 하나를 다른 object에 이렇게 소개하는 것이다.
“이것은 너의 델리게이트이다. 네가 살아있는 동안 어떤 이벤트가 일어나면 이 델리게이트에 메시지를 보내야 한다."
해당 object 는 자신의 델리게이트 포인터를 저장한다.
-
델리게이트 메소드의 첫 번째 인자로 항상 자신을 보내는 것에 주목해야 한다.
-
UITextFieldDelegate 는 다음의 함수들을 정의한다.
- (void) textFieldDidEndEditing:(UITextField *)textField;
- (void) textFieldDidBeginEditing:(UITextField *)textField;
- (BOOL) textFieldShouldEndEditing:(UITextField *)textField;
- (BOOL) textFieldShouldBeginEditing:(UITextField *)textField;
- (BOOL) textFieldShouldClear:(UITextField *)textField;
- (BOOL) textFieldShouldReturn:(UITextField *)textField;
-
textFieldShouldReturn: 메소드는 리턴키를 누른 텍스트 필드를 단 하나의 인자로 받는다.
-
델리게이트를 가질 수 있는 객체에는 해당하는 프로토콜(protocol)이 존재한다.
프로토콜에는 그 객체가 델리게이트에 보낼 수 있는 메시지들이 선언되어 있다.
델리게이트는 프로토콜에서 필요한 메소드들을 구현한다.
어떤 클래스가 프로토콜로부터 메소드를 구현하면 프로토콜을 “따른다(conform to)” 라고 한다.
( 자바나 C# 개발자였다면 프로토콜 대신 “인터페이스” 란 단어를 사용할 것이다. )
-
프로토콜은 @protocol 지시자와 이어서 그 이름을 선언한다.
<NSObject> 는 NSObject 프로토콜을 참조하여 그 프로토콜의 모든 메소드를 포함한다는 것을 나타낸다.
@end 지시자로 프로토콜을 닫는다.
-
프로토콜은 클래스가 아니라는 것에 주의해야 한다.
단순히 메소드 선언을 나열한 것이다.
프로토콜의 인스턴스를 만들 수 없고 인스턴스 변수도 가질 수 없다.
이 메소드들은 프로토콜 어디에도 구현되지 않는다.
대신에 구현은 프로토콜을 따르는 클래스에 맡겨둔다.
-
프로토콜에 메소드를 선언할 때 필수나 선택사항으로 지정할 수 있다.
기본적으로 프로토콜 메소드는 필수이다.
만약 프로토콜이 선택 메소드를 가진다면 선언에 앞서 @optional 지시자를 사용해야 한다.
-
선택 메시지를 보내기 전에, 객체는 먼저 델리게이트에 respondsToSelector: 메시지를 사용해 그 선택 메시지가 존재하는지 확인한다.
respondsToSelector: 메소드는 실행 시에 객체가 해당 메소드를 구현했는지 확인한다.
그래서 모든 객체는 이 메소드를 구현한다.
@selector() 지시자를 사용하여 메소드 셀렉터를 변환하여 respondsToSelector:의 인자로 전달할 수 있다.
-
만약 프로토콜 메소드가 필수이면 메시지를 별도의 확인 없이 보내진다.
이는 곧 델리게이트가 그 메소드를 구현하지 않았다면 인식할 수 없는 셀렉터 예외를 던지게 되고 프로그램이 강제 종료됨을 의미한다.
컴파일러는 이를 방지하기 위해서 프로토콜의 필수 메소드 구현을 클래스에 요구한다.
하지만 컴파일러가 프로토콜의 필수 메소드 구현을 확인하려면 해당 클래스는 반드시 어떤 프로토콜을 따른다고 명시해야 한다.
이것은 클래스 헤더 파일이나 클래스 확장에 명시한다.
클래스가 따르는 프로토콜들은 인터페이스 선언에서 <> 사이에 쉼표로 구분한 목록 형태로 추가한다.
클래스 확장에 명시하는 이유는 정보를 외부에 공개할 필요가 없을 때이다.
다른 객체도 알아야 할 정보라면 클래스 헤더에 추가해야 한다.
-
많은 클래스들이 델리게이트 포인터를 가지며 그 포인터는 강한 참조 순환을 피하기 위해 거의 항상 약한 참조일 것이다.
-
iOS 장비는 하드웨어에 강력한 기능들, 가속도계, 자기계, 자이로스코프 등을 내장하고 있다.
애플은 iOS7 에서 패럴랙스(parallax) 효과를 내장했다.
운전하면서 도로를 지날 때 어깨 너머의 표지판들이 거의 나무들보다 더 빠르게 움직이는 것처럼 보이는데,
사람의 뇌는 이를 공간의 이동에 따른 명백한 속도차로 해석한다.
이러한 시각적 효과를 “패럴렉스” 라 한다.
-
앱들은 UIInterpolatingMotionEffect 클래스를 사용하여 이러한 효과들을 동일한 기술로 접근할 수 있다.
인스턴스에는 수평이나 수직축, 키 패스(효과를 적용하길 원하는 뷰의 프로퍼티), 상대적 최소/최대값(키 패스가 각 방향에서 기울기에 따라 변할 수 있는 범위)이 주어진다.
UIInterpolatingMotionEffect* motionEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyParh:@"center.x"
type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
motionEffect.minimumRelativeValue = @(-25);
motionEffect.maximumrelativeValue = @(25);
[label addMotionEffect:motionEffect];
// same for the center.y
-
Xcode 에서 프로그램을 실행하면 그 프로그램에 디버거가 연결된다.
디버거는 프로그램의 현 상태를 감시한다.
형재 어떤 메소드가 실행 중이고 그 메소드가 접근 가능한 변수들의 값이 무엇인지를 보여준다.
-
브레이크 포인트(breakpoint, 또는 중단점) 는 해당 코드 옆의 거터 (gutter, 편집 영역의 왼편에 있는 약간 어두운 막대)를 클릭하여 설정할 수 있다.
코드에 브레이크 포인트를 설정하면 해당 줄 직전에 실행을 멈춘다.
그리고 나서 뒤이은 코드를 한 줄씩 실행할 수 있다.
이는 프로그램이 예상대로 동작하지 않아 그 문제를 격리할 필요가 있을 때 유용하다.
다음번에 프로그램을 실행하면 파란색 지시자가 보이는 위치에서 멈추게 된다.
-
디버그 네비게이터는 실행이 멈춘 브레이크포인트의 스택 기록을 보여준다.
이 스택 트레이스는 프로그램이 멈췄을 때 스택 기록을 보여준다.
이 스택 트레이스는 프로그램이 멈췄을 대 스택에 존재하는 프레임의 함수와 메소드들을 보여준다.
디버그 네비게이터 하단의 슬라이더는 스택을 펼쳤다 접었다 한다.
스택 트레이스의 맨 꼭대기가 현재 중단된 메소드이다.
이 메소드는 바로 아래 메소드가 호출했고 이 또한 그 아래 메소드에서 호출했다.
그 아래 메소드도 마찬가지이다.
디버깅 시 디버그 네비게이터에 직접 코드를 작성한 메소드는 검정 텍스트로 표시되고 애플이 제공한 메소드는 회색으로 표시된다.
편집 영역의 아래에 있는 디버그 영역에서 콘솔 왼편의 변수 뷰를 확인한다.
메소드 범위 내의 변수들을 그 현재 값과 함께 보여준다.
변수 뷰에서 포인터인 변수는 객체의 주소를 보여준다.
self 옆의 디스클로저 버튼을 클릭하면, self 아래의 첫 번째 항목이 자신의 상위 클래스를 가르킨다.
-
편집 영역과 디버그 영역 사이에는 디버거 바가 위치한다.
이 디버거 바에는 실행을 제어하는 버튼들이 존재한다.
행 단위로 진행하는 스텝 오버.
메소드 내부로 들어가는 스텝 인투.
메소드 바깥으로 나가는 스텝 아웃 등의 기능이 있다.
-
브레이크 포인트제거는 브레이크 포인터를 우클릭하여 Delete Breakpoint 를 선택함으로서 수행한다.
-
개발자들은 종종 브레이크포인트를 설정하고 그것에 대해 잊어버린다.
그리고 나서 프로그램을 시작하면 실행을 멈추고 프로그램이 강제 종료된 것처럼 보인다.
만약 프로그램이 갑자기 멈추면 브레이크포인트 때문이 아닌지 확인해야 한다.
브레이크 포인트 네비게이터에서 프로젝트의 브레이크 포인트 목록을 확인할 수 있다.
-
프로그램에서 예외를 던지거나 강제 종료되는 경우 디버거가 자동으로 중단되도록 설정할 수 있다.
네비게이터 하단의 + 아이콘을 눌러 Add Exception Breakpoint… 를 선택한다.
프로그램에 예외가 발생하는데 원인을 모른다면, 예외 브레이크포인트를 추가하여 원인을 찾는 데 도움을 받을 수 있다.
-
UIApplicationMain 함수는 UIApplication 이라는 클래스의 인스턴스를 만든다.
모든 iOS 프로그램은 UIApplication 의 단일 인스턴스를 가지고 있다.
이 객체는 런 루프의 관리를 책임진다.
일단 application 객체가 만들어지면 런 루프는 필수적으로 무한 루프가 된다.
따라서 실행 스레드는 절대 main() 으로 돌아가지 않는다.
-
UIApplicationMain 함수의 또 다른 동작은 UIApplication 의 delegate 가 될 클래스의 인스턴스를 만드는 것이다.
iOS 앱에서 런 루프에 추가되는 첫 번째 이벤트는 앱이 delegate 에 메시지를 보내도록 하는 특수한 “킥오프” 이벤트이다.
이 메시지가 application:didFinishLaunchingWithOptions: 이다.
UIApplicationMain 함수의 마지막 인자가 델리게이트의 클래스명을 나타내는 NSString 객체이다.
이 함수는 AppDelegate 의 인스턴스를 만들고 그 인스턴스를 UIApplication 객체의 델리게이트로 설정한다.
-
시뮬레이터에서 두 손가락을 흉내 내어 줌을 테스트하려면 옵션키를 누른 채 마우스를 사용해야 한다.
-
핀치 투 줌은 다음과 같이 간단하게 구현할 수 있다. ( 예제는 UIScrollView 에 )
1. UIScrollView 의 delegate 를 설정하여, viewForZoomingInScrollView: 를 구현한다.
이 함수 안에서는 zoom 이 될 target view 를 return 해주기만 하면 된다.
2. scrollview 에 minimumZoomScale 과 maximumZoomScale 을 1.0 을 원본 상태 기준으로 하여 값을 먹여준다. 예를 들어 0.5 이면 1/2배 사이즈이고, 2 이면 2배 사이즈이다.
3. 끝
cf) [UILabel sizeToFit] 은 UILabel 크기를 텍스트 크기에 맞게 조절한다.
'프로그래밍 놀이터 > iOS' 카테고리의 다른 글
[iOS Study] UITableView 편집 (0) | 2016.02.21 |
---|---|
[iOS Study] UITableView 와 UITableViewController (0) | 2016.02.20 |
[iOS Study] 뷰 컨트롤러 (0) | 2016.02.18 |
[iOS Study] 뷰 다시 그리기와 UIScrollView (0) | 2016.02.17 |
[iOS Study] 뷰와 뷰 계층구조 (0) | 2016.02.16 |
댓글