처음부터 다시 시작하는 마음으로 정리를 한다.
이 글은 '아이폰 프로그래밍 가이드(프리랙)', 'Head First iPhone Development(한빛 미디어)'를 주로 참조했고
모르는 부분은 검색을 통해 보충하였으나 편집하면서 출처는 하단 부 참조사이트에 일괄적으로 적어두었다.
그리고 반복해서 나오는 것이 있는데 몰라서가 아니라 중요한 부분이라 계속 읽어볼 수 있게 일부러 합치지 않았다
그냥 한번씩 쭉 읽어보아도 도움이 될 것이다.
암튼 모르면 검색해서 찾아보자!
- 오브젝트 C 란?
* 기존 C에 최소한의 확장으로 객체 지향 프로그래밍을 추가
* Smalltalk 스타일메시징 메커니즘을 추가 (하지만 많은 영향은 받지 않았다)
* Model View Controller(MVC) 모델을 사용한다
- 데이터핵심처리(Mode) , 직접적인 인터페이스(View), 사용자 및 데이터 흐름 처리(Controller)를
각각 분리하여 서로간의 간섭을 최소하 하여 개발/유지/보수의 편리성을 높은것
* Dynamic Runtime을 제공한다.
* 표준 C를 오브젝트 C 코드와 결합할 수 있다.
* 심지어 C++도 결합할 수 있다.
* 가비지 컬렉션을 자체 지원한다.
* 문법은단순하지만 강력한 기법이다.
* 새롭게 추가된 문법도 있다.
- 클래스와 인스턴스
* Object-C에서 클래스와 그 클래스로부터 나온 인스턴스들 모두 객제(Object)이다.
* 클래스는 인스턴스를 생성하기 위한 청사진이다.
클래스는 우리가 이용하고자 하는 객체의 특징을 정의해 놓은 것.
클래스 : 데이터와 함수의 정의.
인트턴스 : 클래스를 이용해 생성되는 객체.
* 클래스는 State와 Behavior를 선언한다.
* State(Date)는 인스턴스 변수들을 통해서 관리된다.
* Behavior는 함수를 통해 구현된다.
* 인스턴스 변수들은 일반적으로 숨겨져 있다.
getter/setter methods를 통해서만 접근 가능. - xcode에서 '@synthesize로 컴파일러가 자동으로 만들어 줌
- 문법
* Objective-C는 C 위에 올라가는 아주 얇은 레이어이며, 엄격한(Strict) C 상위집합(superset)이다.
* 어떤 C 프로그램도 Objective-C 컴파일러로 컴파일 할 수 있다.
* Objective-C의 문법은 Smalltalk와 C의 문법을 계승하고 있다.
* 메소드를 호출하지 않으며 메시지를 보낸다(중요)
메시지의 수신자는 그 메시지를 거부 할 수 있다.
// 메시지는 반드시 실행될 필요는 없는데, 동적으로 바인딩되기 때문이다.
메시지를 받은 객체가 그 메시지를 구현한 경우, 해당 메시지는 실행될 것이지만, 그렇지 않은 경우에는
실행되지 않을 것이다.
그렇다 하더라도 코드는 문제없이 컴파일되고 실행된다.
이 메커니즘은 정의된 객체에 메시지가 실행 시간에 전달되도록 한다.(Dynamic Runtime)
메시지는 메시지를 구현한 객체에 보내질 수도 있으며, 그 객체가 상속한 상위 클래스에 보내질 수 있다.
(self, super라는 객체 포인터 지원)
메시지는 nil 객체에도 전달 될 수 있다.
- 인터페이스와 구현
* Objective-C는 인터페이스와 클래스 구현이 별도로 선언된 코드 블록에 놓이도록 한다.
인터페이스 - 헤더파일 .h
코드(함수) - 구현파일 .m
- 인터페이스
* 클래스의 인터페이스는 보통 헤더파일 안에 정의된다.
* 통상적으로 클래스의 이름과 헤더파일의 이름을 같게 둔다.
인터페이스 선언 예시
@interface classname : superclassname { // instance variables } +classMethod1; +(return_type)classMethod2; +(return_type)classMethod3:(param1_type)parameter_varName; -(return_type)instanceMethod1:(param1_type)param1_varName :(param2_type)param2_varName; -(return_type)instanceMethod2WithParameter:(param1_type)param1_varName
andOtherParameter:(param2_type)param2_varName; @end
+ 기호 : 클레스 메소드
- 기호 : 인스턴스 메소드
클래스 메소드(+)는 인스턴스 변수에 접근할 수 없다.
반환값 타입으로는 표준 C 타입, Objective-C 객체에 대한 포인터, 그리고 특별한 종류의 객체에 대한 포인터
(NSArray*, NSImage*, NSString* 등)을 사용할 수 있다. 내정(default) 반환값 타입은 Objective-C 타입인
id(객체타입의 모든 인자를 받을 수 있다)이다.
* 메소드의 인자는 콜론(:) 기호 뒤에 인자 타입과 그 이름을 두는 식으로 명시
* 타입 이름에는 괄호를 두른다.
* 어떤 경우에는(system API를 작성한다거나 하는 경우) 각 인자 이름 앞에 그 의미를 설명하는(descriptive)
텍스트를 넣어 두기도 한다.
-(void) setRange:(int)start :(int)end;
-(void) importDocumentWithName:(NSString *)name
withSpecifiedPreferences:(Preferences *)prefs
beforePage:(int)insertPage;
- 구현
* 인터페이스(헤더파일)는 클래스의 인터페이스만을 선언하며, 메소드가 어떻게 구현될지는 명시하지 않는다.
* 실제코드는 implementation(구현파일) 안에 들어간다. (.m 파일)
@implementation classname
+classMethod {
// implementation
}
-instanceMethod {
// implementation
}
@end
* 메소드는 인터페이스에 선언된 대로 구현된다.
-(int)method:(int)i {
return [self square_root: i];
}
* Objective-C는 문법적으로 인자에 대한 pseudo-naming(가짜이름)을 지원한다.
-(int)changeColorToRed:(float)red green:(float)green blue:(float)blue
[myColor changeColorToRed:5.0 green:2.0 blue:6.0];
이 메소드의 실제 표현은 Objective-C 구현체에 따라 달라질 수 있다.
myColor가 클래스 Color에 의해 만들어진 것이라면, 인스턴스 메소드 -changeColorWithRed:green:blue 는
내부적으로 _i_Color_changeColorWithRed_green_blue와 같은 이름을 갖게 될수 있다.
i는 인스턴스 메소드임을 표시하기 위한 것이고,
그 뒤에 클래스 이름(Color)과 메소드 이름(changeColorWithRed)를 두었다.
콜론(:)은 전부 _ 기호로 변환되었다.
이 이름을 보면, 인자가 전달되는 순서 또한 메소드 이름의 일부분 임을 알 수 있다.
메소드에 전달되는 실 인자의 순서를 바꿀 수는 없는 것이다.
pseudo-naming이라고 한 것은 그래서 이다.
하지만 이러한 내부 표현명을 직접적으로 사용할 경우는 거의 없다.
일반적으로 메시지는 Objective-C 런타임 라이브러리에 정의된 함수에 대한 호출로 변환된다.
그러니 링킹 시점에 어떤 메시지가 어떤 메소드를 호출하게 되는지 알 필요는 없다.
실행 시간까지는 메시지의 리시버 클래스를 알 필요가 없다는 것.
# 링킹
컴파일의 한 작업
소스코드를 작성하고 컴파일을 하게 되면, 각각의 기능에 따라서 목적코드라고 하는 것에 담고 있는
목적파일이 생성된다.
이러한 목적파일들을 실행 가능한 형태로 만들기 위해, 여러개의 목적파일들을 하나로 연결해주는 작업이
필요한데 이것을 링크, 또는 링킹이라고 한다.
C언어 기준
1.원본문서 작성(소스코드작성) --> 문서.c라는 파일 생성
2.컴파일 --> 문서.obj 파일 생성
3. 링크(링킹) --> 문서.exe 파일 생성
- 객체 생성
* Objective-C 클래스가 작성되고 나면, 그 클래스로 객체를 만들 수 있다.
* 과정 : 새로운 객체에 대한 메모리를 잡고, 그 메모리를 초기화 한다.
이 두 과정이 완전히 끝나기 전에는 객체는 완전하게 기능하지 못한다.
객체 생성 코드
MyObject * o = [[MyObject alloc] init];
alloc 호출은 객체의 인스턴스 변수들을 담기에 충분한 양의 메모리를 잡는다.
init 호출은 그 변수들의 값을 특정한 값으로 초기화 한다.
init 메소드 예시
-(id) init { self = [super init]; if (self) { ivar1 = value1; ivar2 = value2; . . . } return self; }
- 객체 메시지 전달
* 객체에 명령을 주려면 메시지를 보낸다.
* 메시지는 대괄호 '[]'를 사용하여 표현한다.
형식
[receiver message:arg1 andArg:arg2]
receiver : 객체(수신자)
변수 또는 객체를 가르키는 표현 (self : 자신(변수), super : 부모(객체-인스턴스) 변수 포함)
클래스의 이름도 객체가 될 수 있다.
message : 명령 - 메서드의 이름
arg1 : 매서드에 필요한 인자
인자들은 ':' 을 이용하여 넘긴다.
여러개의 인자를 넘기때는 그 인자를 대표하는 키워드도 함께 써줘야 한다.
ex)
함수선언
-(void)setOriginX:(NSFloat)originx y:(NSFloat)originy;
함수사용
[myRect setOriginX:20.0 y:30.0];
myRect이란 객체에 setOriginX라는 함수를 호출하며 20.0이란 인자와 y값에 30.0이란 인자를 넘긴다.
* 중첩된 표현(Nested Expression)
메시지 표현 안에 또다른 메시지를 부르는 형태
[myRect setPrimaryColor:[otherRect primaryColor]];
myRect이란 객체의 setPrimaryColor라는 함수를 호출하며 인자값으로 otherRect이란 객체의 primaryColor를 넘긴다.
* 점(.)구문(도트연산자)를 사용한다. (Objective-C 2.0이상)
[[person child] setHeight: newHeight]; = person.child.height = newHeight;
점구문은 읽기전용(read-only) 속성에 쓰려고 할 때, 컴파일러가 감지하고 에러를 발생시킨다.
C 언어에서 사용하는 복합지정(+= , -= , *=. /=)을 사용할 수 있다.
- 프로토콜
* Objective-C 는 나중에 NeXT에 의해 확장되어 다중 상속의 개념을 스펙에 포함 -프로토콜
* 다중 상속은 C++에서처럼 여러 개의 상위 클래스를 상속받는 형태로 제공되기도 하고,
Java나 C#에서처럼 '인터페이스'를 계승하는 형태로 지원되기도 한다. (인터페이스 계승을 더 많이 쓴다)
* Objective-C는 비정형 프로토콜(informal protocol)이라고 불리는 ad-hoc 프로토콜과, 정형 프로토콜이라고
불리는 컴파일러가 강제하는 프로토콜을 통해 다중 상속을 지원한다.
===============================================================================================
//Formal protocol 정형 프로토콜
* 포멀 프로토콜은 상속된 클래스에서 반드시 구현되어야만 하는 메소드들이다.
* 주어진 서비스를 위해 필요한 모든 것을 다룰 수 있는지를 확인하는 클래스에 따른 검증으로 보여질 수 있다.
* 클래스는 무제한 갯수의 프로토콜을 적용할 수 있다.
* Objective-C에서 프로토콜은 특수한 개념이다.
* 각진 괄호 <...> 로 표시
예시
@protocol MouseListener
-(BOOL) mousePressed;
-(BOOL) mouseClicked;
@end
@protocol keyboardListener
-(BOOL) keyPressed;
@end
@interface Foo : NSObject <MouseListener, KeyboardListener> { //프로토콜의 상속
.............
}
@end
* 클래스는 그 적용의 선언 없이도 모든 프로토콜의 메소드를 구현할 수 있다.
* 포멀 프로토콜을 따르는 개체 타입은 프로토콜 그 자체의 이름이 각진 괄호 사이에 추가될 수 있다.
-(NSDragOperation) draggingEntered:(id <NSDraggingInfo>)sender;
@protocol Locking - (void)lock; - (void)unlock; @end
락을 걸고 푼다는 추상화된 프로토콜이 존재한다는 사실을 명시하고 있다. 클래스를 정의할때는 다음과 같이 쓴다.
@interface SomeClass : SomeSuperClass <Locking>
@end
SomeClass에 의해 만들어진 객체들은 Locking 프로토콜에 명시된 두개의 인스턴스 메소드의 구현을 제공할것임을 명시하고 있다.일례로 이런 추상화된 명세법은 구현계층(hierachy)이 어떻게 만들어져야 하는지를 지정하지 않더라도플러그인에 요구되는 행위 형태를 기술할 수 있어서 특히 효과적이다.- 동적타입(dynamic typing)* Smalltalk에서와 마찮가지로 Objective-C에서는 동적 타입을 사용할 수 있다.* 객체는 그 인터페이스에 명시되지 않은 메시지를 수신할 수 있다.* 그 결과 유연성이 향상되는데, 해당 메시지를 '캡쳐'한 후 또다른 객체에 그 메시지를 보내버릴 수도 있는 것이다.(메시지 수신객체는 그 메시지에 올바르게 응답할수도, 또다른 객체에 메시지를 다시 전송해 버릴수도 있다.)* 이런 형태의 행위 패턴을 흔히 메시지 전달(message forwarding) 혹은 위임(delegate)라고 한다.* 메시지를 포워드 할 수 없을 경우에는 오류 핸들러(error handler)를 통해 처리할 수도 있다.객체가 메시지를 포워드하지도 않고, 오류 처리를 하지도 않고, 응답하지도 않는 경우에는 런타임 오류가 발생.* 선택적으로 변수에 정적으로 타입 정보를 부가할 수도 있다. - 이 정보는 컴파일 시에 검사된다.- setMyValue:(id) foo; - setMyValue:(id <aProtocol>) foo; - setMyValue:(NSNumber*)foo;위 소스에서 아래쪽으로 갈수록, 더 많은 정적 타입 정보가 부가되어 있다.실행시간에 이들 문장들은 전부 동일하다.하지만 부가 정보는 컴파일러로 하여금 전달한 인자의 타입이 맞지 않을 경우 경고를 내 보내줄 수 있도록 한다.첫번째 문장의 경우 객체는 어떤 타입이라도 될 수 있다.두번째 문장의 경우 객체는 반드시 aProtocol 프로토콜을 준수해야한다.세번째 문장의 경우 해당 객체는 반드시 NSNumber 클래스의 멤버이어야 한다.- 전달 (Forwarding)* Objective-C가 아무 객체에나 메시지를 보낼 수 있도록 허용하고 있기 때문에, 객체가 메시지를받았을 경우 할 수 있는 일도 다양하다. 그 중 하나는 메시지를 다른 객체로 전달하는 것이다.이것을 사용하여 옵저버 패턴이나 프록시 패턴 같은 디자인 패턴을 간단히 구현할 수 있다.===============================//Observer(관측자) Pattern 옵저버 패턴뭔가 중요한 일이 일어났을 때 객체들한테 새 소식을 알려줄 수 있는 패턴이다.객체 쪽에서는 계속해서 정보를 받을지 여부를 실행 중에 결정할 수 있다.- Observer Pattern의 정의Observer Pattern이란 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들한테 연락이 가고 자동으로내용이 갱신되는 방식으로일대다(one-to-many) 의존성을 정의한다.- Observer Pattern의 특징옵저버 패턴에서는 주제와 옵저버에 의해 일대다 관계를 정의된다.옵저버는 주제객체에 의존하기 때문에 주제객체의 상태가 바뀌면 주제객체에 의존하는모든 옵저버 객체에게 연락이 간다.연락 방법에 따라 옵저버에 있는 값이 새로운 값으로 갱신될 수 도 있다.Observer Pattern 을 구현하는 방법에는 여러가지가 있지만, 대부분 주제(subject) 인터페이스와 옵저버(observer)인터페이스가 들어있는 클래스 디자인을 바탕으로 한다.- Observer Pattern 의 클래스 다이어 그램주제 (subject) : 데이터가 바뀌면 새로운 데이터 값을 옵저버들에게 보내 주는 객체옵저버 (observer) : 주제의 데이터가 변경되면 갱신내용을 받는 객체- Observer Pattern의 구성1. 주제를 나타내는 subject 인터페이스 객체에서 옵저버로 등록하거나 옵저버 목록에서 탈퇴하고 싶을 때는이 인터페이스에 있는 메소드를 사용한다.2. 옵저버가 될 가능성이 있는 객체에서는 반드시 observer 인터페이스를 구현해야 한다.이 인터페이스에는 주제의 상태가 바뀌었을 때 호출되는 메소드가 있다.3. 주제 역할을 하는 구상 클래스에서는 항상 subject 인터페이스를 구현해야 한다.주제 클래스에서는 등록 및 해지를 위한 메소드 외에 상태가 바뀔 때마다 모든 옵저버들에게 연락하기 위한메소드를 구현해야 한다.4. Observer 인터페이스만 구현한다면 무엇이든 옵저버 클래스가 될수 있다.각 옵저버는 특정 주제 객체에 등록을 해서 연락을 받을 수 있다.- Observer Pattern에서 느슨한 결합(Loose Coupling)의 위력옵저버 패턴에서는 주제와 옵저버가 느슨하게 결합되어 있는 개체 디자인을 제공한다.두 객체가 느슨하게 결합되어 있다는 것은 그 둘이 상호작용을 하긴 하지만 서로에 대해 잘 모른다는 것을 의미한다.주제가 옵저버에 대해서 아는 것은 옵저버가 특정 인터페이스를 구현 한다는 것 뿐이며, 옵저버는 언제든지 새로추가하거나 제거할 수 있다.새로운 형식의 옵저버를 추가하려고 할 때도 주제를 전혀 변경할 필요가 없으며, 주제와 옵저버는 서로 독립적으로재사용할 수 있다.주제나 옵저버가 바뀌더라도 서로한테 영향을 미치지는 않는다.이런 관계를 느슨한 결합이라고 하며 느슨하게 결합하는 디자인을 사용하면 변경 사항이 생겨도 무난히 처리할 수 있는유연한 객체 지향 시스템을 구축할 수 있다.객체 사이의 상호의존성을 최소화 할 수 있기 때문이다.- 주제가 옵저버한테 상태 정보를 전달하는 두가지 방식주제가 옵저버한테 상태 정보를 전달하는 방식에는 두 가지가 있다.주제객체에서 데이터를 보내는 방식인 푸시방식과 옵저버가 데이터를 가져오는 방식은 풀 방식이 있다.두 가지 방식 중에는 풀 방식을 더 좋은 것으로 간주한다.// Proxy Pattern 프록시 패턴* 프록시는 다른 객체를 대신해 존재하며 특정 객체로 접근할 수 있는 대리자 역할을 한다.* 프록시는 매우 다양한 형태의 클래스가 있지만 원격(remote) 프록시와 가상(virtual) 프록시가 가장 널리 사용된다.* 프록시 패턴은 어댑터(adapter) 패턴과 퍼사드(facade) 패턴과 혼동되기도 한다.이들 패턴과 가장 중요한 차이점은 프록시 패턴이 특정 객체와 정확히 같은 API나 인터페이스를 가지고 해당 객체를 대신해존재하는 반면 퍼사드와 어댑터는 해당 객체의 API를 수정한다는 점이다.- virtual Proxy 가상 프록시* 가상 프록시는 생성하는 비용이 많이 들거나 당장 사용할 수 없는 프록시 객체에 이용된다.* 실제 객체가 생성되기 전과 생성되는 동안에는 가상 프로시가 실제 객체를 대신한다.* 생성이 완료된 후에 프록시 객체는 요청을 실제 객체에 위임한다.보편적인 가상 프록시 패턴의 예 : 이미지 로더이미지 로더는 외부 이미지가 로딩되는 동안 해당 이미지를 대신하는 객체이다.플래시플레이어 9에는 이미지 객체에 대한 프록시 역할을 하는 Loader 클래스가 있다.Loader 클래스가 로드되는 이미지를 대신해 존재하긴 하지만 이것이 순수한 형태의 가상 프록시는아니라는 점을 유의해야 한다.Loader 클래스가 실제로 이미지에 대한 수정을 가하는 프록시가 아니라 Loader 객체 자신을 수정하기 때문이다.XMLProductProxy 클래스는 게으른 직렬화를 위해서 Product 클래스를 대신해 존재한다.프록시 객체(XMLProductProxy 클래스의 객체)는 Product 클래스의 모든 메서드를 상속받기 위해서합성(Composition)을 이용한다. (Product 클래스를 composition으로 둔다)게으른 직렬화는 애플리케이션에서 미리 일어나는 직렬화의 양을 줄이고 사용되지 않을 수 있는항목(item)에 대한 직렬화를 제거함으로써 애플리케이션을 좀 더 부드럽게 동작하게 한다.=====================================Objective-C 런타임은 Object 클래스에 몇 가지 메소드들을 정의해 놓고 있다.전달 메소드들 :- (retval_t) forward:(SEL) sel :(arglist_t) args; // with GCC - (id) forward:(SEL) sel :(marg_list) args; // with NeXT/Apple systems액션 메소드들 :- (retval_t) performv:(SEL) sel :(arglist_t) args; // with GCC - (id) performv:(SEL) sel :(marg_list) args; // with NeXT/Apple systems메시지를 전달하고 싶은 객체는 전달 메소드를 오버라이드(한 클래스에서 같은 이름의 메소드를 한 개 이상 사용해야 할 경우 리턴 타입 또는 파라메터의 수를 다르게 하여 사용할 수 있게 정의) 하여 구현하면된다.액션 메소드 peformv: 는 오버라이드 할 필요 없는데, 이 메소드는 단순히 셀렉터(selector)와 인자를 가지고 메소드를실행하는 역할만 하기 때문이다.예제다음은 전달(forwarding)의 기본기를 보여주는 예제 프로그램이다.Forwarder.h#import <objc/Object.h>@interface Forwarder : Object{id recipient; // The object we want to forward the message to.}//Accessor methods- (id) recipient;- (id) setRecipient:(id) _recipient;@endForwarder.m#import "Forwarder.h"@implementation Forwarder- (retval_t) frward : (SEL) sel : (arglist_t) args{/** Check whether the recipient(수신자) actually(실제로,사실은) responds to the message.* This may or may not be desirable(한 것), for example, if a recipient* in turn does not respond to the message, it might do forwarding* itself.*/if([recipient respondsTo:sel])return [recipient performv: sel : args];elsereturn [self error : "Recipient does not respond"];}- (id) setRecipient : (id) _recipient{recipient = _recipient;return self;}- (id) recipient{return recipient;}@endRecipient.h#import <objc/Object.h>// A simple Recipient object.@interface Recipient : Object- (id) hello;@endRecipient.m#import "Recipient.h"@implementation Recipient- (id) hello{printf("Recipient says hello! \n");return self;}@endmain.m#import "Forwarder.h"#import "Recipient.h"intmain(void){Forwarder *forwarder = [Forwarder new];Recipient *recipient = [Recipient new];[forwarder setRecipient:recipient]; //Set the recipient./** Observe(관찰하다) forwarder does not respond to a hello message! It will* be forwarder. All unrecognized(인식/승인되지 않은) methods will be forwarded to* the recipient* (if the recipient responds to them, as written in the Forwarder)*/[forwarder hello];return : 0;}이 프로그램을 컴파일 하면 컴파일러가 다음과 같은 메시지를 보여줄 것이다.$ gcc -x objective-c-Wno-import Forwarder.m Recipient.m main.m =lobjcmain.m:In function 'main':main.m:12:warning:'Forwarder' does not respond to 'hello'$Forwarder 가 hello 메시지에 응답하지 않는다는 경고 메시지이다.어떤 환경에서는 저런 경고 메시지를 통해 좀 더 쉽게 오류를 찾아 낼 수 있다.하지만 지금 이 환경에서는 이 경고 메시지는 무시해도 좋다.전달 기능을 구현했기 때문이다.그러니 프로그램을 실행해 보면 다음과 같은 메시지를 보게 될 것이다.$ ./a.outRecipient says hello!
- Objective-C 유형과 타입
유형 |
정의 |
id |
객체 (포인터) - 어떤 종류의 객체 또는 인스턴스를 유형 짓기 위해 사용될 수 있다. - 클래스의 인스턴스를 정적으로 유형짓기 위해 클래스 이름을 타입 이름으로 사용할 수 있다. - 정적으로 유형 지어진 인스턴스는 해당 클래스나 상위 클래스의 인스턴스 포인터로 선언된다. |
Class |
클래스 객체 |
SEL |
매서드 이름을 식별하는 컴파일러 할당코드 |
IMP |
id를 돌려보내는 메서드 구현 포인터 |
BOOL |
Boolean 값 |
* nil : null 객체 포인터
Nil : null 클래스 포인터
클래스변수나 객체에 모두 nil, Nil을 사용할 수 있다.
- 컴파일러 지시문
* 컴파일러 지시문은 @로 시작한다.
지시문 |
정의 |
@interface |
클래스 또는 카테고리 인터페이스의 선언시작 - 헤더파일(.h)에 선언 |
@implementation |
클래스 또는 카테고리의 정의 시작 - 구현파일(.m)에 선언 |
@protocol |
정형 프로토콜의 선언시작 |
@end |
클래스, 카테고리 또는 프로토콜의 선언/정의 종료 |
@private |
인스턴스 변수 범위를 이를 선언한 클래스로 한정 |
@protected |
인스턴스 변수 범위를 클래스 선언 및 상속으로 한정 |
@public |
인스턴스 변수 범위의 한정 해제 |
@class |
다른 곳에서 정의된 클래스 이름을 선언 |
@selector(method) |
method를 식별하는 컴파일러 셀렉터를 반환 |
@protocol(name) |
프로토콜 클래스의 인스턴스를 반환 |
@encode(spec) |
spec 의 유형 구조를 인코딩하는 문자열을 산출 |
@defs(classname) |
classname 인스턴스의 내부 자료 구조를 산출 |
기본 문법
- 객체 선언
* 객체는 정적 또는 동적으로 선언할 수 있다.
* 정적 유형 객체는 클래스 포인터로 선언된다.
//포인터
int *a;
int b;
이렇게 선언을 했다고 할때,
* 는 * 뒤의 변수의 주소가 가리키는 값을 의미한다.
a=&b;
여기서 & 는 주소를 의미한다.
즉, 이것은 a라는 포인터 변수가 b라는 변수의 주소를 가리키고 있다는 것이다.
a라는 변수로 b의 값을 변동 시킬 수 있다는 뜻.
즉 포인터란 이와 같이 변수의 주소를 가지고 가는 것임.
* 정적 유형은 컴파일 시의 유형 검사(변수의 유형과 표현식이 호환되는지 여부를 확인 하는 것.)
더 잘하도록 하며 코드를 더욱 쉽게 이해할 수 있도록 한다.
* 동적 유형 객체는 id 로 선언된다.
id anObject;
동적 유형 객체의 클래스는 런타임 때 결정된다.
그러므로 클래스에 관한 지식이 없어도 코드에서 객체를 참조할 수 있다는 장점이 있다.
인스턴스 메서드 선언은 마이너스 표시(-) 로 시작한다. (플러스표시(+)는 클래스 매소드)
-(NSArray*)modifyArray;
메서드가 반환하는 값의 유형은 메서드 선언(- or +)과 메서드 이름 사이에 괄호로 묶어 표시한다.
반환값이 없는 메서드는 void 의 반환타입을 가진다.
-(id)initWithName:(NSString*)name_type:(int)type;
메서드 인수는 메서드 이름 뒤에 콜론(:)을 붙이고 표시한다.
인수의 유형은 괄호로 묶고 인수의 키워드와 인수 사이에 배치한다.
모든 선언은 ; 으로 마무리 한다.
- 클래스 정의
대부분 객체 지향 프로그램은 새로운 객체를 만들기 위해 클래스를 정의하는 데서부터 시작한다.
Objective-C에서는 클래스를 크게 두 부분으로 나누어 정의한다.
1. 인터페이스(interface) : 클래스의 메서드와 인스턴스 변수를 선언하고, 필요하다면 클래스의 슈퍼클래스를 정의한다.
C++에서의 헤더파일에 해당하는 부분이라 생각하면 된다. (xcode 에서는 .h 파일)
//슈퍼클래스
쉽게 생각해서 수학용어로 상위집합을 뜻하는 Superset과 하위집합을 뜻하는 Subset을 생각하면 된다.
예를 들어
P클래스에는 methodC 라는 메소드와 methodP라는 메소드가 존재하고
Q클래스에는 methodC 라는 메소드와 methodQ라는 메소드가 존재한다고 가정하면,
공통하는 기능 methodC와 각각의 기능 methodP, methodQ를 전부 포함하는 영역을 상위집합,
각각의 기능 methodP, methodQ만을 포함하는 영역을 하위집합을 보는 포함관계가 성립한다.
이때, 기능의 포함관계상
공통기능을 포함하는 클래스를 상위집합을 의미하는 슈퍼셋에서 유래한 슈퍼클래스(Super-Class),
고유기능을 포함하는 클래스를 하위집합을 의미하는 서브셋에서 유래한 서브클래스(Sub-Class)라고 한다.
이러한 사고방식은 계승 (Extend)의 개념에도 적용되어
공통 기능을 계승하는 클래스가 슈퍼클래스, 공통기능을 계승받는 클래스가 서브클래스가 된다.
참고로 오브젝트지향의 관점에서 "공통성이 있는 복수의 개체를 묶어 하나의 상위개체를 형성하는 과정"을
"일반화 ( Generalization)" 이라고 부른다.
2. 구현 (Implementation) : 실제로 클래스를 구현하는 부분이다. 여기서 인터페이스에서 선언한 함수들의
실제 동작을 구현하게 된다.
C++에서의 c파일에 해당하는 부분이라 생각하면 된다. (xcode 에서는 .m 파일)
클래스 정의에서 기억해야 할 규정과 요점사항
* 클래스의 인터페이스는 '클래스이름.h' 파일에 선언된다.
이 헤더 파일은 해당 클래스를 사용하고자 하는 부분에서 임포트(Import) 될 수 있다.
* 클래스를 구현하는 코드는 '클래스이름.m' 파일에 저장된다.
이 코드는 프레임웤, 동적 공유 라이브러리, 정적 라이브러리 또는 구현 파일의 형태로
클래스를 내장한 프로그램이 컴파일 될 때 사용된다.
* 메서드의 선언이나 구현은 '-' 또는 '+' 표시로 시작한다.
'-' 표시는 해당 메서드가 클래스의 인스턴스에서 사용된다는 것.
'+' 표시는 해당 메서드가 클래스 객체에서 사용된다는 것.
* 메서드 구현 시, 그 메서드가 정의된 클래스에 속한 객체에 한하여,
그 객체의 인스턴스 변수를 직접 참조할 수 있다.
변수에 접근하거나 객체의 자료 구조를 넘겨주기 위한 추가 문법은 필요하지 않고 모든 것이 숨겨진 채로 존재한다.
* 메서드는 수신객체를 'self(자신)' 로 지칭 할 수 있고 이 변수는 객체가 자신의 메서드 정의 내에서
객체 자신에게 메시지를 보낼 수 있게끔 해준다.
Objective-C를 작성할때는 보통 인터페이스 파일과 구현파일을 분리해서 작성한다.
(컴파일러는 이 두 개의 파일이 나뉘건 나뉘지 않건 상관하지 않는다.)
또한 개발의 편의를 위해 한 인터페이스 파일에는 하나의 클래스만을 정의하는 것이 좋다.
>> 너무 길어졌네... 보기 힘들겠다 다음편으로 계속 미남~~!!
- 참고 사이트.
http://en.wikipedia.org/wiki/Objective-C
http://blog.naver.com/jedikim72?Redirect=Log&logNo=10041604586
http://blog.naver.com/citrulline?Redirect=Log&logNo=60063102459 - 옵저버 패턴
http://blog.naver.com/cuckoo03?Redirect=Log&logNo=120108897140 - 프록시 패턴
'개발 > Objective-C' 카테고리의 다른 글
object - c Initialization (0) | 2010.09.01 |
---|---|
#pragma (0) | 2010.09.01 |
기초부터 다시 시작 - 반(2) Objective - c (0) | 2010.09.01 |
* <- 이넘의 정체 (0) | 2010.08.31 |
[Objective-C] Convert NSString to char * (0) | 2010.08.29 |