01-12_iphone 코드를 위한 간단한 objective

<연재 순서>
1, iPhone/iPod 개발의 시작.
2. iPhone 코드를 위한 간단한 Objective-C 2.0 문법(기존 C/C++문법과의 비교)
3. iPhone 프로그램에 사용되는 Object들의 활용
4. Interface Builder 없이 프로그램 하기.
5. AppStore Application 따라하기 #1
6. AppStore Application 따라하기 #2
2. iPhone 코드를 위한 간단한 Objective-C 2.0 문법(기존 C/C++문법과의 비교)
글쓴이 : 안경훈(캐빈, [email protected])
지난 한달 동안은 한국에서 iPhone용 소프트웨어를 개발하거나 계획중인 개발자들에게
좋은 소식이 전해졌다. 그동안 많은 사람들이 발매일을 추측하면서 이른바 떡밥(?)을 많이
던졌었는데, iPhone life가 우리나라 에서도 현실이 된 것이다. 요금제와 기기 선택을
잘하면 꽤 괜찮은 iPhone을 만날 수 있다. 필자의 주위에서 많은 사람들이 아이폰으로
옮겨가기 위해 예약을 하는 것을 보았다.
이번호에서는 iPhone 코드를 위한 간단한 Objective-C 2.0 문법을 기존의 C/C++ 문법과
항목별로 비교하면서 살펴보겠다.
특별히 언급하고 싶은 것은 아래 그림과 같은 developer.apple.com에 있는 참조 문서들을
열심히 보면 도움이 아주 많이 된다는 것이다. 특히, 참조 5.(
http://developer.apple.com/iphone/library/referencelibrary/GettingStarted/Learning_Objectiv
e-C_A_Primer/index.html)
문서는 Objective-C라는 언어의 개념을 익히는데 상당히 많은 도움이 될 것이다. 처음
Objective-C를 접하는 독자라면 한번쯤은 읽어보자.
Objective-C는 80년에 SmallTalk의 객체지향적인 것을 추가하여 개발되었다. ANSI표준
C언어의 superset에 해당되는 규칙을 가지고 있다. 이제 항목별로 Objective-C 와 기존의
C/C++를 비교하면서 기술해 보겠다.
확장자
.h-이것은 두 언어 모두 공통적으로 header 파일을 지칭한다. 주로 class, type, function,
그리고, 상수 등을 기록한다.
header 파일을 소스에 추가하고 싶으면 '#import' 라는 지시어를 쓴다. 이것은 C/C++의
'#include'와 같다. '#import' 를 사용하면 기존 C/C++ 에서 사용하고 있는 중복 헤더
선언 방지 코드인 아래와 코드를 넣지 않아도 기능은 동일하게 동작하므로 '#include'를
대신하여 Obj-C에서 자주 사용되고 있다.
#ifndef _HEAD_NAME
#define _HEAD_NAME
...
#endif _HEAD_NAME
.m-이 확장자는 Obj-C에서 사용하는 소스 파일의 확장자이다. C 언어의 *.c 확장자쯤
된다.(기존의 c 소스를 그대로 가져와서 확장자만 변경해도 빌드가 되는 경우가 있다.)
.mm- 역시 Obj-C의 소스 파일인데 C++ 확장자라고 생각하면 되겠다.
Objective-C에서 사용되는 지시어
기존의 C/C++에서는 사용하지 않는 컴파일러 지시어가 Obj-C에는 존재한다. 이제 부터는
Obj-C에서 사용되는 여러 가지 컴파일러 지시어에 대해서 살펴보도록 하자. 각각의
지시어는 '@'문자로 시작한다. 아래와 같은 종류들이 있다.
@interface : 클래스 선언 시 사용한다.
@implementation : 클래스 구현 시 사용한다.
@protocol : Delegate등 일반적인 선언을 할 때 사용한다.
@end : class, category, protocol 등을 종료할 때 사용한다.
아래는 Obj-C에서 사용되는 member 접근 지정자 이다. C++에서도 유사하게 사용되고
있다. 용도는 Obj-C/C++ 모두 같다.
@private : 상속이 되지 않으며 해당 클래스 안에서만 사용되는 member들의 집합.
@protected : 정의된 클래스와 상속된 클래스에서만 접근이 가능한 member들의 집합
@public : 모든 곳에서 사용할 수 있는 member들을 쓴다.
exception 핸들링을 위해 사용되는 지시어
예외 처리를 위해서 사용하는 지시어들도 C++에서 사용될 때와 유사하게 사용된다. @try,
@throw, @catch(), @finally 등이 있다.
선언을 위한 지시어
Obj-C 에서만 사용되는 지시어로 아래와 같은 3가지가 있다.
@property : 프로퍼티 정의에 사용.
@synthesize : property로 정의한 변수 등의 getter, setter 없이 사용하고자 할때 사용
@dynamic : 동적으로 사용되는 메소드와 변수에 사용
Obj-C의 특별한 지시어
@class : 사용자 클래스 선언을 위해서 사용.
@selector(method_name) : 정의된 메소드 이름을 리턴해 준다.
@protocol(protocol_name) : 프로토콜 클래스의 인스턴스를 리턴해 준다.
@encode(type_spec) : type_spec의 구조를 인코딩하는 문자열을 산출.
@synchronized() : 하나의 스레드에 의한 코드 블럭 정의시 사용
이제 부터는 자주 사용되는 Obj-C 지시자의 간단한 사용 예를 살펴보자.
@property 와 @synthesize 컴파일러 지시어.
Obj-C에서는 인스턴스 멤버 변수들의 값에 편리하게 접근하기 위해서 @property라는
지시어를 사용한다. (accessor method를 자동으로 생성하여, property를 사용할 때 일일이
get, set등을 붙이지 않아도 되도록 한다.)
실제 사용 예를 보자.
@interface allSourceAppDelegate : NSObject <UIApplicationDelegate> {
...
UIWindow *window
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@end
여기서 보면 @property 부분에서 UIWinodw *window형식으로 사용된 것을 보면
window가 앞으로 구현부에서 아래와 같이 사용될 것이라는 것을 알 수 있다.
@implementation allSourceAppDelegate
@synthesize window;
(void)applicationDidFinishLaunching:(UIApplication *)application {
...
[window addSubview:a.view];
...
[window makeKeyAndVisible];
}
@synthesize window; 처럼, @property 에서 정의한 지시어를 써주어야 함수 내부에서
사용할 수 있다. 즉, @property 에서 정의한 것은 @synthesize 를 통해서 사용할 수 있다.
이외에도 @property에 사용되는 여러 가지 attribute 들이 많이 있는데 'Introduction to
The Objective-C Programming Language' 를 참조하면 각 attribute 에 대한 자세한
설명을 볼 수 있다.
클래스선언 방법
C++에서 클래스 선언은 일반적으로 하나의 파일에서 모두 기술하게 된다. 하지만,
Obj-C에서는 두개의 다른 영역으로 나누어서 쓴다. 또한 Obj-C는 다중 상속 등을
지원하지 않는 특징이 있다.
@interface 와 @implementation 의 영역으로 나누어서 기술한다. 아래 그림은
myView라는 클래스를 선언한 코드이다. UIView base class를 상속받은 클래스임을
나타낸다. Obj-C 에서 클래스의 선언의 끝에는 @end 라는 지시어를 붙여주어야 한다.
@end 뒤에서 ; 를 붙이지 않는 것을 주목해야 한다. 인스턴스(or 멤버) 변수는 { } 기호
안에 쓴다. 또한 메소드는 {} 직후에 바로 기술하게 된다.(initWithString,
createmyViewWithString) 각각의 변수와 메소드등의 끝에 ; 을 붙이는 것은 C++과
동일하다.
이 코드를 기존의 C++ 코드로 써보면 아래와 같은 의미일 것이다.
class myView:UIView
{
public :
int
count;
id
data;
NSString*
name;
initWithString(aName);
...
};
여기서 기존의 C++ 문법과 다른것이 보인다. id라는 지시어가 있는데 이것은 어떤 타입
이든지 다 될 수 있다는 의미이다.(Weak typing) 만약, 메소드 선언시에 (id)를 붙이지
않고 쓰면 자동으로 (id)타입으로 간주한다.
클래스 구현부의 기술방식
실제 구현 부분을 기술할 때는 @implementation 와 @end 라는 지시어가 커플로 사용된다.
실제 사용 예를 아래 코드로 살펴보자.
@interface allSourceAppDelegate : NSObject <UIApplicationDelegate> {
...
}
@end
와 같은 클래스 가 있다면 구현부는 아래와 같이 쓸 수 있다.
@implementation allSourceAppDelegate {
...
}
@end
메소드와 메시지 전송방식
Obj-C 에서는 2가지 방식의 메소드 정의 방식이 있는데, instance 메소드와 class
메소드이다. instance 메소드를 사용하기 위해서는 반드시 class의 instance 를 미리 생성해
두어야 한다. 반대로 class 메소드는 instance를 미리 생성해 둘 필요가 없다.
-(id)initWithString(NSString*)aName; 라는 메소드를 보자.
'-' 기호는 instance 메소드를 선언한다는 의미이다. (Method type identifier)
'+'가 사용될 수도 있는데 이것은 class 객체에서 사용될 것이라는 의미이다. '+'기호는
C++의 static 멤버 함수와 유사하며, 인스턴스를 생성 하지 않고 바로 사용할 수 있는
특징을 가지고 있다.
코드 사용 예를 살펴 보자. 아래 코드는 툴바를 화면에 붙이는 코드의 일부이다.
UIToolbar *toolbar = [[UIToolbar alloc]
initWithFrame:CGRectMake(0.0,0.0,320.0,40.0)];
':' 이것은 앞에는 키워드를 쓰고, : 뒤에는 이 키워드의 값을 의미하도록 표기한다.
'[]' 는 메시지의 시작과 종료를 나타낼 때 쓰인다. C/C++에서는 배열의 index를 표기할
때 주로 사용하였을 것이다.
myAppObject.theArray = aNewArray; 와 같은 C/C++ 코드를
Obj-C형태로는 아래와 같이 기술할 수 있다.
[myAppObject setTheArray:aNewArray];
모든 클래스가 그런것은 아니지만, 전형적인 클래스 초기화 방식은 [[className alloc]
init...]처럼 하는 것
인자의 전달
일반적으로 C++에서 인자를 전달하는 방법은 아래와 같이 괄호() 안에 넣는 방법이
사용되고 있다. 아래는 myRect라는 클래스 객체에 width와 Height를 넣는 것을 나타낸다.
myRect->setWidth(10.0);
myRect->setHeight(15.0);
이것은 Obj-C에서 아래와 같이 표현될 수 있다.
[myRect setWidth:10.0 height:15.0]
String Class 와 동작
Obj-C 에서 문자열을 처리하는 방식에 대해서 알아보자. NS로 시작 되는 string 처리
클래스 중에서 대표적인 것들과 주요 메소드에 대해서 알아보자. 이번 호에서는 주요 string
처리 방법을 설명한다. (더 자세한 내용은 Introduction to String Programming Guide for
Cocoa를 참조하면 좋다.)
NSString NSMutableString : 일반적으로 문자열을 처리할 때 가장 많이 사용되는
클래스이다. NSMutableString 는 NSString의 서브클래스이다. 이 두 클래스가 지원하는
인코딩 타입은 아래와 같다. availableStringEncodings 메소드를 이용해서 지원하고 있다.
NSASCIIStringEncoding, NSUnicodeStringEncoding, NSISOLatin1StringEncoding,
NSISOLatin2StringEncoding, NSSymbolStringEncoding
label의 텍스트로 사용된 간단한 예제 코드를 보자.
self.string = textField.text;
NSString *nameString=string;
if([nameString length] == 0){
nameString = @"iPhone";
}
NSString *greeting = [[NSString alloc] initWithFormat:@"hi @!",nameString];
label.text = greeting;
이 코드는 nameString에 텍스트 필드에서 받은 텍스트를 넘겨주도록 하는 전형적인 예이다.
이 외에도 NSString은 C String을 아래와 같은 형식으로 직접적으로 사용 할 수도
있다.(stringWithCString:,initWithCString:, initWithCString:length:, and
initWithCStringNoCopy:length:freeWhenDone:).
다음은 NSMutableString 클래스를 활용해서 스트링을 수정하는 예제 코드이다.
NSString *firstStr=[NSMutableString string];
int formatNumber = 100
[firstStr appendString:@"This is"];
[firstStr appendFormat:@" Formatting Number %d",formatNumber];
다음은 NSMutableString 클래스를 활용해서 스트링을 수정하는 예제 코드이다.
NSString *firstStr=[NSMutableString string];
int formatNumber = 100
[firstStr appendString:@"This is"];
[firstStr appendFormat:@" Formatting Number %d",formatNumber];
String 객체들의 형식
일반적으로 Ascii 형식이 아닌 스트링을 출력하기 위해서 stringWithFormat: 이라는
메소드를 사용해서 아래와 같은 형식으로 사용할 수 있다.
NSString *s = [NSString stringWithFormat:@"Long %C dash", 0x2014];
또한 아래와 같이 UTF8형식으로 표현 할 수도 있다.
NSString *s = [NSString stringWithUTF8String:"Long - dash"];
NSString 은 에러메시지를 출력하기 위해서 아래와 같은 유틸리티 함수를 제공한다.
NSLog(string) 처럼 사용하지 않고 아래와 같이 포맷을 정한 후에 사용하는 것이
안전하다는 점에 유의하자.
NSString *string = @"A contrived string %@";
NSLog(@"%@", string);
// Output: A contrived string %@
위에서 본 바와 같이 %C %@등과 같은 string 포맷 형식(서식)은 아래와 같이 기술 될 수
있다.(64bit로 사용되는 타입은 지면관계상 삭제했다.)
SpecifierDescription
%@
%%
%d, %D, %i
%u, %U
%hi
%hu
%x
%X
%o, %O
%c
%C
%s
%S
descriptionWithLocale: 에 의해 string을 돌려준다.
'%' 문자를 출한다.
Signed 32-bit integer (int)
Unsigned 32-bit integer (unsigned int)
Signed 16-bit integer (short)
Unsigned 16-bit integer (unsigned short)
Unsigned 32-bit integer (unsigned int), 핵사값을 찍을 때 0-9와 소문자
a-f를 사용한다.
Unsigned 32-bit integer (unsigned int), 핵사값을 찍을 때 0-9와 대문자
A-F를 사용한다.
Unsigned 32-bit integer (unsigned int), Oct값을 찍는다.
8-bit unsigned character (unsigned char), NSLog()에 의해 ASCII문자를
찍을때 사용한다.
16-bit 유니코드 문자 (unichar), NSLog()에 의해 ASCII 문자를 찍거나
포맷에 맞추어 유니코드 문자를 찍을 때 사용한다.
8-bit unsigned 의 Null-terminated array를 찍을 때 사용.
예를 들면 UTF-8.
16-bit Unicode 문자들의 Null-terminated array를 찍을 때
%p
사용.
Void 포인터 (void *), 0x를 앞에 붙이는 0-9 and 소문자 a-f,
%L
대소문자를 컨버팅할 때 사용한다.
String 합치기
하나의 스트링에 다른 스트링을 더할 경우에는 아래와 같이 stringByAppendingString
메소드를 이용하여 추가하면 된다.
NSString *hString = @"Hello";
NSString *hwString = [hString stringByAppendingString:@", world!"];
스트링을 활용한 조건문
NSString의 함수들을 활용하여 조건문을 만드는 방법을 알아보자. NSString을 조건으로
사용할 수 있는 함수는 아래와 같은 것들이 있다.
- (BOOL)isEqualToString:(NSString *)aString;
- (BOOL)hasPrefix:(NSString *)aString;
- (BOOL)hasSuffix:(NSString *)aString;
isEqualToString은 스트링과 스트링을 직접 비교해서 TRUE/FALSE를 판별하는 함수이다.
아래의 예제 코드를 보자. 위의 3가지 NSSting 멤버 함수를 설명하기 위해서 chtext와
numtext 라는 변수에 각각 @"prefix"와 @"201001"이라는 값을 넣었다. 그리고, chtext를
isEqualToString을 사용하여 스트링끼리 비교하였다. 이러한 방식은 에디트 박스로 특정
단어를 입력받고 나서 스트링을 직접 비교하여 결과를 리턴할 때 사용할 수 있을 것이다.
NSString *chtext=@"prefix"
NSString *numtext = @"201001"
if([chtext isEqualToString:@"prefix"]){
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"스트링 값은"
message:[NSString stringWithFormat:@"TRUE"]
delegate:self
cancelButtonTitle:nil
otherButtonTitles:@"확인", nil];
[alert show];
[alert release];
}
위의 코드를 실행하게 되면 if()안에 조건문으로 사용된 isEqualToString의 결과가 TRUE일
때 {} 안의 내용을 실행하게 된다. 아래 그림은 TRUE를 리턴 했을 경우의 그림이다.
다음으로 hasPrefix와 hasSuffix라는 함수가 있는데 이름에서 알 수 있듯이 이것은
스트링의 앞부분과 뒷부분을 비교하여 그 결과값을 리턴하는 함수이다. 위의 예제 코드에서
isEqualToString 대신 아래와 같이 변경해 보자.
if([chtext hasPrefix:@"pre"]){ ... }
if([chtext hasSuffix:@"x"]){ ... }
두 가지 경우 모두 TRUE를 리턴하게 될 것이다. hasPrefix는 비교 대상이 되는
단어중 앞글자 한글자 이상이 포함되면 되고, hasSuffix는 뒤에서 부터 비교하여
일치하는 글자가 있으면 참을 리턴 하도록 되어 있다. 한글도 역시 비교
스트링으로 사용할 수 있다.
또한, 형변환을 하지 않고 스트링을 직접 사용하여 double, float, int등의 숫자
형태의 type과 비교하는 조건문을 표현할 수도 있다. 아래의 코드는 스트링을 int
값과 비교한 코드이다.
if ([numtext intValue] == 201001){...}
intValue와 같이 사용될 수 있는 타입은 아래와 같은 종류들이 있다.
- (unsigned char)unsignedCharValue;
- (short)shortValue;
- (unsigned short)unsignedShortValue;
- (unsigned int)unsignedIntValue;
- (long)longValue;
- (unsigned long)unsignedLongValue;
- (long long)longLongValue;
- (unsigned long long)unsignedLongLongValue;
- (float)floatValue;
- (double)doubleValue;
스트링을 활용한 조건문
NSString의 함수들을 활용하여 조건문을 만드는 방법을 알아보자. NSString을 조건으로
사용할 수 있는 함수는 아래와 같은 것들이 있다.
- (BOOL)isEqualToString:(NSString *)aString;
- (BOOL)hasPrefix:(NSString *)aString;
- (BOOL)hasSuffix:(NSString *)aString;
isEqualToString은 스트링과 스트링을 직접 비교해서 TRUE/FALSE를 판별하는 함수이다.
아래의 예제 코드를 보자. 위의 3가지 NSSting 멤버 함수를 설명하기 위해서 chtext와
numtext 라는 변수에 각각 @"prefix"와 @"201001"이라는 값을 넣었다. 그리고, chtext를
isEqualToString을 사용하여 스트링끼리 비교하였다. 이러한 방식은 에디트 박스로 특정
단어를 입력받고 나서 스트링을 직접 비교하여 결과를 리턴할 때 사용할 수 있을 것이다.
NSString *chtext=@"prefix"
NSString *numtext = @"201001"
if([chtext isEqualToString:@"prefix"]){
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"스트링 값은"
message:[NSString stringWithFormat:@"TRUE"]
delegate:self
cancelButtonTitle:nil
otherButtonTitles:@"확인", nil];
[alert show];
[alert release];
}
위의 코드를 실행하게 되면 if()안에 조건문으로 사용된 isEqualToString의 결과가 TRUE일
때 {} 안의 내용을 실행하게 된다. 아래 그림은 TRUE를 리턴 했을 경우의 그림이다.
다음으로 hasPrefix와 hasSuffix라는 함수가 있는데 이름에서 알 수 있듯이 이것은
스트링의 앞부분과 뒷부분을 비교하여 그 결과값을 리턴하는 함수이다. 위의 예제 코드에서