[Objective-C] 프로토콜

Objective-C의 프로토콜

프로토콜의 개념 잡기

프로토콜은 “선언만 되고 구현되지 않은” 메소드를 말한다. 이 프로토콜은 역시나 “너무 단순해서 쉽게 감이 잡히지 않는” Objective-C의 기능이다. 프로토콜은 크게 다음 3가지 경우에 유용하게 사용된다.
[Objective-C] 프로토콜 더보기

[Cocoa] NSImage를 파일로 저장하기

NSImage를 파일로 저장하기

이미지를 파일로 저장하기 위해서는 ‘표현형식'(representation)에 대해 알아야 한다. 즉 이미지 자체는 일련의 픽셀을 모아둔 데이터인데, 우리가 흔히 알고 있는 JPG, PNG 등의 파일 포맷은 이 이미지를 각각 정해진 방식으로 ‘정리’하여 파일에 저장하기 때문이다. 표현형식은 이런 파일에 저장된 비트맵 데이터를 다시 이미지로 렌더링하는 역할을 하고, 그 반대의 역할도 수행할 수 있다.

NSImage는 1) TIFFRepresentation 메소드를 사용하여 표현형식을 구성하는 데이터로 만든다. 이 데이터를 사용하여 2) NSBitmapImageRep 객체를 생성하고, 이 객체에서부터 3) 실제 저장이 가능한 그래픽 파일 포맷의 데이터를 생성해서 ( -representationUsingType: ), 그래픽 파일 포맷으로 만들어진 데이터를 저장해야 우리가 알고 있는 ‘그림 파일’이 만들어진다.

NSImage *currentImage; // 이 이미지는 이미 존재하는 이미지로 가정한다.  
NSString *pathToSave = ... // 파일을 저장할 경로  
NSData *imageData = [currentImage TIFFRepresentation];  
NSBitmapImageRep *rep = [NSBitmapImageRep imageRepWithData:imageData];  
NSData *dataToWrite = [rep representationUsingType:NSPNGFileType  
properties:nil];  
[dataToWrite writeToFile:pathToSave atomically:NO];

이 TIFF표현형으로부터 각 파일 포맷에 대한 저장용 데이터를 생성할 수 있다. 지원하는 포맷은 다음과 같다.

  • NSTIFFFileType : TIFF
  • NSBMPFileType : BMP
  • NSPNGFileType : PNG
  • NSJPEGFileType : JPG
  • NSGIFFileType : GIF
  • NSJPEG2000FileType : JPEG2000

이 때 전달하는 프로퍼티는 사전의 형태로 파일을 저장할 때 필요한 옵션을 지정한다. PNG로 저장하는 경우에는 인터레이스 여부만 필요하다. 그외 JPG포맷의 압축 정도나 애니메이션 GIF를 저장하는 설정 등을 다룬다. 자세한 내용은 개발자 문서를 참고.

이미지의 표현형에 대해 조금 익숙해진다면, 뷰 자체를 캡쳐하여 이를 저장하는 것도 손쉽게 가능하다. NSBitmapImageRep는 initWithFocusedViewRect: 메소드가 있어서 현재 포커스 뷰의 일부 혹은 전체 내용을 잘라, 이를 데이터로 변환한다. 역시 동일한 방식으로 뷰의 내용을 그대로 저장하는 것이 가능하다.

화면을 캡쳐할 때 iOS의 경우에는 좀 다른 방식으로 접근해야 한다. 비트맵 그래픽 컨텍스트를 만들어서 이 곳에 뷰의 CALayer를 렌더링해 넣는 방식으로 CGImage를 얻을 수 있다. 그리고 이 이미지를 다시 저장하면 된다. 이에 대해서는 별도의 포스팅으로 알아보도록 하겠다.

[Cocoa] 코코아의 이름 규칙

코코아 프레임워크에서 이름 짓는 규칙에 익숙해지는 것은 단순히 코드의 가독성을 높일 뿐만아니라 부분적으로 키-밸류 코딩의 규칙을 따르는 것과도 관련이 있다. 애플의 이름 짓기 규칙은 특히나 약어를 거의 사용하지 않고 단어나 문장을 통째로 쓰는 경향이 있는데 이러면 메소드나 변수의 이름이 길어질 수는 있지만 그 의미를 명확히 이해할 수 있을 뿐만아니라, Xcode의 멋진 자동완성기능이 있어 그리 많은 타이핑이 필요하지도 않다. 이름 짓기가 잘 된 소스는 나중에 본인이 재사용할 때도 매우 명확하고 쉽게 접근할 수 있으며, 그 자체로 소스에 대한 주석이 될 수도 있다.

이름을 정할 때의 규칙 일반

  1. 간결하되 명확성을 해치지 않아야 한다.
  2. 군더더기를 빼라. 예를 들어 my나 object와 같은 접두어는 불필요하다.
  3. 축약형을 쓰지 마라. 축약할 때는 쉽지만 원래 의미는 나중에 아무도 알아보지 못한다.
  4. 이중적인 의미의 단어를 피하라. 예를 들어 displayText는 문자를 표시하는 메소드인가, 그냥 표시되는 텍스트의 이름을 나타내는 변수명인가?
  5. 일관성은 중요하다. 서로 다른 클래스에서 같은 이름의 메소드를 만들었다면, 이들 메소드는 같은 기능을 수행해야 한다.
  6. 접두어를 사용하는 것은 추천할만하다. 대부분의 파운데이션 클래스나 함수는 NS로 시작한다. (이는 NextSTEP에서 왔다는 의미이다.) 또한 아이폰 개발에 사용되는 UIKit에서는 UI로 시작하는 클래스들이 있다. 비슷한 기능을 하는 객체가 접두어를 통해 쓰임새나 출신을 파악할 수 있다.
  7. 클래스 이름에는 연관되는 명사가 있어야 한다. 또한 이들과 관련된 이름은 클래스 이름과 닮으면 된다. 예를 들어 UITableViewCell 은 클래스이고, 셀의 스타일을 지정하는 상수는 UITableViewCellStyleDefault 와 같은 식으로 정의되어 있다.
  8. 카테고리 이름은 클래스+카테고리 로 표현한다. 예를 들면 NSString+HTMLFormatting 과 같은 식이다. 여기서 HTML은 축약어로 들어갔지만, HTML은 널리 사용되고 있기에 허용할 수 있다. URL도 같은 맥락에서 허용한다.
  9. 델리게이트나 데이터소스 프로토콜은 이름이 곧 설명이다. UITableViewDataSource, UITableViewDelegate를 보라.
  10. 그외 프로토콜 이름은 형용사를 쓸 수 있다. 예를 들어 NSCoding 프로토콜은 NSCoder와 NSDecoder 의 두 클래스와 관련이 있음을 알 수 있다.

메소드 이름들

  1. 메소드 이름은 소문자로 시작하고, 단어 단위로 대문자를 첫 글자로 쓴다. 축약어를 쓰는 것은 명확하지 않으므로 권장하지 않는다. 또한 메소드 이름은 접두어를 쓰지 않는다.
  2. 메소드 이름을 언더스코어를 시작하는 것은 가능하나, 애플은 이를 private method로 간주하게 될 것이다.
  3. 속성을 리턴하는 메소드이름은 그 속성과 같은 이름을 쓴다. get-, calculate-와 같은 접두어를 사용하지 않는다. 이는 키-밸류 코딩 규칙과도 관련이 있으므로 중요하다.
  4. 파라미터의 이름은 그 파라미터를 설명하는 이름을 쓴다.
  5. 동사를 형용사처럼 만들지 않는다. calculationPerformed 보다는 performsCalculation이라고 한다.

델리게이트와 데이터 소스

  1. 첫번째 인자는 이 메소드를 호출하는 객체의 이름이다. 예를 들어 테이블 뷰의 데이터 소스에서 -(NSInteger)tableView:(UITableView*) numberOfRows… 와 같다. 왜냐하면 델리게이트나 데이터 소스가 되는 객체는 동시에 여러 객체의 델리게이트나, 데이터소스가 될 수 있기 때문이다.
  2. 델리게이트 메소드 이름에는 did나 will이 종종 들어갈 수 있다. 이는 어떤 작업 이전에 호출되는지, 이벤트가 일어난 이후에 호출되는지를 명시적으로 드러내는 좋은 방법이다.
  3. 델리게이트에게 어떤 ‘허가’를 요청하는 메소드는 -(BOOL)shouldCloseWindow…와 같이 should로 시작한다.

기타

  1. 상수값을 사용하는 경우 정수보다는 열거형을 선언하여 단어로 인식할 수 있도록 하라.UITableViewCellStyleDefault는 그냥 0일 뿐이지만, 이름이 붙어 훨씬 명확해진다.
  2. 전처리기가 처리하는 이름은 전체를 대문자로 사용하고 공백을 언더스코어로 대치한다. LIKE_THIS, DEFAULT_NAME_VALUE 등이 이러한 예다.
  3. 오류 이름은 접두어+고유이름+Exception으로 붙인다. NSIllegalSelectorException 이나 NSRangeException 등이 이런 이름이다.

[iOS] 코어그래픽에 손대기

코어그래픽은 뷰에 그림을 그리는 기술이다. 하지만 C로 짜여진 API에 온갖 혼란스러운 함수명하며, 컨텍스트와 같은 어려운 개념들이 들어가면서 나와 같은 초보자에게는 마치 ‘넘을 수 없는’ 장벽과 같이 느껴진다. 하지만 많은, 정말 많은 튜토리얼들이 코어그래픽을 사용해서 그림을 그리는 이유는 명확하다. 바로 “아주 빠르기” 때문이다. 코어 그래픽은 그래픽 메모리의 버퍼를 직접 다루므로 아주 빠르다. (다만 일부 기기에서는 느리기도 하더라 ㅠㅠ) 오늘은 “시작하는 마음가짐”으로 코어 그래픽에 대해 잠깐 살펴보도록 하자.

코어그래픽을 사용하는데는 ‘컨텍스트’라는 개념을 이해해야 하는데, 이는 뒤에서 설명하기로 하고 잠시동안 ‘컨텍스트’는 그림을 그리는 도화지, 혹은 포토샵에서의 레이어와 같다고 간주하자.
[iOS] 코어그래픽에 손대기 더보기

[iOS/OSX] predicate를 사용한 배열의 필터

배열을 필터하기

특정한 값을 만족하는 원소만을 추출하여 부분 집합을 구하는 작업을 종종 해야 할 때가 있다. 배열에 대한 정렬 보다 간단하다면 간단하고 어렵다면 어려운데, predicate를 사용하면 쉽게 추출이 가능한데, 이 predicate를 사용하는 문법이 별도로 존재하기 때문에 조금 성가실 수 있다. (하지만 영문법과 크게 다르지 않다)

NSMutaleArray *array = [NSMutableArray arrayWithObjects:@"Bill", @"Ben", @"Chris", @"Melisa", nil];
NSPredicate *bPredicate = [NSPredicate predicateWithFormat:@"SELF beginsWith:'b'"];
NSArray *beginWithB = [array filteredArrayUsingPredicate:bPredicate];
// ==> { @"Bill", @"Ben" }

predicate는 너무 깊이 파면 복잡하므로 일종의 쿼리문이며, 대략 다음과 같은 포맷과 문법이 있다고 알아두자.

  • %@ : 하나의 객체로 치환한다.
  • %K : 하나의 문자열로 치환한다. 이는 비교하고자 하는 키패스가 된다.
  • = / == : 두 항이 같다.
  • >= / => : 왼쪽이 크거나 같다.
  • <= / =< : 오른쪽이 크거나 같다.
  • > : 왼쪽이 크다
  • < : 오른쪽이 크다.
  • != / <> : 같지 않다.
  • BETWEEN : 사이에 있다 – 1 BETWEEN {0,3}
  • TRUEPREDICATE : 항상 TRUE
  • FALSEPREDICATE : 항상 FALSE
  • AND / && : 논리곱
  • OR / || : 논리합
  • NOT / ! : 논리 부정
  • 문자열 비교시 [cd] 토큰 : c는 대소문자구분하지 않음, d는 공백등을 무시
  • BEGINSWITH : 첫글자가 ~로 시작함
  • ENDSWITH : 마지막이 ~로 끝남
  • CONTAINS : ~를 포함함
  • LIKE : ~와 유사함
  • MATCHES : 정규식을 사용함
  • IN : 비교항이 특정 집합에 포함됨

언제나 그렇지만 자세한 내용은 개발자 문서를 참고하면 된다.