아이폰어플개발정보2010. 10. 29. 10:29
[아이폰 앱 개발] 아이폰 어플 개발 Table View 의 기초

Table View Basics
iPhone tables(UITableView) 의 행(Row)수는 제한이 없음.(iPhone OS Memory)
UITableView - 테이블의 Data를 표시하는 뷰 오브젝트.
UITableViewCell - 테이블의 단일 행을 표현.

UITableViewCell 에 복수의 데이터를 추가하기 위해서
1.UITableViewCell 에 subview 를 추가 하거나
2.UITableViewCell 을 상속하는 서브클래스 작성.

Table > Section > Rows...
그룹 테이블(Figure 8-3)에서 각 Section 은 한 그룹을 나타냄.
인덱스 테이블(Figure 8-3)에서 각 Section 은 한 인덱스의 집합.

Implementing a Simple Table
Writing the Controller

  1. // delegate, datasource protocol 선언.  
  2. // datasource 는 테이블 각 행에 대한 데이터 핸들.  
  3. // delegate 는 데이터의 설정(font, user interation...) 핸들.  
  4. @interface SomeUITableView  {  
  5.     // Table Data.  
  6.     NSArray *tableData;  
  7.     ...  
  8. }  
  9.   
  10. #pragma mark -  
  11. #pragma mark Table View Data Source Methods  
  12. // 해당 Section 에 행 수.  
  13. - (NSInteger)tableView:(UITableView *)tableView  
  14.  numberOfRowsInSection:(NSInteger)section {  
  15.     return [self.tableData count];  
  16. }  
  17.   
  18. // 행이 그려질 때 호출되어 현재 표시될 행의 UITableViewCell 를 리턴.  
  19. // NSIndexPath 를 이용해서 해당 Section[indexPath section]과  
  20. // 해당 행[indexPath row]을 알 수 있음.  
  21. // UITableViewCell 는 캐쉬화 되고 시스템 메모리가 부족할 때 자동 메모리 해제됨.  
  22. - (UITableViewCell *)tableView:(UITableView *)tableView  
  23.          cellForRowAtIndexPath:(NSIndexPath *)indexPath {  
  24.     // cache 할 때 구분자.  
  25.     static NSString *SomeID = @"SomeID";  
  26.   
  27.     // cache 에 저장된 UITableViewCell 취득.  
  28.     UITableViewCell *cell = [tableView   
  29.                              dequeueReusableCellWithIdentifier:SomeID];  
  30.   
  31.     if (cell == nil) {  
  32.         cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero  
  33.                  reuseIdentifier:SomeID] autorelease];  
  34.     }  
  35.     ...  
  36. }  


Adding an Image
UITableViewCell 의 기본 옵션으로 각 행의 왼쪽에 이미지를 붙일 수 있음.
  1. // tableview:cellForRowAtIndexPath:  
  2. ...  
  3. UIImage *image = [UIImage imageNamed:@"someImage.png"];  
  4. cell.image = image;  
  5. ...  


Addtional Configurations
Setting the Indent Level
  1. #pragma mark -  
  2. #pragma mark Table View Delegate Methods  
  3. // 각 행의 indent level(NSInteger) 설정.  
  4. - (NSInteger)tableView:(UITableView *)tableView  
  5. indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath {  
  6.     ...  
  7.     return indentLevel;  
  8. }  


Handling Row Selection
USER 가 선택한 행의 이벤트 전후로 핸들링이 가능.
  1. - (NSIndexPath *)tableView:(UITableView *)tableView  
  2.   willSelectRowAtIndexPath:(NSIndexPath *)indexPath {  
  3.     // USER 선택에 대한 이벤트 전처리.  
  4.     ....  
  5. }  
  6.   
  7. - (NSIndexPath *)tableView:(UITableView *)tableView  
  8.    didSelectRowAtIndexPath:(NSIndexPath *)indexPath {  
  9.     // USER 선택에 대한 이벤트 후처리.  
  10.     ....  
  11. }  


Changing Font Size and Row Height
  1. // tableview:cellForRowAtIndexPath:  
  2. ...  
  3. cell.font = [UIFont boldSystemFontOfSize:80];  
  4. ...  
  5. // 열의 높이 설정.  
  6. - (CGFloat)tableView:(UITableView *)tableView  
  7. heightForRowAtIndexPath:(NSIndexPath *)indexPath {  
  8.     ....  
  9.     return height;  
  10. }  
Posted by 오늘마감

댓글을 달아 주세요

아이폰어플개발정보2010. 9. 11. 01:32
아이폰 어플 개발 Table View 의 기초

Table View Basics
iPhone tables(UITableView) 의 행(Row)수는 제한이 없음.(iPhone OS Memory)
UITableView - 테이블의 Data를 표시하는 뷰 오브젝트.
UITableViewCell - 테이블의 단일 행을 표현.

UITableViewCell 에 복수의 데이터를 추가하기 위해서
1.UITableViewCell 에 subview 를 추가 하거나
2.UITableViewCell 을 상속하는 서브클래스 작성.

Table > Section > Rows...
그룹 테이블(Figure 8-3)에서 각 Section 은 한 그룹을 나타냄.
인덱스 테이블(Figure 8-3)에서 각 Section 은 한 인덱스의 집합.

Implementing a Simple Table
Writing the Controller

  1. // delegate, datasource protocol 선언.
  2. // datasource 는 테이블 각 행에 대한 데이터 핸들.
  3. // delegate 는 데이터의 설정(font, user interation...) 핸들.
  4. @interface SomeUITableView  {  
  5.     // Table Data.
  6.     NSArray *tableData;  
  7.     ...  
  8. }  
  9. #pragma mark -
  10. #pragma mark Table View Data Source Methods
  11. // 해당 Section 에 행 수.
  12. - (NSInteger)tableView:(UITableView *)tableView  
  13.  numberOfRowsInSection:(NSInteger)section {  
  14.     return [self.tableData count];  
  15. }  
  16. // 행이 그려질 때 호출되어 현재 표시될 행의 UITableViewCell 를 리턴.
  17. // NSIndexPath 를 이용해서 해당 Section[indexPath section]과
  18. // 해당 행[indexPath row]을 알 수 있음.
  19. // UITableViewCell 는 캐쉬화 되고 시스템 메모리가 부족할 때 자동 메모리 해제됨.
  20. - (UITableViewCell *)tableView:(UITableView *)tableView  
  21.          cellForRowAtIndexPath:(NSIndexPath *)indexPath {  
  22.     // cache 할 때 구분자.
  23.     static NSString *SomeID = @"SomeID";  
  24.     // cache 에 저장된 UITableViewCell 취득.
  25.     UITableViewCell *cell = [tableView   
  26.                              dequeueReusableCellWithIdentifier:SomeID];  
  27.     if (cell == nil) {  
  28.         cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero  
  29.                  reuseIdentifier:SomeID] autorelease];  
  30.     }  
  31.     ...  
  32. }  


Adding an Image
UITableViewCell 의 기본 옵션으로 각 행의 왼쪽에 이미지를 붙일 수 있음.
  1. // tableview:cellForRowAtIndexPath:
  2. ...  
  3. UIImage *image = [UIImage imageNamed:@"someImage.png"];  
  4. cell.image = image;  
  5. ...  


Addtional Configurations
Setting the Indent Level
  1. #pragma mark -
  2. #pragma mark Table View Delegate Methods
  3. // 각 행의 indent level(NSInteger) 설정.
  4. - (NSInteger)tableView:(UITableView *)tableView  
  5. indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath {  
  6.     ...  
  7.     return indentLevel;  
  8. }  


Handling Row Selection
USER 가 선택한 행의 이벤트 전후로 핸들링이 가능.
  1. - (NSIndexPath *)tableView:(UITableView *)tableView  
  2.   willSelectRowAtIndexPath:(NSIndexPath *)indexPath {  
  3.     // USER 선택에 대한 이벤트 전처리.
  4.     ....  
  5. }  
  6. - (NSIndexPath *)tableView:(UITableView *)tableView  
  7.    didSelectRowAtIndexPath:(NSIndexPath *)indexPath {  
  8.     // USER 선택에 대한 이벤트 후처리.
  9.     ....  
  10. }  


Changing Font Size and Row Height
  1. // tableview:cellForRowAtIndexPath:
  2. ...  
  3. cell.font = [UIFont boldSystemFontOfSize:80];  
  4. ...  
  5. // 열의 높이 설정.
  6. - (CGFloat)tableView:(UITableView *)tableView  
  7. heightForRowAtIndexPath:(NSIndexPath *)indexPath {  
  8.     ....  
  9.     return height;  
  10. }  



출처 : http://blog.naver.com/PostList.nhn?blogId=hana_815¤tPage=91
Posted by 오늘마감

댓글을 달아 주세요

아이폰어플개발정보2010. 8. 23. 09:37
[펌] 쓰레드 기초

아아폰에서 모든 어플리케이션은 기본적으로 하나의 쓰레드를 가지고 있다. 이 쓰레드는 UIApplication 클래스에서 자동으로 생성하며 프로그램의 메인 룹이 이곳에서 실행된다. 하지만 어떤 작업이 그 작업을 마치는데 너무 오랜 시간이 걸린다면 그 작업을 새로은 쓰레드로 만들어서 실행하는 것이 좋다. 메인 쓰레드는 기본적으로 사용자와 상호 작용을 해야하는데, 어떤 작업이 시간을 너무 소모하면 사용자가 프로그램이 멈춘 것으로 오해 할 수 있다.

아이폰 OS 에서 쓰레드는 리눅스와 유닉스에서 지원하는 POSIX 쓰레드를 그대로 이용할 수 있다. 또한 코코아 터치 프레임워크 자체에서도 NSThread 라는 클래스를 이용해서 쓰레드를 좀 더 편리하게 생성할 수 있게 해 준다. 만약 이미 POSIX 로 작성된 코드를 가지고 있는 경우라면 새롭게 NSThread로 포팅하지 않고 바로 사용하는 것이 좋을 것이다.

이제 부터 코코아 터치가 제공하는 쓰레드 기능을 하나씩 구현해 보도록하자. POSIX 쓰레드는 이책에서는 따로 설명하지 않겠다.

* 쓰레드 생성하기

먼저 NSThread 객체를 이용해서 쓰레드를 생성해 보자. 다음은 NSThread 의 클래스 메서드를 이용하는 방법이다.

01: [NSThread
02: detachNewThreadSelector:@selector(threadFunc:)
03: toTarget:self
04: withObject:nil
05: ];

detachNewThreadSelector 메서드는 지정한 객체의 메서드를 이용해서 새로운 쓰레드를 생성해 준다. 위 코드에서 생성된 쓰레드는 바로 실행을 시작한다. 다음은 쓰레드를 생성하는 다른 방법이다.

01: NSThread* myThread = [[NSThread alloc]
02: initWithTarget:self
03: selector:@selector(threadFunc:)
04: object:nil
05: ];
06: [myThread start];

위 코드는 alloc, init 으로 생성을 먼저 한 후에 실행은 나중에 start 메서드를 호출할때 하도록 할 수 있다.

마지막으로 NSObject 를 이용해서 쓰레드를 생성하는 방법도 있다.

01: [objectA
02: performSelectorInBackground:@selector(doSomething)
03: withObject:myName];

 

* 쓰레드 메서드 구현하기

쓰레드에서 실행될 메서드는 다음과 같이 정의한다. 전달되는 인자는 쓰레드를 생성할 때 설정했던 object 가 넘어온다.

01: - (void)doSomething:(NSString*)name {
02: NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
03:
04: // 작업
05:
06: [pool release];
07: }

오토릴리즈(autoreleae) 풀은 객체 중에서 autorelease 메서드를 호출해서 생성된 객체들을 관리한다. 오토릴리즈 풀을 생성하면 그 이후로 생성되는 모든 autorelease 객체를 마지막에 생성된 오토릴리즈 풀 객체가 관리한다. 그리고 오토릴리즈 풀을 해제(release) 하면 이때 모든 오토릴리즈 객체도 같이 해제된다.

모든 쓰레드는 자신만의 오토릴리즈 스택을 관리하기 때문에, 쓰레드를 생성한 후 반드시 오토릴리즈 풀을 생성해야 한다.

* 런 루프

런 루프는 쓰레드가 외부와 통신하기 위해서 존재한다. 런 루프는 자신(쓰레드)에게 전달된 이벤트가 있는지를 검사하고, 만약 존재하는 경우 알맞은 메서드를 호출해 준다. 런 루프가 처리하는 이벤트는 크게 두가지가 있다.

• 입력 소스
    • performSelector:: 계열의 메서드를 호출해서 지정한 셀렉터를 실행시켜달라는 외부의 요청.
• 타이머
    • 타이머를 생성하면 그 타이머는 코드가 실행된 쓰레드의 런 루프에 소속된다. 런 루프는 타이머중에서 지정한 시간이 경과한 것들을 검사해서 메서드를 호출해 준다.

다음 코드를 보자.

01: if ( tapCount == 2) {
02: // 5개 모두 보여주자.
03: [self performSelector:@selector(showAllCircles) withObject:nil afterDelay:0.3];
04: NSLog(@"Scheduled");
05: }
06: ... 생략 ...
07: if (tapCount > 2) {
08: [UIView cancelPreviousPerformRequestsWithTarget:self];
09: NSLog(@"Cancelled");
10: }

이때 이미 쓰레드에 입력 소스를 추가하는 작업을 구현한 것이다. performSelector:withObject:afterDelay 메서드를 호출하면 현재 쓰레드의 런 루프에 입력 소스로써 등록이 된다. 그리고 런 루프가 실행될 때 자신에게 등록된 모든 입력 소스를 검사해서 조건이 만족되는 (여기서는 0.3초 경과) 경우 해당 메서드를 호출(예제에서는 showAllCircles)해 주는 것이다.

만약 스스로 쓰레드를 생성했다면 런 루프가 자동으로 실행되지는 않는다. 그래서 자신의 쓰레드 함수에서 직접 런 루프를 실행시켜서 주기적으로 외부의 이벤트에 대응할 수 있도록 만들어야 한다. 하지만 쓰레드가 하나의 작업만 수행하고 종료되는 경우라면 반드시 필요하지는 않다. 하지만 무한 루프를 돌면서 지속적으로 상호작용이 필요한 쓰레드라면 반드시 런 루프를 실행해 주도록 하자.

01: - (void)doSomething:(NSString*)name {
02: NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
03:
04: NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop];
05: BOOL stop=NO;
06:
07: while(!stop) {
08: // 작업
09: [myRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]];
10: }
11:
12: [pool release];
13: }

4행에서 현재 쓰레드의 런 루프를 얻어온다. 그리고 9행에서 런 루프를 실행시킨다. 이 때 runIntilDate 메서드는 지정한 시간까지 런 루프를 실행시켜 준다. 하지만 런 루프가 아무런 할 일이 없다면 바로 종료된다.

* 쓰레드의 대안

쓰레드를 생성하는 코드를 직접 작성하지 않고도 간접적으로 쓰레드를 생성하게 할 수 있다. 이때 NSInvocationOperation 객체를 이용한다.

01: NSInvocationOperation* op =
02: [[[NSInvocationOperation alloc]
03: initWithTarget:self
04: selector:@selector(myMethod:) object:data] autorelease];

위 코드는 NSInvocationOperation 객체를 생성해 준다. 다음으로 할 일은 동작을 시작시키는 일이다.

01: NSOperationQueue* queue = [[NSOperationQueue alloc] init];
02: [queue setMaxConcurrentOperationCount:1];
03: [queue addOperation:op];

위 코드와 같이 NSOperatonQueue 객체를 생성하고 그 객체에 작업을 등록해 주면 된다.

[출처: http://maclove.pe.kr/30]



출처 : http://blog.naver.com/PostView.nhn?blogId=baek2187&logNo=150059860556
Posted by 오늘마감

댓글을 달아 주세요

오브젝트C2010. 8. 22. 19:58
Objective-C의 기초

http://developer.apple.com/iphone/gettingstarted/docs/objectivecprimer.action

Objective-C 언어는 객체지향 Programming이 가능한 심플한 컴퓨터 언어이다. Objective-C는 표준 ANSI C를 확장하였으며 이를 통하여 클래스, 메써드, properties를 정의 하며 클래스의 동적확장을 더욱 더 증진시킨다. 클래의 문법과 설계는 Smalltalk에 기반을 하며 이는 최초의 객체지향 programming 언어이다.

객체지향 Programming을 해본적이 있다면 아래의 내용은 Object-C의 기본 문법을 배우는데 도움이 되는 정보이다. 많은 전통적인 객체지향 개념들(슐화, 상속성, 다향성과 같은) Object-C 안에서 모두 구현이 가능하다. 몇몇 중요한 차이점은 이 문서에 소개가 될것이고 더 깊은 정보들에 대해서 제공을 한다.

만약 객체지향 Programming 언어를 써본적 없다면 다음으로 넘어가기 전에 기본 개념을 이해할 필요가 있다. 객체의 사용 그리고 객체지향적인 개념은 iPhone Application을 설계하는 기본이며 어떻게 상호작용을 하는지에 대한 이해는 iPhone application을 중요하다. 객체지향개념의 개론은 Object-Oriented Programming with Objective-C을 보라. 추가적으로 Cocoa Fundamentals Guide를 보면 Cocoa에서 객체지향 디자인패턴을 사용하는 방법에 대한 정보를 얻을 수 있다.

For a more detailed introduction to the Objective-C language and syntax, see The Objective-C 2.0 Programming Language.

Object-C 언어와 문법에 대한 상세한 소개는 The Objective-C 2.0 Programming Language을 보라.

Objective-C: A Superset of C c의 확장

Objective-C는 ANSI 버젼의 c언어와 기본적인 c문법의 집합이다. C코드처럼 헤더 파일과 소스파일을 분리하여 선언부와 구현부를 분리하여 정의할 수 있다. Objecive-C에서 사용하는 파일 확장자는 표1에 나와있다.

 
표1  Objective-C code의 확장자

헤더파일. 헤더파일은 class, type, function, 상수의 정의를 포함한다.

소스 파일. 이 확장자는 Objective-C와 C 코드를 사용한 소스이다.

소스 파일. 이 확장자는 Objective-C와 C++ class를 사용할 수 있다. C++ class에 대한 접근도 가능하다.

When you want to include header files in your source code, you can use the standard #include compiler directive but Objective-C provides a better way. The #import directive is identical to #include, except that it makes sure that the same file is never included more than once. The Objective-C samples and documentation all prefer the use of #import, and your own code should too.

소스코드에 헤더 파일을 포함하고 싶다면, 표준방식 #include를 사용하여 컴파일러에 직접 지시할 수 있다 그러나 Objective-C는 더 좋은 방법을 제공한다. #import는 #include와 동일한 지시를 하지만 한번이상 동일한 파일이 포함되지 않게 만든다. Objective-C 예제와 문서에는 모두 #import를 사용하고 너의 코드에도 그렇게 해라.

Strings

C의 포함집합(superset)이라는 것은 Objective-C가 C의 규칙으로 string을 사용하는 것을 지원한다. 다른 말로, 하나의 character들은 '로 묶이고 문자열은 "으로 묶인다는 것이다. 그렇지만, 대부분의 Objective-C framework들은 C형식의 문자열 자주 사용하지 않는다. 그대신에 대부분의 framework들은 NSString 객체로 통용된다.

NSString class,는 당신이 기대하는 모든 잇점을 가지고 있으며, 저장된 임의길이의 문자열을 위한 완성된 메모리 관리를 포함하고, Unicode를 지원, printf형태의 유용한 포맷팅 그리고 더 많은 것을 가진 문자열을 싸고있는 객체이다. 때문에 비슷한 문자열은 일반적으로 사용이 되지만 Objective-C는 NSString객체를 상수로부터 생성할 수는 약식표기법을 지원한다. 이같은 약식 표기를 사용하려면 모든 문자열의 앞에 @를 붙여야 하며 다음 예제에 나온다.

NSString* myString = @"My String\n"; NSString* anotherString = [NSString stringWithFormat:@"%d %s", 1, @"String"]; // Create an Objective-C string from a C string NSString* fromCString = [NSString stringWithCString:"A C string" encoding:NSASCIIStringEncoding]; 

Classes

다른 모든 객체지향 언어처럼, Objective-C안의 클래스들은 일부 데이터에 대해 캡슐화를 지원 한다. 객체는 실행시기의 클래스의 instance이며, 그리고 클래스의 클래스 와 method의 포인터에 의해 선언된 instance 변수의 복사본 을 그것 자신에 포함한다.

Objective-C 클래스의 명세는 두개의 뚜렷한 구분을 필요로 하는데 그것은 interface 그리고 imlementation이다. Interface는 클래스의 정의 일부를 선언하고 클래스와 교류하는 instance 변수와 method를 정의 한다. Implementation 클래스의 실제 동작하는 코드를 가진 method 일부를 포함한다. 그림1은 MyClass라고 불리는 클래스를 선언하는 문법을 보여주는데 이 클래스는 NSObject 기본 클래스를 상속 받았다. 클래스의 정의는 항상 @interface로 시작해서 컴파일러에 지시한다. 그리고 끝은 @end로 지시한다. 그 다음 클래스 이름은(:으로 구분된) 부모클래스의 이름이다. 클래스의 instace(또는 맴버) 변수는 { }블럭안에 정의된다. 그 뒤로 클래스의 method들이 정의 된다. 세미콜론은 instance변수 와 method의 정의가 끝났음을 나타낸다.

(출처:iPhone Dev Center)

Listing 1 shows the implementation of MyClass from the preceding example. Like the class declaration, the class implementation is identified by two compiler directives—here, @implementation and @end. These directives provide the scoping information the compiler needs to associate the enclosed methods with the corresponding class. A method’s definition therefore matches its corresponding declaration in the interface, except for the inclusion of a code block.

리스트1은 앞선 예제 MyClass의 구현을 보여준다. 클래스의 선언처럼 클래스의 구현은 컴파일러에 두개의 지시자인 @implementation과 @end로 선언이 된다. 이 지시자들은 일치하는 클래스와 함께 둘러싸인 메써들과 필요한 연동을 제공한다. 메써드의 정의와 어울리는 인터페이스안의 일치하지만 그 인터페이스의 선언과 일치하는 포함된 코드블럭은 제외한다.

Listing 1  A class implementation

@implementation MyClass - (id)initWithString:(NSString *) aName { if (self = [super init]) { count count = 0; data = nil; name = [aName copy]; return self; } } + (MyClass *)createMyClassWithString: (NSString *) aName { return [[[self alloc] initWithString:aName] autorelease]; } @end

Note: Although the preceding class declaration declared only methods, classes can also declare properties. For more information on properties, see “Properties”.

When storing objects in variables, you always use a pointer type. Objective-C supports both strong and weak typing for variables containing objects. Strongly typed pointers include the class name in the variable type declaration. Weakly typed pointers use the type id for the object instead. Weakly typed pointers are used frequently for things such as collection classes, where the exact type of the objects in a collection may be unknown. If you are used to using strongly typed languages, you might think that the use of weakly typed variables would cause problems, but they actually provide tremendous flexibility and allow for much greater dynamism in Objective-C programs.

The following example shows both strongly and weakly typed variable declarations for the MyClass class:

NOTE:단지 method의 선언을 정의하기 전이라고 해도 클래스는 properties선언을 통해 할 수 있다. properties에 대한 더 많은 정보를 원한다면 "Properties"를 보라.

변수에 객체를 저장할때 당신은 항상 포인트 타입을 사용한다. Objective-C 강한형(Strongly type)과 약한형(Weekly type) 두가지를 통해 변수에 객체를 저장하는 방법을 제공한다. 강한형 포인터들은 변수형 선언안에 클래스의 이름을 포함한다. 약한형 포인터는 객체 대신에 id type을 사용한다. 약한형 포인터들은 collection 클래스를 이용할때 사용이 되는 이유는 collection 정확한 클래스의 형태를 알 수 없을때 사용이 된다. 마약 당신이 강한형 포인트를 사용하는 언어를 사용했다면, 넌 약한형이 문제를 일으킬것이라고 생각하게 된다 그러나 그것들은 크다란 융통성과 Objective-C의 큰 원동력을 허용한다.

다음 예제는 MyClass class에서 쓸 두가징형태의 변수 방법을 보여준다

MyClass* myObject1; // Strong typing id myObject2; // Weak typing 

Methods

A class in Objective-C can declare two types of methods: instance methods and class methods. An instance method is a method whose execution is scoped to a particular instance of the class. In other words, before you call an instance method, you must first create an instance of the class. Class methods, by comparison, do not require you to create an instance, but more on that later.

The declaration of a method consists of the method type identifier, a return type, one or more signature keywords, and the parameter type and name information. Figure 2 shows the declaration of the insertObject:atIndex: instance method. The declaration is preceded by a minus (-) sign, which indicates that this is an instance method. The method’s actual name (insertObject:atIndex:) is a concatenation of all of the signature keywords, including colon characters. The colon characters declare the presence of a parameter. If a method has no parameters, you omit the colon after the first (and only) signature keyword. In this example, the method takes two parameters.

 

 


출처 : http://blog.naver.com/PostView.nhn?blogId=baek2187&logNo=150059568493
Posted by 오늘마감

댓글을 달아 주세요

아이폰기본사용2010. 6. 23. 21:10
아이폰 처음 구입시 꼭 알아야할 기초 사용법.

[아이폰/아이폰 사용법]

아이폰 처음 구입시 꼭 알아야할 기초 사용법.

사파리 기본 기능복사하기

사파리를 이용 뉴스를 보고 마음에 드는 글이나

사진을 복하사하 싶을때는 위 사진처럼 이용합니다

글복사:글복사하고자 하는 문장중에  아무단어나

 꾹 누르면 왼쪽 화면 처럼 나옵니다

그럼 믿에사진 화면처럼 글복사 범위조절바를

누르고 드래그를 하시면 자기가 복사하고자

하는 글의 범위를 설정하실수 있습니다.

▶ 이미지 저장

이미지 저장: 저장 하고자 하는 이미지를

 꾹눌러줍니다 그럼 위 사진처럼 저장 하고자 하는 팝업창이 뜹니다
그리고 이미지 저장을 누르시면 아이폰 사진란에 저장됩니다.

▶ 사파리 새로고침기능

새로고침:동그란 화살표 모양을 클릭하시면

 새로고침 기능입니다.

▶ 홈버튼 두번클릭설정

설정-일반-홈 을 선택하시면 위화면 처럼 나타납니다

락화면이 아닌 일반화면 에서 홈버튼 두번 클릭을 하면

어떠한 기능을 실행시킬지 선택하실수 있습니다

자주 사용하는 기능을 선택해놓으면 유용하게 사용하실수 있을겁니다.

▶ 아이폰에서 계정 로그인 로그아웃하기

설정-Store 를 선택하시면 위화면과 같이

자신의 계정을 로그인 로그아웃을 하실수 있습니다

위 기능의 장점은 한국계정과 미국계정 둘다

가지신분드에게 유용합니다

한국계정으로 로그인을 하면 한국 Store로

미국계정으로 로그인하면 미국Store로 접속이 됩니다

한국&미국 Store에 중복되지 않는 어플들을 받을때 좋습니다.

▶ 키보드 자동수정기능 끄기

설정-일반-키보드-자동수정 를 선택하시면

문자나 일반 글을쓸시 자동으로 수정되는

 기능을 끄실수 있습니다.



출처 : http://blog.naver.com/PostView.nhn?blogId=mytelelink&logNo=20101835527
Posted by 오늘마감

댓글을 달아 주세요

오브젝트C2010. 6. 21. 18:29
objective-c 기초

1. Objective-C 의 특징


일단 Objective-C의 중요한 특징들에 대해서 먼저 알아보도록하자.
앞에서도 이야기 했듯이 오브젝티브-C는 C++과는 달리 진정한 ANSI C의 슈퍼셋이다. C++의 경우 C에서 되던게 갑자기 안되는 경우가 종종 있다. :( 그리고 Objective-C는 C++보다 훨씬 다이나믹하다. 종종 그렇기 때문에 더 느리다고 비난의 대상이 될 때도 있긴 하다. 또한 복잡한 C++의 문법에 비해서 Objective-C는 상당히 간소한 문법을 가지고 있다. 그리고 Objective-C는 C++ 보다 쎄련되었다. 메시징 신텍스가 마치 스몰톡 같다!
그리고 결정적으로 앞에서 이야기하기도 했지만 이런 장점들에도 불구하고 생각보다 느리지는 않다.
Objective-C의 소스파일은 ".m"으로 끝난다. gcc는 .m으로 끝나는 파일을 Objective-C소스로 판단하고 .mm으로 끝나는 파일은 Objective-C++로 판단한다. Objective-C++은 Objective-C코드와 C++코드를 동시에 병행해서 사용할 수 있게 해주며 GCC 3.1 이후 부터 지원된다. 만일 동일한 프로젝트 내에서 C로만 구현해둔 파일이 있다면 확장자를 c로 C++로만 구현된 파일은 cpp로 하면 된다.

● Dynamic Typing

앞서 이야기 했듯이 Objective-C는 다이나믹한 언어이다. Objective-C에서는 오브젝트는 id라는 데이타 타입으로 표현된다. id는 실제로는 오브젝트의 포인터이다.
id에 대해서 이야기 하면서 하나 더 짚고 넘어가야 할 부분이 있데, C에서는 리턴값을 생략하면 int가 리턴되는것으로 정의되지만 Objective-C의 메소드에서는 리턴값이 생략되면 id가 리턴된다.
또한 nil 키워드가 null 오브젝트로 정의 되어있다. 이것은 id값이 0임을 말한다.
id타입은 그 대상이 오브젝트라는 것을 제외하고는 오브젝트에 대한 어떤 정보도 제공하지 않으며 이로인해 상당히 다이니믹한 모습을 보여준다. 컴파일 단계에서는 id에 무엇이 들어갈지 알 수 없으며 실제 런타임에서만 오브젝트이 상세정보, 즉 인스턴스 변수와 메소드에 대해서 알아볼 수 있다.
모든 사용가능한 오브젝트는 isa라는 인스턴스 변수를 가지는데 이것은 오브젝트의 클래스(클래스 오브젝트 또는 그냥 클래스라고 지칭한다. - 소스코드에서의 클래스를 말한는것과는 조금 다르다)를 알려준다. 이것은 런타임 시스템에서 각각의 오브젝트가 무엇으로부터 인스턴스화 되었는지 알려주는 역할을 한다. 이것으로 실행시간에 다이나믹 타이핑을 지원한다.

● Message 기반

오브젝티브 C에서는 바로 메소드를 찾아서 불러주는게 아니라 리시버(메시지를 받을 객체)에 메시지를 보내면 리시버가 적절한 메소드를 찾아서 불러주는 구조로 되어있다.
오브젝트가 무엇인가 하게하기 위해서 method로 정의되어 있는 메시지를 보내면 된다. 오브젝티브 C에서는 아래처럼 리시버와 메세지를 대괄호 안에 넣으면 된다.
	[receiver message] 

receiver는 오브젝트이며 메시지는 무엇을 할것인지를 말한다. 메시지는 메소드 이름과 전달할 매개변수로 구성된다. 메시지가 전달되면 런타임 시스템은 리시버에서 적당한 메소드를 찾아서 실행한다.
예를 들어 myCircle오브젝트에 display라는 메시지를 보내면 원이 화면에 디스플레이 된다면 아래와 같이 표현할 수 있다.
	[myCircle display]; 

메시지에 매개변수를 보낼 수 있는데 예를 들면 아래와 같이 표현된다.
	[myCircle setOrigin:30.0 :50.0]; 

setOrigin::은 메시지 이름이며 두개의 콜론을 가지는데 각각 하나의 파라메터를 보낼 수 있다. 흔히 콜론 앞에 매개변수의 설명을 붙이는데 예를 들면 setWidth:height: 처럼 사용한다.
	[myRect setWidth:10.0 height:15.0]; 

또한 메시지는 가변적인 갯수의 매개변수를 보낼 수 있으며 메시지 이름의 끝에 콤마로 구분짓는다.
	[receiver makeGroup:group, memberOne, memberTwo, memberThree]; 

C언어와 같이 메소드는 리턴 값을 가진다.
	BOOL isFilled; 	isFilled = [myRect isFilled]; 

그리고 하나의 메시지 전송을 다른 메시지 전송과 같은 줄에 포함 시킬 수 있다. 이 형태는 자주 보게 될 것이다.
	[myRect setPrimaryColor:[otherRect primaryColor]]; 

이 경우 otherRect의 primaryColor메소드가 돌려주는 객체를 다시 myRect의 setPrimaryColor메시지를 불러서 myRect의 primaryColor로 만들어준다.
C++의 경우
	myRect->setPrimaryColor(otherRect->primaryColor()); 

이렇게 사용될것이다.
만일 여기서 primaryColor가 nil이라면, 예를 들어 C++의 경우
	myRect->primaryColor()->getRed(); 

이런 코드를 작성하게 된다면 이 프로그램은 NULL 포인터를 참조해서 크래쉬 하게 될 것이다.
하지만 Objective-C에서는 걱정 하지 않아도 된다. nil에게 보내는 메시지도 가능하기 때문이다. nil에게 메시지를 보내면 nil이 돌아온다.
	[[myRect primaryColor] red]; 

즉 이러한 코드를 작성해도 갑자기 크래쉬하는 일은 발생하지 않는다.
C++에서와 마찬가지로 메소드는 그 오브젝트의 인스턴스 변수를 자동적으로 사용할 수 있다. 역시 다른 객체에 있는 값이 필요하다면 메소드의 매개변수로 받아야 한다.
메시지에 대한 더 상세한 내용은 뒤에 다시 다루게 될 것이다.
?메시지와 메소드란 말이 혼용되어 사용되었다. 이 부분에 대해서는 뒤에 나오는 설명을 읽고 나면 좀 더 이해가 될 것이다. 가끔은 정확하게 이 둘을 구분하는것이 무의미해질때도 있지만 필자가 일부러 메시지란것을 강조했다.

● Polymorphism

Polymorphism에 대해 이야기 하기 전에 기존의 C++같은 언어에서의 polymorphism에 대해서는 잠시 잊어두도록하자. 오히려 더 헷깔리게 만들기 때문이다. Objective-C의 polymorphism은 단지 Objective-C의 polymorphsim이다. 이게 무슨 polymorphism이냐고 따질 만한 가치도 없다. 이것은 Objective-C가 메소드와 메시지를 엄밀하게 말하면 구분 짓는다는 사실에 염두하고 보기바란다.
만일 A라는 객체와 B라는 객체가 있다고 하자. 이 객체들이 setOrigin이라는 메시지를 받는다면 어떻게 될까? 만일 A와 B가 같은 클래스로부터 파생되어서 나왔다면 같은 동작을 하겠지만 만일 다른 클래스로 부터 파생되어 나온 객체라면 다른 동작을 보인다. 이것이 메시지의 polymorphism이다. 이렇게 동일한 메시지가 각각의 객체에서 다르게 해석되기 때문에 개발자들은 메시지의 이름을 정하는데 상당히 여유로울 수 있고 공동개발을 할때도 메시지의 혼동을 줄일 수 있다.
?메시지를 부르는 일련의 작업이 특정 객체의 맴버펑션을 바로 호출하는 C++의 방식과 다르다는것을 염두해두기 바란다.

● Dynamic Binding

함수의 호출과 메시지의 전달이 그러면 무엇이 다르다는 것인가? 함수의 호출은 함수와 그 매개변수들이 컴파일된 코드에 완전히 바인딩되어버린다. 그렇지만 메시지와 메시지를 받는 오브젝트는 그렇지 않다. 그것은 실행시간에 메시지를 보내기 전까지 전혀 바인딩되지 않는다.
어떤 메소드를 실행할건지는 실행시간에 메시지를 받으면서 결정난다. 컴파일 할때는 알 수 없다.
메시지에 대해서 실행되는 메소드는 리시버에 의해 결정난다. 다른 리시버라면 다른 메소드가 실행되는것이다.(polymorphism에서 설명했다) 컴파일러가 메시지에 대해서 정확한 메소드 구현을 찾게 하기 위해서 오브젝트가 무슨 클래스에서 유래했는지 알아야 한다. Objective-C에서는 이런 정보가 소스코드에서 파악이 불가능하며 리시버가 메시지를 받은 시점에서 알 수 있다. 이것이 Objective-C에서 구현된 dynamic binding이다.
앞서 설명한 polymorphism과 함께 생각해보면 이해가 쉬울것이다.
메시지가 보내지면 런타임 메시징 루틴은 리시버의 메소드 리스트에서 메시지와 같은것이 있는지 확인해서 그 메소드를 호출하고 리시버의 인스턴스 변수들의 포인터를 넘긴다.
메시지안에 있는 메소드 이름은 실제 실행될 메소드를 찾는데 사용되어서 셀랙터라고 부른다.
이런 dynamic binding은 polymorphism과 함께 유연함과 힘을 제공한다.
예를 들면 워드프로세서를 한번 생각해보자. 화면에 선택된 영역이 있다. 이 선택된 영역은 텍스트 일수도 있고, 레스터이미지 일수도 있고 벡터 이미지 일수도 있다. 아니면 복합적인 형태의 표이거나 다른 형태의 데이타의 표현일 수 도 있다. 다이나믹 바인딩이 지원되지 않는 언어라면 이런 경우 메뉴에서 Copy를 선택하면 어떤 동작을 해야할까?
먼저 선택된 것이 무엇인지 부터 판단해야한다. 결과적으로 코드가 복잡해지는 것이다.
반대로 다이나믹 바인딩과 폴리모피즘을 이용한 오브젝티브 C의 경우 선택된 객체가 무엇인지 신경 쓰지 않아도 된다 단지 copy메시지만 보내면 된다. 단, 선택된 객체가 copy를 구현하고 있어야 하지만 말이다. 당연히 특정 객체가 특정 메소드를 구현하고 있는지 런타임시에 확인 할 수 있는 방법도 제공한다.
얼핏 보면 이게 차이가 얼마나 날까 싶다. 하지만 많은 차이가 난다.

● Class

Objective-C에서는 C++과 마찬가지로 오브젝트를 정의하기 위해서 클래스를 정의해야 한다. 이 클래스가 오브젝트의 프로토타입이 되는 것이다. 클래스는 인스턴스 변수와 메소드로 이루어진다.
컴파일러는 각 클래스당 단 한개의 오브젝트를 생성한다. 이건은 흔히 팩토리 오브젝트 또는 클래스 오브젝트라고 불리는 것으로 이것은 해당 클래스에 해당하는 오브젝트를 생성하는 역할을 한다. 즉 클래스 오브젝트는 클래스의 컴파일 된 버젼인 것이다. 실제 프로그램에서 작동되는 클래스들은 실행시간 중에 클래스 오브젝트로 부터 만들어진 것이다.
하나의 클래스로 부터 만들어진 모든 객체들은 같은(동일한 메모리 위치에 존재하는, 즉 각 인스턴스마다 복제되지 않은) 메소드를 억세스 하지만 인스턴스 변수들은 각각 가진다.
참고로 Objective-C의 일반적인 코딩 컨벤션은 클래스 이름은 대문자로 인스턴스들의 이름은 소문자로 시작한다.

● Inheritance

클래스는 상속이 가능하다. 새로운 메소드와 변수를 추가 할 수 있지만 기존의 모든 코드를 다시 가져와서 구현할 필요가 없다. 필요하다면 특정 메소드를 오버라이딩 할 수 있다.
모든 클래스들은 하나의 클래스로 부터 상속 되어 있는데 그것은 NSObject이다. root클래스를 제외한 모든 클래스는 superclass를 가지며 모든 클래스들은 superclass가 될 수 있다.(사실 이말에 대해서는 다시 조정할 필요가 있다.)
C++과 다른 점이 있다면 Objective-C는 다중 상속을 지원하지 않는다.

● 인스턴스 변수의 상속

클래스 오브젝트가 새 인스턴스를 만들면 그 클래스에 정의 된 인스턴스 변수 뿐만 아니라 루트에 이르기 까지의 모든 superclass의 변수들도 모두 만들어진다. 그렇게 되어 있기 때문에 NSObject에 있는 isa가 모든 상속된 오브젝트에 포함되며 오브젝트의 클래스가 뭔지 알 수 있다.

● 메소드의 상속

인스턴스 변수와 마찬가지로 메소드도 현재 클래스에서 저장한 것 뿐만 아니라 각각의 superclass를 거쳐 root 클래스에 이르기까지 모든 메소드들에 접근 할 수 있다.
클래스 오브젝트 역시 hierarchy에 따라 상속되어있지만 인스턴스 변수를 가지지 않기 때문에 메소드만 상속한다.

● 메소드의 overriding

새로운 클래스를 정의할때 이미 superclass에 있던 메소드를 다시 구현하면 새로 만들어진 메소드가 원래의 메소드를 오버라이딩 한다. 그렇게 되면 그 새로 만들어진 클래스의 인스턴스는 새로 만들어진 메소드를 사용하고 이로 부터 상속받은 모든 다른 클래스들도 새로 만들어진 메소드를 사용한다.
비록 오버라이딩 된 메소드가 원래의 메소드를 막아버려도 새로 정의된 메소드를 무시하고 원래것을 찾을 수 있는 방법이 제공 되는데 super와 self를 이용한다. 이에 대해서는 뒤에서 다시 다룰 예정이다.
서브클래스가 상속된 메소드를 오버라이드 할 수 있는것에 반해 상속된 인스턴스 변수들을 오버라이딩 할 수는 없다. 만일 이미 정의되어 있는것과 같은 이름의 인스턴스 변수를 만들면 컴파일시 워닝(에러)를 낼 것이다.

● NSObject Class

여기서 루트 클래스인 NSObject에 대해서 알아보고 넘어가도록 하자.
NSObject 클래스는 루트 클래스로 슈퍼클래스를 가지지 않는다. 이것에는 Objective-C를 위한 기본적인 프래임웍과 오브젝트의 사이에서 벌어지는 작동이 정의 되어있다. 즉 런타임 시스템과 같이 움직일 수 있는 최소한의 객체의 형태를 가지고 있다는 말이다. 그래서 새로운 루트 클래스를 만드는것 보다 NSObject를 상속받으므로서 오브젝트가 가져야 하는 최소한의 기능을 가지는 부분을 다시 만들지 않아도 된다.
새로운 루트 클래스를 만드는 작업은 매우 까다로우며 많은 위험을 내포하고 있다. NSObject가 오브젝트를 인스턴스화 시킨다던지 그것을 클래스와 연결하는 작업 또 런타임 시스템에 오브젝트를 확인시키는(identify) 일들을 다 처리해주기 때문에 이런 부분들에 대해 모두 작업을 해야한다. 애플에서 제공하는 문서에서는 NSObject를 상속받도록 권장하고 있다.

● Abstract Classes

어떤 클래스들은 단지 상속하기 위해서 디자인 된것이 있다. 이런 abstract class들은 그 자체만으로는 불완전하지만 그것을 상속받아서 구현할 수 있다.
NSObject클래스는 가장 중요한 abstract class이다. 다른 클래스를 만들때 이 NSObject클래스에서 상속하는 경우도 많고 상속한 클래스의 인스턴스를 사용하기도 하지만 바로 NSObject클래스를 인스턴스화 시켜서 사용하지 않는다.
NSObject는 일반적인 오브젝트의 기능을 가지며 어떤 특정한 기능을 가지지는 않는다.
Abstract Class는 가끔 애플리케이션의 구조를 정의하는데 도움이 되는 코드를 가지고 있다. 이 클래스들의 서브클래스를 만들었을때 이 클래스는 자동적으로 애플리케이션 구조 내에서 다른 오브젝트들과 잘 맞아서 작동된다. 이것은 abstract class들이 반드시 서브클래스를 가지며 그것들은 종종 abstract superclass를 호출하기 때문이다.

● Class Types

클래스의 정의는 어떤 특정 종류의 오브젝트에 대한 명세사항이다. 이것은 데이타 구조를 정의하고(instance variables) 그것의 behavior를 정의한다.(method)
클래스의 이름은 소스코드 내에서 타입 specifier로 나타난다. 다음 예제를 보자
	int i = sizeof(Rectangle); 

여기서 Recangle은 클래스 이름이며 sizeof연산자를 이용해서 그 크기를 알 수 있다.

● Static Typing

클래스 이름을 id 대신 사용해서 오브젝트의 타입을 나타낼 수 있다.
	Rectangle* rect;

이렇게 할 경우 컴파일러에 오브젝트이 종류에 대한 정보를 주기 때문에 스태틱 타이핑이 된다. id가 오브젝트의 포인터가 되는것 처럼 클래스의 포인트로 스태틱 타이핑되는 것이다. 스태틱 타이핑이 포인터를 정확히 명시하는 반면 id는 숨기는 것이다.
스태틱 타이핑은 컴파일러로 하여금 타입 채킹을 하게 한다. 이것은 만일 오브젝트가 처리할 수 없는 메시지를 받거나 다른 형태의 오브젝트이 포인트에 대입을 할때 경고를 나오게 한다.
또한 이것은 코드를 읽는 다른사람에게 의미가 더 명확하게 전달되게 하지만 이것이 런타임 시에 다이나믹 바인딩이나 리시버의 클래스를 다이나믹하게 체크하는데 영향을 주지는 않는다.
오브젝트는 그 자체의 클래스와 그것의 부모 클래스들로 스태틱 타이핑될 수 있다. 예를 들면 Rectangle이 Graphic에서 상속 받았다면 Rectangle클래스는 Graphicc클래스로 스태틱 타이핑 될 수 있다.

● Type Introspection

인스턴스의 타입을 런타임에서도 알 수 있다. NSObject 클래스에 정의되어있는 isMemberOfClass: 메소드를 이용하면 리시버가 어떤 클래스의 인스턴스인지 확인 가능하다. 또한 isKindOfClass: 메소드를 이용하면 특정 클래스의 상속계통에 해당하는 인스턴스인지 확인 가능하다.

● Class Objects

앞에서 클래스를 설명하면서 잠시 나왔던 클래스 오브젝트에 대해서 좀 더 상세하게 이야기 할 필요가 있을것 같다.
클래스 정의에는 다양한 정보들이 들어가있는데 클래스의 이름과 그것의 슈퍼클래스, 인스턴스 변수들, 메소드 이름과 리턴값과 매개변수들 그리고 실제 메소드의 구현이 포함된다.
이들 정보는 런타임 시스템에서 알아볼 수 있는 형태로 컴파일 되어서 저장된다.컴파일러는 단 한개의 오브젝트를 생성하는데 그것이 클래스 오브젝트이다. 이 클래스 오브젝트는 클래스에 대한 모든 정보에 대해 접근이 가능하다. 이 클래스 오브젝트는 새로운 객체의 생성에 대한 요구가 들어오면 클래스의 정의에 따라 새로운 오브젝트를 만드는 기능을 가지고 있다.
정확하게 말한다면 클래스 오브젝트는 오브젝트의 프로토타입을 가지고 있지만 자체적인 인스턴스 변수를 가지지 않기때문에 그 자체가 클래스의 인스턴스는 아니다.
클래스 오브젝트는 컴파일 될때 준비되었다가 코드가 그 클래스를 사용하기 전에 초기화 된다.
클래스 오브젝트를 얻어오기 위해서 -class: 메소드를 사용하는데 예를 들면 다음과 같다.
	Circle* c = [Circle new]; 	Class circleClass = [c class]; 

오브젝티브 C 런타임의 모든 오브젝트는 isa 필드로 시작하는데 그것은 그 오브젝트의 클래스 오브젝트의 포인터를 가지는 것이다. 클래스 오브젝트는 그 오브젝트가 가지는 인스턴스 메소드들을 가지며 각 클래스 오브젝트는 super_class라는 부모 클래스 오브젝트의 포인터를 가지고있다. 물론 루트 클래스는 super_class가 nil이다.
런타임에서 메소드를 부르는 과정은 다음과 같다.

1. 리시버의 isa 멤버를 이용해서 클래스 오브젝트를 찾는다.
2. 클래스 오브젝트의 메소드 리스트에서 메소드를 찾는다.
3. 만일 메소드를 찾을 수 없다면 super_class 포인터를 이용해서 부모 클래스 오브젝트를 찾는다.
4. 2-3번을 메소드를 찾을때까지 반복한다.
5. 만일 끝까지 찾지 못한다면 -forward:: 메소드를 호출한다. -forward:: 메소드는 NSObject에 정의되어 있으며 디폴트 역할은 프로그램을 종료시키는 것이다.
6. 만일 오브젝트가 forwarding 메소드를 찾지 못하면 프로그램은 에러를 내면서 종료한다.
클래스 오브젝트는 일반 오브젝트와 같이 id변수에 포인터를 넣을 수도 있고 메시지도 받을 수 있다.

● Metaclass Objects

오브젝티브 C에서는 클래스 오브젝트와 같이 메타클래스 오브젝트도 하나씩 생성된다.
인스턴스 메소드가 클래스 오브젝트에 저장되어 있는것과 달리 클래스 메소드는 메타클래스 오브젝트에 저장되어있다.
이 경우에도 클래스 오브젝트의 isa에는 메타클래스 오브젝트가 저장되어있다. 메타클래스 오브젝트에서 인스턴스를 찾아나가는 방법은 클래스 오브젝트에서와 같다.
클래스 메소드의 isa와는 다르게 메타클래스 isa는 루트 메타클래스를 가르키고 있고 루트 메타클래스의 슈퍼클래스는 루트 오브젝트 클래스를 가리키고 있다.
이 메타클래스 오브젝트는 개발자가 손댈 필요는 없다.

(그림 2) 인스턴스, 클래스 오브젝트, 메타클래스의 관계

● 인스턴스 생성

앞에서 이야기 했듯이 클래스 오브젝트의 주된 기능은 새로운 인스턴스를 만드는 일이다. alloc메소드는 동적으로 새로운 오브젝트의 인스턴스 변수를 만들고 이것을 모두 0으로 세팅한다. 이것엔 앞서 이야기 했듯이 isa필드에 대해서는 예외적인데 isa에는 클래스 오브젝트의 포인터를 가진다.
	id myCircle; 	myCircle = [Circle alloc]; 

오브젝트가 사용되게 할려면 사용에 적당한 초기화가 필요한데 이때는 init 메소드를 이용한다.
	myCircle = [[Circle alloc] init]; 

alloc메소드가 새로 만든 인스턴스를 리턴하며 그것은 init 메시지를 받을 수 있으며 init 메소드는 초기화된 오브젝트를 넘긴다.

● 클래스 오브젝트를 이용한 사용자화

클래스 오브젝트가 오브젝트 처럼 다뤄지는것은 아무 생각없이 만들어 진것이 아니다. 이것은 클래스를 이용해서 오브젝트를 커스터마이징을 할 수 있게 해준다.
만일 특정 크기의 NSMatrix의 인스턴스가 있다고 하자, 이게 어떤 형태의 데이타로 이루어 질 수 있는데 이 NSMatrix의 인스턴스에 클래스 오브젝트를 넘기므로써 이것이 무슨 형태의 매트릭스인지 동적으로 결정 할 수 있게 한다.

● 변수와 클래스 오브젝트

앞서 설명했듯이 클래스 오브젝트에는 인스턴스 변수가 없다. 각각의 인스턴스화된 오브젝트가 각각의 인스턴스 변수를 가지는데 클래스 오브젝트에는 변수를 넣을 수 없다. 이말인즉, 클래스 변수가 없다는 말이다. 클래스 오브젝트는 그것의 오브젝트들의 인스턴스 변수들의 복사본도 가질 수 없고 접근 할 방법 마져 없다.
그러므로 모든 인스턴스화된 오브젝트들이 변수를 공유할 방법이 있어야 한다. 이런 경우 클래스 선언 밖에서 static으로 변수를 선언하는 방법 밖에 없는데 이경우 상속에서는 제외된다.

● 클래스 오브젝트의 초기화

만을 클래스 오브젝트가 사용될려면 일반 오브젝트의 인스턴스화에서와 마찬가지로 초기화 되어야 한다. 프로그램이 클래스 오브젝트를 얼로케이션 하는것이 아니기 때문에 오브젝티브 C는 다른 방법으로 프로그램이 클래스 오브젝트를 초기화 할 수 있게 한다.
런타임 시스템은 모든 클래스 오브젝트에게 그 클래스가 사용되기전에 초기화 할 수 있게 initialize 메시지를 보낸다. 만일 초기화가 필요없다면 initialize 메소드를 구현 하지 않으면된다. initialize 메소드는 NSObject에 선언되어 있지만 아무것도 구현되어 있지 않은 상태로 있다.
만일 클래스에서 static이나 글로벌 변수를 사용해야 한다면 initialize 메소드에서 초기화 하는것이 좋을 것이다.

● 소스코드에서의 클래스 이름

소스코드 내에서 클래스 이름은 다른 두가지 용도로 사용된다. 하나는 데이타 타입으로서 사용되는 것이고 하나는 오브젝트로 사용되는 것이다.
	Circle *anObject; 	anObject = [[Circle alloc] init]; 

여기서 Circle은 오브젝트의 타입 이름으로 사용되었다.
메시지 익스프레션 내에서 리시버로 사용되었을때는 클래스 오브젝트를 말한다.
	if ( [anObject isKindOf:[Circle class]] ) 			: 

이 경우 Circle은 리시버로서 클래스 오브젝트로 사용된 경우이다.
이렇게 사용할때 만일 클래스 오브젝트의 이름을 런타임에서만 알 수 있는경우 objc_lookUpClass()함수를 사용한다.
즉,
	char *aBuffer; 		: 	if ( [anObject isKindOf:objc_lookUpClass(aBuffer)] ) 		: 



2. 클래스 정의


오브젝티브 C에서 클래스는 두 파트로 나눠서 정의 된다.
하나는 interface로 클래스 이름을 정하고 슈퍼 클래스를 정해주며 메소드와 인스턴스 변수들을 선언하는데 사용된다.
다른 하나는 implementation으로 말 그대로 실제로 클래스를 구현하는 것이다.
쉽게 알 수 있듯이 interface는 .h파일에 implementation은 .m 파일에 넣어주면 될것이다.
물론 하나의 파일에 다 넣어도 되고 하나의 파일에 하나 이상의 클래스를 넣는것도 가능하지만 권하지 않는 방법이다.
흔히 파일 이름은 클래스 이름을 따라 지으며 .h와 .m파일로 구성된다.


1) interface

인터페이스는 @interface 컴파일러 지시자와 @end지시자 사이에 작성하면 된다.
@interface ClassName : ItsSuperClass { 	instance variable declarations } methods declarations @end 

첫줄은 클래스 이름과 슈퍼 클래스를 정해준다. 만일 콜론과 슈퍼클래스의 이름이 빠지게 되면 이 클래스는 루트 클래스로 만들어진다. 하지만 이렇게 사용하는것을 권하지 않는다. 무조건 NSObject를 상속 받도록 하자.
인스턴스 변수 선언은 C에서와 같은 방법으로 하면 된다.
예를 들면 아래와 같은 식으로 사용할 수 있다.
	float xPosition; 	float yPosition; 	NSColor *color; 

인스턴스 변수의 스코프를 정해주기 위해서 제공되는 지시자는 @private, @protected 그리고 @public이 제공된다.
각각은 다음과 같은 의미이다.


예를 들면 다음과 같이 사용된다.
@interface Worker : NSObject { 	char *name; @private 	int age; 	char *evaluation; @protected 	id job; 	float wage; @public 	id boss; } 

메소드는 크게 클래스 메소드와 인스턴스 메소드 두가지로 나누어지는데 클래스 메소드는 객체를 인스턴스화 시키지 않아도 클래스 오브젝트에서 사용할 수 있는 것이고 인스턴스 메소드는 반드시 인스턴스화 된 메소드에서 사용가능하다.
클래스 메소드는 앞에 +기호를 붙이며 인스턴스 메소드 앞에는 -기호가 붙는다.
아래는 두 메소드 선언의 형태 이다.
+ alloc; - (void)display; 

흔하지는 않지만 동일한 이름의 클래스 메소드와 인스턴스 메소드를 만들 수 있으며 반면 인스턴스 메소드와 인스턴스 변수를 같은 이름으로 쓰는것은 오브젝티브 C에서는 매우 흔한 일로서 accessor메소드를 구현할때 많이 보인다.
예를 들면 오브젝트에 count라는 인스턴스 변수가 있다면 count라는 인스턴스 메소드를 만들어 count의 값을 가져오는데 사용한다. int count의 accessor 메소드는 다음과 같이 많이 쓰는데, 자바 같은 언어와 달리 흔히 get...으로 시작하지 않고 바로 그 변수이름과 동일한 메소드 이름을 사용한다.
- (int)count; - (void)setCount:(int)aCount; 

또한 메소드의 이름은 보통 첫글자를 소문자로 시작하며 중간에 읽기 쉽게 대문자를 섞어 준다.
만일 메소드의 리턴 값의 형을 정확히 명시해 주지 않으면 기본적을 id를 리턴하게 되며 하나 이상의 매개변수가 있을때는 변수이름과 콜론으로 구분하고 가변 갯수의 변수를 넘길때는 콤마를 사용한다고 앞에서 이야기한 바 있다.
오브젝티브 C의 노테이션은 처음 보면 생소하고 읽기 힘들지만 상당히 재미있는 부분이며 익숙해지면 오히려 읽기 쉽게 느껴질 수도 있다. 오브젝티브 C의 메소드는 아래와 같은 구조이다.

celsius = [converter convertTemp: fahrenheit];
└─┬─┘ └─┬─┘└──┬──┘└──┬──┘
returned value receiver method name argument

range = [string rangeOfString: @"Cocoa" options: NSLiteralSearch];
└┬┘ └┬┘ └──┬──┘ └┬┘ └┬┘ └──┬──┘
returned receiver first part first second second argument
value of method name argument part of
method name

매개변수를 콜론으로 분리하고 콜론 앞에 그 매개변수에 대한 설명을 붙일 수 있게 되어있어 정확한 함수의 프로토타입을 몰라도 이해가 되는 경우가 많을 뿐만 아니라 새로운 메소드를 설계할때도 잘 생각해보면 무척 직관적인 설계가 가능하다.


2) importing the interface

클래스 인터페이스가 필요한 부분에 인터페이스를 포함시키기 위해서 #import 지시자를 이용하면 된다. 이것은 사용법이 C의 #include와 같지만 같은 파일이 두번 포함되지 않는다는것이 다르다.
그러면 아래와 같이 된다.
#import "ItsSuperClass.h" @interface ClassName : ItsSuperClass { 	instance variable declarations } methods declarations @end 

이렇게 해주면 간접적으로 모든 상속의 관계에 있는 클래스들의 인터페이스 파일들이 포함된다.


3) 다른 클래스의 참조

  1. import 지시자를 사용하면 NSObject부터 연관된 모든 인터페이스 파일들이 포함되게 된다. 만일 이 계통에 해당되지 않는 클래스를 사용하고 있다면 임포트를 해주거나 @class 지시자를 사용해야 한다.
	@class Rectangle, Circle; 

이 지시자는 단지 컴파일러에게 Rectangle과 Circle이 클래스 이름이란 것만 알려준다. 그것들의 인터페이스 파일을 임포트하는것은 아니다.
만일 어떤 클래스를 사용하는데 있어서 그 클래스의 메소드나 기타 상세한 정보가 필요치 않은 경우 @class 지시자로 충분하다. 하지만 인스턴스를 만들거나 메시지를 보낸다면 클래스 인터페이스는 반드시 임포트 되어야 한다.
만일 A라는 클래스와 B라는 클래스가 있는데 A라는 클래스에서 B라는 클래스가 스태틱 타이핑되어 인스턴스 변수로 사용되고 B라는 클래스에 A 크래스가 스태틱 타이핑되어 인스턴스 변수로 사용되면 일반적인 #import를 사용하게 되면 서로 상호 참조하게 되는 경우가 있다. 이런 경우 @class 지시자를 사용해야 한다.


4) implementation

클래스의 구현은 인터페이스와 비슷하게 @implementation 지시자와 @end 지시자 사이에서 이루어진다. 클래스의 구현파일에는 반드시 그 클래스의 인터페이스 파일이 임포트 되어야 한다.
기본적인 implementation의 구조는 아래와 같다.
#import "ClassName.h" @implementation ClassName method definitions @end 

클래스의 메소드 들은 C 처럼 { } 안에 구현된다.
+ (id)alloc { 	... } - (BOOL)isFilled { 	... } - (void)setFilled:(BOOL)flag { 	... } 

가변 갯수의 매개변수는 아래와 같이 쓸 수 있다.
#import <stdarg.h> ... - (id)getGroup:group, ... { 	va_list ap; 	va_start(ap, group); 	... } 


5) 인스턴스 변수의 사용

인스턴스 메소드에서는 단지 이름을 사용하는 것으로만으로도 객체내의 모든 인스턴스 변수를 사용할 수 있지만 다른 클래스의 인스턴스에서는 그럴 수 없다. 이런경우 스태틱 타이핑된 오브젝트에 대해서는 스트럭춰 포인터 오퍼레이터인 "->"를 사용할 수 있다.
필자는 인스턴스 변수를 이렇게 바로 사용하는것을 별로 권하고 싶지 않다. 항상 accessor 메소드를 이용하는것이 좋다고 생각한다.
인스턴스 변수의 스코프에 대해서는 앞서 설명한 부분을 참고하기 바란다.



3. 메시지의 작동 방식


오브젝티브 C에서는 컴파일할때 바인딩 되지않고 실행시간에 바인딩 된다고 이야기 했었다.
만일 다음과 같은 구문이 있다고 하자
	[receiver message] 

이 메시지 호출은 objc_msgSend()메시징 함수로 바뀌어 불린다. 이 함수는 리서버와 메시지에 나오는 메소드 이름을 중요한 두개의 매개변수로 가진다.
	objc_msgSend(receiver, selector) 

메시지에 넘어간 매개변수들 역시 이 함수를 통해서 넘어간다
	objc_msgSend(receiver, selector, arg1, arg2, ...) 

이 메시징 함수 하나로 다이나믹 바인딩이 실현된다.
이 함수는 먼저 셀렉터가 가리키는 메소드를 찾는다. 같은 메소드들이 다른 클래스에 구현 될 수 있기 때문에(폴리모피즘) 해당 클래스(클래스 오브젝트)에서 찾게 되는것이다.
그리고 나서 그 메소드를 호출하면서 리시빙 오브젝트를 넘기고 메소드에 해당하는 매개변수들도 함께 넘긴다.
그리고 그 메소드가 종료되면 리턴 값을 받아서 넘긴다.
이 메시징 함수는 컴파일러가 알아서 불러주며 개발자가 직접 다룰일은 절대 없다.
메시징의 중요한 핵심은 각 클래스와 오브젝트에 대해 컴파일러가 만든 구조속에 있다. 모든 클래스 구조는 두개의 중요한 요소를 가지고 있는데,
첫째는 슈퍼클래스에 대한 포인터이고
두번째는 클래스 dispatch table이다. 이 테이블에는 각 클래스에 해당하는 메소드들의 메소드 셀렉터의 엔트리를 가지고 있다. 이것은 특정 메소드의 해당하는 함수의 주소를 가지고 있다.
앞서 이야기한 isa는 각 인스턴스가 만들어질때 만들어지며 클래스(클래스 오브젝트)의 포인터이다. isa를 통해서 인스턴스의 클래스 오브젝트에 접근하며 또 그 안에서 super_class변수를 이용해서 슈퍼클래스들을 찾아 볼 수 있다.
이것에 대한 구조는 아래와 같이 도식화 될 수 있다.


(그림3) super_class변수를 사용한 메소드 검색

만일 객체에 메시지가 보내지면 isa를 통해서 클래스를 찾아가며 그곳의 dispatch table의 셀렉터 엔트리에서 원하는 메소드가 없으면 다시 슈퍼클래스로 가서찾는다. 이런식으로 찾을때까지 계속 거슬러 올라가면서 메소드를 찾게 되는 것이다.
이런 구조는 속도저하를 가져 올 수있기 때문에 실제 구현된 런타임 시스템은 바로 dispatch table에서 메소드를 뒤지지 않고 캐쉬를 만들어서 그곳을 먼저 뒤진다. 덕분에 큰 속도 저하는 발생하지 않는다.


1) Selectors

효율성 때문에 실제 컴파일된 코드에서는 메소드 이름이 아스키 문자열로 처리되지 않는다. 대신 컴파일러는 각 메소드들의 이름을 테이블에 넣어두고 각각의 고유한 아이디를 만든다. 이것이 실제 런타임에서 특정 메소드를 지칭하게 될 것이다. 컴파일 된 셀렉터는 SEL이라는 특별한 형으로 처리되는데 사용가능한 셀렉터는 0이 아닌 값이다.
	SEL setWidth; 	setWidth = @selector(setWidth:); 

만일 스트링을 셀렉터로 런타임시 바꿀 필요가 있다면 sel_getUid()함수를 사용한다
	setWidth = sel_getUid(aBuffer); 

반대로 셀렉터에서 메소드 이름을 알아낼 수도 있다
	char *methodName; 	methodName = sel_getName(setWidth); 

컴파일된 셀렉터는 메소드의 이름에 대한 것이지 메소드의 구현에 대한 것은 아니다. 즉 같은 이름의 메소드가 다른 클래스에 존재하고 있다면 같은 셀렉터를 가질 것이다. 이것은 폴로모피즘과 다이나믹 바인딩에서 중요한 부분이다. 같은 셀렉터라도 받는 리시버에 따라서 다르게 해석되는 것이다.


2) self, super

오브젝티브 C에서는 메소드 안에서 오브젝트를 참조하기 위해 사용할 수 있는 두개의 어구를 제공한다. 그것은 self와 super로 self는 오브젝트 자신을 super는 슈퍼클래스를 지칭한다.
예를 들어서 오브젝트 자신에게 메시지를 보내기 위해서 self를 사용한다.
	[self setValue:10.0]; 

그리고 슈퍼클래스에 메시지를 보내기 위해서 super를 사용한다. 이것은 init메소드를 구현할때 자주 보인다.
	- (id)initWithFrame:(NSRect)frameRect 	{ 	 self = [super initWithFrame:frameRect]; 	 if ( self ) { 		... 	 } 	 return self; 	} 

이 메소드는 먼저 슈퍼클래스를 초기화 하고 그것을 self에 받아두고 슈퍼클래스의 init이 정상적으로 작동되었으면, 즉 self가 nil이 아니면 자신을 초기화한다.
self에 메시지가 전달되면 일반적인 경우와 같이 먼저 자신의 클래스 오브젝트에서 메소드를 찾는 작업을 하지만 super에 메시지가 전달되면 자신의 클래스 오브젝트가 아닌 슈퍼클래스의 클래스 오브젝트에서 그 메소드를 찾기 시작한다. super는 단지 컴파일러에게 메소드를 찾기 시작하는 위치를 알려줄 뿐이다.
반대로 self는 다양한 방법으로 사용되어 질 수있는 변수로 새로운 값을 넣을 수도 있다.
클래스 메소드를 부르는 메시지는 클래스 오브젝트에서는 작동하지만 종종 인스턴스에서는 작동하지 않는다.
	+ (id)newRectOfColor:(NSColor *)aColor 	{ 		self = [[self alloc] init]; 		[self setPrimaryColor:aColor]; 		return self; 	} 

이 메소드는 클래스 메소드이기 때문에 기본적으로 self는 클래스 오브젝트를 가리킨다. 즉 alloc 메시지를 받는것은 클래스 오브젝트이다. 그런데 self는 alloc 메시지를 받아서 인스턴스화되고 init으로 최기화된 뒤 인스턴스로 재정의된다.
그래서 그 새로운 인스턴스가 setPrimaryColor 메시지를 받게 되는것이다.
작동은 하겠지만 위의 코드는 아주 좋지 않은 코드이다. 혼동을 피하기 위해서 위의 코드는 아래와 같이 쓰는것이 좋다.
	+ (id)newRectOfColor:(NSColor *)aColor 	{ 		id newInstance = [[self alloc] init]; 		[newInstance setPrimaryColor:aColor]; 		return newInstance; 	} 

이 예에서 클래스 메소드에서 인스턴스를 초기화 하기 위한 메시지를 보낸다. 하지만 값을 세팅하기 위해 인스턴스 메소드에서 처럼 인스턴스 변수에 바로 값을 쓸 수는 없다. 이것은 클래스 메소드의 리시버(이게 클래스 오브젝트이다.)가 인스턴스 변수를 가지지 않기 때문이다. 만일 newInstance변수가 스태틱 타이핑되었다면 아래와 같이 값을 넣을 수 있을것이다.
	 newInstance->value = aValue; 



일단 오브젝티브 C의 가장 기본적인 부분들에 대해서 살펴보았다. 이것이 오브젝티브 C언어의 모든것은 아니다. 다음달에는 카테고리와 프로토콜에 대해서 알아볼 것이며 런타임 시스템에 대해서도 조금 더 보충을 할 내용이 있다. 내용이 좀 복잡할지도 모르겠다. 하지만 C언어만 익숙하다면 현재까지의 내용을 잘 들여다 본다면 오브젝티브 C언어가 어떻게 구성되어져 있는지 그 속사정까지 잘 알 수 있을것이라고 생각한다.
만일 오브젝티브 C에 대해서 더 궁금하고 내부를 더 파고 들어가고 싶다면 소스가 공개된 GNUstep을 참고하는것도 좋을것이다. 물론 연재의 중심이 되는 Mac OS X에서의 오브젝티브 C/코코아가 GNU의 오브젝티브 C/GNUstep과 조금은 다른 점이 있기는 하다. 그렇지만 기본적인 맥락에서는 같은것이기 때문에 충분히 도움이 되리라고 생각한다.

[출처] Objective-C 기초|작성자 semigifn



출처 : http://blog.naver.com/PostView.nhn?blogId=mewizard&logNo=20065869285
Posted by 오늘마감

댓글을 달아 주세요