본문 바로가기

스터디/20101111

Objecitve-C





도대체 몇번을 다시 시작하는 건지..
직장인이라는 미명아래 
짬짬이 공부를 하다보니 개념정리가 많이 부족하다 
그저 외워 사용하는 것일 뿐..

얼마전 내 맥돌이의 OS를 날려 다시 까는 불상사가 발생했다..
백업이나 타임머신을 사용하지 않아 
가지고 있던 데이터를 전부 날려버렸다..ㅠㅠ

젤 아쉬웠던 건 그동안 코딩한 소스들...ㅠㅠ
다시 해볼려 하니 
공백기간으로 인해 어리버리한 내 모습에 충격을 받고 
또 한번 다시 시작하기로 했다...

두서 없이 정리한 내용들 그때는 보기 편했는데 
지금은... 내가 뭔말을 했는지 ㅋㅋㅋ

암튼 오늘부터 다시 시작이다.   ㄱ ㄱ ㄱ
일단 공부한 책들 부터 정리 

일단은 오브씨 부터...

* 처음 접하시는 분들은 쉽게 이해가지 않는 부분들도 있겠지만 
   그냥 넘어가시고 쭉 읽어보세요.
  원래 소스는 직접 쳐봐야 이해가 빠르니 걍 한번 읽고 코딩 좀 하다보면
  이해가 갈 것 입니다.

Objective - C 란 ?

 *참고 : 여기서 오브씨는 언어로서보다 아이폰 앱 개발에 대한 초점으로 정리하였다.

간단 소개 :
 ANCI(표준기구) C 언어에 스몰토크 스타일의 메세지 구문을 추가한 객체지향 언어.
하지만 스몰토크의 영향이 많이 남아있지는 않다. 
(그러나 중요한 것은 이 스몰토크의 영향으로 오브씨에서는 클래스도 
하나의 객체 취급을 받는다 이것은 기억해두자)
1980년대 초 Brad Cox 가 만들었고, 188년에 NeXT사의 워크스테이션 Next의 사용자
인터페이스인 NetStep에 사용됨으로써 널리 알려지기 시작하였으며, 
1996년 애플이 넥스트 사를 인수하고 나서 Mac OS X 의 (Cocoa) 애플리케이션 
프레임워크의 표준 프로그래밍 언어로 쓰이고 있다. 
- 코딩기본규칙 (대충..)
   클래스는 대문자로 시작한다. 
   클래스 메소드이건 인스턴스 메소드인건 메소드는 소문자로 시작한다. 
   인스턴스 변수는 소문자로 시작한다. (private일 경우 '_' 허용)
   캐멀 표기법을 따른다. (식별자의 첫자는 소문자로, 첫단어는 대문자로 시작한다)
- 처음에는 이게 다 뭔말인가 싶었는데 몇 번 다시 공부하니 이제 술술 나온다 ㅋ

* 주요 특징 
- 기존 C에 최소한의 확장으로 객체지향 프로그래밍 기능을 추가하였다.
- MVC (Model - View - Controller) 모델을 사용한다. 
  Model - 데이터 핵심처리 (로직) 
                애플리케이션 데이터를 저장하고, 이 데이터를 조작하는 로직을 정의
  View - 직접적인 인터페이스 뷰 화면
              사용자 인터페이스(윈도우나 버튼)에서 볼 수 있는 객체들의 집합으로 정의
  Controller - 사용자/데이터의 흐름 처리 
                     위의 모델과 뷰를 조율하는 역할을 한다. 
  각각 분리하여 서로간의 간섭을 최소화하여 개발/유지/보수의 편의성을 높였다.
- Dynamic Runtime을 제공한다. 
  확실히 뭔 말인지는 모르겠으나 그간 공부한 것으로 생각하자면 
  불필요한 객체나 리소스들을 처음부터 생성하지 않고 가능한 필요할때 
  생성/로드 한다는 것 같음. 강제적이 아니라 개발자 선택사항임
- 표준 C와 C++을 Objective - C 코드와 결합할 수 있다
  하지만 나는 C 와 C++ 을 잘 모른다는 것.. 상관없는 얘기 ㅎ
- 가비지컬렉션 (Garbage Collection)을 자체 지원한다. 

뭐 대략 이정도 일려나..

* 클래스와 인스턴스 
- 오브씨에서 클래스와 그 클래스로부터 나온 인스턴스들 모두 객체이다. 
  위에서 말했다시피 스몰토크의 영향이다. 클래스도 객체취급이다. 
  어찌보면 매우 편하다, 
- 클래스는 인스턴스를 생성하기 위한 청사진이다. 
  즉 객체를 표현하기 위한 선언 정도.
  즉 이용하고자 하는 객체의 특징을 정의해 놓은 것이다. 
  클래스는 데이터와 함수가 정의되어 있고 
  이 클래스를 이용하여 생성되는 객체들이 인스턴스이다. 
  예를 들면 '사람'이란 클래스를 정의하면
  '철수', '영희' 와 같은 실제적인 인스턴스를 만들어 사용하게 된다. 
  자신은 self, 부모는 super 로 접근이 가능하다. 
 
  *.h 파일 
@interface 클래스명 : 상위클래스명
{
     멤버변수 선언
}
메소드 선언
@end

*.m 파일
@implementation 클래스명
메소드 구현 
@end

  위와 같은 형식으로 사용된다. 
- 객체와 인스터스는 비슷한 개념으로 사용되지만 조금 차이가 있다. 
  객체는 모든 것을 의미하는 반면, 
  인스턴스란 클래스의 정의를 통해 만들어진 객체를 의미한 것이다. 
  위에서 클래스를 인스턴스를 생성하기 위한 청사진이라고 정의한 것과 같다.
  좀 더 자세히 들어가면 객체지향 프로그래밍적인 관점에서
  객체란 : 클래스의 타입으로 선언되었을 때를 의미
  인스턴스란 : 객체가 메모리에 할당되어 실제 사용 될 때  
  그리고 중요한 것은 앱 개발에 있어서 alloc으로 메모리를 잡은 다음 
  반드시 init 로 메소드를 호출해 줘야 한다. 
   이런식 [[someClass alloc]init];
  

* 클래스와 객체 
- 클래스는 State 와 Behavior 를 선언한다. 
- State (편하게 DATA라고 생각하자)는 인스턴스 변수들을 통해 관리된다. 
- Behavior (동작정도..)는 함수를 통해 구현된다.
- 인스턴스 변수들은 일반적으로 숨겨져 있다. 
  (getter/setter methods를 통해서만 접근이 가능)

쉽게 State는 data 또는 변수 정도로 생각하고 Behavior는 함수라 생각하면 될 듯 하다.

* 객체 메시지 전달 
- 오브씨는 객체에 명령을 주는 것을 '메시지를 보낸다'라고 표현한다. 
- 메시지는 '[ ]'(대괄호)를 사용하여 표시한다. 
- 여기서 중요한 것은 메소드를 호출하는 것이 아니라 메세지를 보낸다는 것이다.
- 또한 메시지의 수신자는 그 메시지를 거부 할 수 있다. 
  이것또한 재미있는 것인데 바로 Dynamic Runtime 을 제공하기 때문이다. 
  이 매커니즘으로 정의된 객체에 메시지가 실행시간에 전달된다. 
  그러므로 즉 메시지를 받은 객체가 그 메시지를 구현할 경우 실행되지만, 
  그렇지 않은 경우에는 실행되지 않는다. 
  그렇다고 컴파일시 에러는 나지 않는다. 바로 다이나믹 런타임 때문이다. 
- 메시지는 메시지를 구현한 객체로 보내지거나 그 객체가 상속한 상위 클래스로도 보내질 수 있다.
  self, super 라는 객체 포인터를 지원한다. 더군다나 nil 객체에도 전달 될 수 있다. 

[reciver message];
[reciver message:argument];
[reciver message:arg1 andArg:arg2];

위의 예문을 보면, 
수신자(reciver)는 객체이고, 메시지(message)는 어떤 명령을 할 것인지 말해준다. 
소스코드 내에서 메시지는 단순히 메서드 이름이고, 그 메서드에 필요한 인자들을 
넘겨주게 된다. 
여기서 수신자는 다음 중 하나를 가리키게 된다. 
- 변수 또는 객체를 가리키는 표현 (self : 자신(변수), super : 부모(객체-인스턴스) 변수 포함)
- 클래스 이름

쉽게 생각해 메시지는 메서드 이름과 그 메서드에 전달되는 인수들을 쭉 나열한 것이다. 
예를 들어보자 

[myName addName];

이 메세지는 myName이라는 객체에 addname이라는 메서드를 실행하라는 메시지 전달표현이다. 
메서드가 넘겨 받아야 할 인자들(arguments, parameters)이 있을 경우 ' : ' (콜론)을 이용한다. 

[myDraw setWidth:20.2];

위와 같이 인자가 하나일 경우 ' : ' 을 붙이고 바로 인자값을 넣어주면 된다. 
그럼 여러개일 경우에는?

(함수)
-(void)setOriginX:(NSFloat)originx y:(NSFloat)originy;  //두개의 인자를 가진 함수 

(메시지 전달)
[myDraw setOriginX:20.2 :50.5];
[myDraw setOriginX:20.2 y:50.5];  // 메세지 구별자 추가 

위의 두 코드는 같다. 하지만 아래것을 보면 인자를 받도록 정의된 메세지 구별자를 추가하였다.
밑에 것과 같이 코딩하는 것이 소스관리에 편하다. 

예문 작렬)

Person *person;
// Person 이라는 클래스가 있다고 일단 가정 
// 여기서 '*' 는 일종의 포인터로 객체생성을 의미한다. 

[person displayName];
// Person의 이름을 표시하는 함수를 호출하는 메세지 . 그냥 함수가 있다고 치자..

int theAge = [person age];
// 걍 나이를 가져오는 메세지가 있다고 치자..

[person setAge:30];
// Person 의 나이를 바꾸는 setAge 함수 호출 

[person setInformation:@"미남" age:30];
// Person 의 정보를 바꾸는 setInformation 함수 호출

위의 예문을 오브씨 또는 Xcode를 처음 시작하는 사람이라면 
이게 뭔말인가 싶기도 하겠지만 
걍 클래스와 함수가 있다는 가정하에 호출을 저런식으로 한다 정도만 이해해두자.

* 메세지 중첩 사용 : 중첩된 표현 (Nested Expression)
- 이는 가장 많이 사용하는 메세지 전달방법이다. 
  바로 메세지 전달 안에 또 다른 메시지를 부르는 형태이다. 
  조금 낯설수도 있지만 정말 많이 쓰이고 유용하다. 
  그냥 생각없이 써도 되지만 하나 기억해야 할 것은 
  메세지 메소드의 결과 값이 객체일 경우에만 중첩하여 쓸수 있다.
  (하지만 오브씨는 거의 모든게 객체이므로 신경쓸 일이 거의 없다.)
  물론 3중, 4중... 모두 가능하다. 

[myDraw setWidth:[yourDraw primaryWidth];

위의  코드와 같이 사용하면 된다. 쉽게 내 그림의 너비를 니 그림 너비로 바꾸는 코드이다. 

여기서 참고로 알아두어도 좋을 것은 
오브씨는 문법적으로 인자에 대한 pseudo-naming(가짜이름)을 지원한다는 것이다. 

-(int)changeColorToRed:(NSFloat)red green:(NSFloat)green blue:(NSFloat)blue 

[myColor changeColorToRed:2.0 green:5.0 blue:3.0];

위의 예문을 보면 오브씨 표현에 따라 딸라질 수 있다. 
myColor 가 Color에 의해 만들어진 것이라면, 인스턴스 메소드 
-changeColorWithRed:green:blue 는 내부적으로 
_i_Color_changeColorWithRed_green_blue 와 같은 이름을 갖게 된다. 
여기서 i 는 인스턴스 메소드 임을 표기하기 위함이고, 
그 뒤에 클래스 이름(Color)과 메소드 이름 (changeColorWithRed) 를 두었다. 
콜론 기호는 전부 ' _' 기호로 변환되었다. 

이 이름을 보면, 인자가 전달되는 순서 또한 메소드 이름의 일부분 임을 알 수 있다. 
메소드에 전달되는 실 인자의 순서를 바꿀 수는 없는 것이다. (중요)
pseudo-naming 이라고한 이유이기도하다. 

바트 그러나 이러한 내부 표현명을 직접적으로 사용할 경우는 거의 없다. 
그냥 참고사항으로 알아두라고...

일반적으로 메세지는 오브씨 런타임 라이브러리에 정의된 함수에 대한 
호출로 변환된다. 

그리니 링킹 시점에 어떤 메시지가 어떤 메소드를 호출하게 되는지 
알 필요가 없다. 
실행 시간까지는 메시지의 리시버 클래스를 알 필요가 없다는 뜻이다.

여기서 링킹이란..
컴파일의 한 작업.
소스코드를 작성하고 컴파일을 하게 되면, 각각의 기능에 따라서 
목적코드라고 하는 것에 담고 있는 목적파일이 생성된다. 
이러한 목적파일들을 실행 가능한 형태로 만들기 위해 여러개의 
목적파일들을 하나로 연결해 주는 작업이 필요한데 이것을
링크, 또는 링킹 이라고 한다. 

* dot (' . ') 연산자 - 도트 연산자
- 막 오브씨와 앱개발을 시작한 사람이라면 이해할 필요가 없다. 그냥 쓰면 된다. 
- 도트연산자는 실체는 함수를 불러내는 것이지만 컴파일 타임의 처리가 다르다. 
  오브씨의 경우 함수를 불러낼 때 그 함수가 정말 존재하는지 아닌지의 체크는
  런타임에 체크한다는 것이 원칙이다.(다이나믹 런타임)
  따라서 ID 형의 오브젝트에 대응하는 함수의 호출은 특히 체크도 하지 않고 
  모두 컴파일이 된다. (위 메세지에서 설명)
  오브젝트에 자료형이 지정되어 있는 경우에도 경고는 나오지만 
  컴파일에는 문제가 없다.  - 물론 그 상태로 실행하면 앱에서는 예외가 발생하여 
  프로그램은 종료가 되어 버린다. 
 
일단 개념을 적다 보니 처음시작하는 사람은 뭔가 하는 맘도 있겠다 
먼저 예문을 보자 

float height = [person height];
float height = person.height;

[person setHeight : newHeight];
person.height = newHeight;

[[person child] setHeight : newHeight];
person.child.height = newHeight;

이 예문들은 모두 같은 의미이다. 
이쯤에서 일단 도트연산자는 소스를 아주 편하게 만들어주는 좋은 놈이란 걸 알 수 있다.

그럼 다시 설명하다만 부분으로 돌아가 
존재하지 않는 메세지를 전달하고 컴파일이 되는 상황에서 도트연산자의 
중요한 기능을 알 수 있다. 
도트연산자는 좀 더 엄격한 체크를 하도록 해뒀다는 것이다. 
오브젝트에 도트연산자를 적용하면 그 자료형이 체크되도록 된다. 
존재하지 않는 프로퍼티가 지정되어 있으면 컴파일이 되지 않는다.
하지만 애시당초 id 형은 오브젝트에 도트연산자를 적용하는 것이 불가능하다.
그러므로 도트연산자를 사용하고 싶은 경우 반드시 형변환을 하여 사용하자.

일단 예문

id person = [[person alloc]init];

NSString* lastName = [person lastName];
//존재하지 않는 함수를 호출 그러나 컴파일은 된다 

도트함수 사용 

id person = [[person alloc]init];

NSString* name = person.name;
// 일단 id 형으로 프로퍼티에 접근 - 에러가 난다. 

NSString* lastName = ((person*)person).lastName;
// 존재하지 않는 프로퍼티에 접근 - 에러가 난다. 

- 처음 하시는 분들은 코드가 쉬이 이해가지 않을 것이다. 
그냥 도트연산자만 보자 저렇게 사용하는 거구나.. 나중 차례로 설명하겠다. 

아무튼 이것을 가지고 프로퍼티는 "컴파일 타임의 정적인 자료형체크를 도입했다"
라는 것이 가능하게 됐다. 이해할 필요는 없고 걍 읽고 내려가자 
오브씨와 같은 동적인 언어는 그 약점이 컴파일 타임의 검사가 느슨하다는 것이다.
프로퍼티의 처리는 정적인 성향의 개념을 도입하고 있다. 

가장 동적인 느슨함이 오브씨의 특징인 것이 사실이다. 
프로퍼티를 사용하는 경우 늘 오브젝트의 자료형을 의식하고 또 그것을 소스코드에
형변환하는 방식으로 사용하지 않으면 안된다. 
실제로 프로퍼티를 사용한 프로그래밍을 실행한 경우 id 형을 오브젝트에 대해서 
프로퍼티를 적용하고 싶은 경우가 많다. 
예를 들어 NSArray 부터 꺼낸 오브젝트 등에 이와 같은 경우 형변환 하던가 자료형을
지정한 변수에 대입할 필요가 있다. 

도트연산자는 컴파일 타임의 체크 기능을 높인다는 점에는 성공적인 기능일 것이다.
그러나 원래목적은 코드작성을 줄이고 편하게 하기 위한 목적으로 도입된 기능이라
빈번하게 형변환할 필요가 있으므로 결과적으로 늘어나버리고 있는 상황이다.

또 한가지의 특징은 C 언어에서 사용하는 복합지정(+=, -=, *=, /=)을 사용할 수 있다.

* Method
-  객체가 가지는 함수 정도. 크게 인스턴스 메소드와 클래스 메소드가 있다.
- 인스턴스 메소드 : 클래스로 선언된 변수 즉 인스턴스를 그 적용 범위로 갖는 메소드
  어렵게 생각하지 말자 그냐 메모리에 올라갔다 정도로 이해하자 
- 클래스 메소드 : 인스턴스로 실행될 필요가 없는 메소드 
  이른바 static method 라는 것으로 산술 함수 모음을 클래스로 정의 한다던가 할 때 
  유용하다. 가끔 생성자를 스태틱으로 따로 만들어서 사용하는 경우가 있다.
- 리턴 타입을 명기하지 않으면 id  타입을 리턴한다. 

메소드 선언 형식 

- (void)insertObject:(id)anObject atIndex:(NSUInteger)index

' - ' : method type identifier 메소드 타입
       ' - ' 는 인스턴스 메소드, ' + ' 는 클래스 메소드 
'(void)' : 리턴타입 
'insertObject:atIndex:' 'atIndex:' : Method signature keywords
'(id)' '(NSUInteger)' : 파라미터 타입
'anObject', 'index' : 파라미터 명

- Object 클래스는 Object  클래스를 포함하여 그것을 상속하는 클래스의 
  인스턴스를 제대로 생성 alloc 클래스 메서드를 정의한다. 
- 일반적인 인스턴스 매서드는 매서드를 호출하는 인스턴스가 필요하지만 
  클래스 매서드는 인스턴스 없이도 실행될 수 있다. 
- 따라서 alloc 메소드는 인스턴스가 존재하지 않더라도 호출에 문제가 없다. 
  alloc 매서드는 인스턴스를 생성하기 위한 클래스 매서드 이므로 
  팩토리 매소드라고도 한다. 

* Self
- 암시적 self
- 메서드 범위 내에서는 임시 인수 및 선언된 변수 이외에 절대적인 변수로 self 를 정의한다.
- self 변수는 id  형식. 항상 매서드를 호출 인스턴스를 참조한다. 
- 즉, 매서드를 실행하는 개체 자신을 나타내는 변수가 self 인 것이다. 
- self 는 매소드 이외의 장소에서는 사용하지 않는다. 실행 코드 부분에서만 암시 값이 존재한다.
- self 를 사용하여 개체의 인스턴스 변수 개체에서 볼 수 있다. 
  이것은 메서드의 정식 인수 변수 이름, 인스턴스 변수 이름을 은폐할 때 등에 사용할 수 있다. 

 * Property 

 * 프로퍼티에 들어가기 전에 접근제어에 대해 잠깐 알아보자 
이것은 오브젝트가 가지는 인스턴스 변수로의 접근에 관한 구현 사항을 간략하게 해주는 기능이다.
C 언어적인 자유도를 프로그래머에게 제공해주고 싶은 오브씨는 역시 그쪽에서는 자유였다. 
일단 인스턴스 변경에 @public, @protected, @private 라고 하는 접근 수식자를 부가하는 것도 가능하다.
그러나 @protected 와 @private 를 붙였다고 해도 컴파일 타임에 경고가 나오는 정도로 빌드도 나오고
실행도 문제 없이 되버린다. 이게 오브씨다운 방식이라 할 수 있다 라고 하지만 한계가 있다..
접근은 복잡하고, 반대로 접근을 금지시키는 것은 거의 불가능에 가깝다. 
이러한 상황에서 나오게 된 것이 바로 프로퍼티라는 넘이다. 

- 우선 프로퍼티의 목적을 명확히 해두고 보자 
  프로퍼티는 "클래스에 엑세스 함수를 간단히 추가한다" 를 위해 도입된 기능이다.
- 객체의 멤버 변수, 그 중 외부에서 접근 할 수 있는 것들 이라고 생각하자
- property 는 MVC 디자인 패턴에서  Model 에 해당한다. 
- property 는 어플리케이션에 필요한 데이터를 신뢰할 수 있고 안전하게 보존하는 데 
  필요한 룰을 제공한다. 
- Synthesize  는 Property 에서 선언한 데이터들을 합법적으로 접근할 수 있는 통로를 
  편리하게 제공한다. 

@property BOOL flag;
@property (copy) NSString *nameObject; // Copy the object during assignment
@property (readonly) UIView *rootView; // Declare only a getter method

- 위의 코드를 헤더파일 (*.h)에 써주고 구현파일(*.m)에서 아래처럼 적어주면 
프로퍼티와 같은 이름의 getter 멤버 함수와 set<프로퍼티명> 의 이름으로 
setter 함수를 자동으로 만들어 준다. 
- 일반적으로 MVC 개발에서도 setter/getter 로 구성된 도메인 객체를 따로 두고 있듯이
  오브씨에서도 역시 비슷하게 구현을 하고 있다. 
- @property 지시자는 클래스의 @interface  내부에 선언한다.

@synthesize flag, nameObject, rottView;

- 프로퍼티에 접근 할 때 getter/setter 멤버 함수를 통하여 접근하도록 하는 것은 
  추후 코드 수정에 편이를 가져온다.
- 이 메서드들을 사용함으로써 객체 지향 프로그래밍의 캡슐화(Encapsulation)에 
  더욱 충실 할 수 있다.
- Property 를 정의함으로써 효과적으로 접근자 메서드들을 간략화 시키는 효과를 가져온다.
- 프로퍼티 접근 함수를 직접 작성하거나 실행 중에 함수 id 를 대입한다던가 하려면 
  @synthesize 대신 @dynamic 이라고 적어주면 된다. 
- @property 뒤에 '( )' 안에 들은 것들은 프로퍼티의 성질을 정의한다. 

@property(getter=suckAss, setter=fuckAss, readwrite, copy) NSObject *ass;

- 예문과 같이 getter/setter 의 명을 지정해 줄 수 있을 뿐 아니라 asign, retain, copy 택일하여
  프로퍼티가 객체 형일 때 객체 id 를 넘겨 받느냐, retain 함수 리턴 값을 받느냐
  아니면 새로 만들어 복사하여 사용하느냐 등을 지정해 줄 수 있다. 

- 프로퍼티 성질 
getter = getter명, setter=setter명 : 겟터, 셋터 함수명을 정할 수 있다. 
정하지 않으면 기본적으로 property의 getter  매서드 명은 property 자신의 이름과 동일하고
setter 매서드명은 setPropertyName: 이다. 

readonly : 읽기전용, 셋터를 만들지 않는다.
주로 프로퍼티가 변경되지 않도록 할 때 사용한다. 
이 속성은 @implementation 블럭 안에서 오로지 getter 메서드만 필요할 경우 사용한다. 
@synthesize 지시자를 사용하였을 경우라도 역시 getter 매서드 역할만을 하게 된다.
값을 대입하려고 할 경우 에러를 출력한다. 
필드의 값을 바꾸는 메소드를 사용자가 직접 만들 수 있기는 하지만, 
컴파일러가 세터를 자동으로 생성해주지는 않는다.

readwrite : 기본값. 겟터/셋터 둘다 만든다. 값을 읽고 쓸 수 있다는 말.

assign : 기본값. 포인터를 받는다고 보면된다.
단순하게 값을 대입한다.
이전에 어떤 객체를 가리키고 있던 프로퍼티라면 이로 인해 해당 객체는 
미아가 되어 메모리릭의 주범이 될 수 있다. 
가비지 콜렉터를 사용하지 않는다면 사용을 피해야 한다. 
int 나 float 와 같은 기본형을 다룰 때 사용한다. 
컴파일러는 setter 를 단순히 "myField = value" 와 같은 단순 할당문으로 만든다. 
이것은 기본값으로 되어 있지만 
대부분 객체를 다룰 때에는 메모리 관리 측면에서 적절하지 않다.

retain : xcode 에서는 레퍼런스 카운팅으로 메모리를 관리해 주기 때문에 
필수적이다 아주 중요하다. 이것은 따로 설명하겠지만 개략저그로 말하면
객체의 retain 함수는 자기 id 를 리턴하긴 하는데 대신 레퍼런스 카운트를 
하나 증가 시킨다 요쯤.. 자세한 것은 따로 설명하겠다. 
어찌보면 assign 과 비슷하지만 조금 다르다 
이전에 가리키고 있던 객체가 있다면 해당 객체를 Release 하여 메모리에서 
제거해 준다. 
가비지 콜렉터를 사용한다면 결과적으로 assign 과 동일한 결과를 가지겠지만 
좀 더 명시적으로 사용해 주면 좋다. 
객체의 값을 다룰 때 주로 사용
컴파일러는 입력값으로 쓰이는 객체를 리테인하고 이전에 있던 객체를 릴리스 한다.

copy : 객체 사용시 새로 만들어 복사하여 사용
객체를 바로 대입하지 않고 해당 객체의 복사 메서드를 Invoke호출한다.
(Invoke : 간단히는 함수 호출. 다른 스레드에 있는 컨트롤을 안전하게 호출하기 위해 사용)
그리하여 다른 메모리 영역에 복사본을 만든 다음 그것을 반환하게 된다. 
이전에 가리키고 있던 값은 Release 시킨다. 
전달된 원래의 값이 변경되지 않도록 할 때 사용한다. 
예를 들어 배열을 프로퍼티로 할당할 때, 프로퍼티로 지정한 다음에도 
원래 배열에 있떤 값을 보존하고자 하는 경우에 쓰인다. 
객체를 복제하고 복제된 객체를 프로퍼티에 지정하게 된다. 

atomic : 기본값 멀티쓰래드 상에서 안전하게 접근
멀티스레드 등으로 구성된 프로그램이 특정 접근자 메서드를 호출할 때
서로 충돌이 나지 않도록 객체 레벨에서 Lock 을 걸고 프로퍼티에 접근.
기본적으로 생성된 접근자 메소드는 프로퍼티의 값을 변경할 때, 
뮤텍스(mutex)를 사용하도록 되어 있어서 멀티 스레드 환경에서도 안전하게 실행할 수 있다.


nonatomic : 앱 개발 대부분 이것을 선언한다 멀티쓰래드 지원 안함.
이 속성은 접근자 메서드가 Atomic 하지 않게 동작한다. 
기본적으로 접근자는 Atomic 하게 동작한다. 
하지만 Atomic은 접근 할때마다 Lock 을 걸고 다시 푸는 작업이 반복되므로 퍼포먼스를 
떨어뜨리는 결과를 가져온다. 이런 접근이 필요없다면 이 속성을 사용하는 것이 좋다. 
클래스가 멀티 쓰레드 환경에서 실행되는 것이 아니라면 nonatomic 을 선언하여 
불피요한 뮤텍스 관련 처리를 하지 않는다. 

- Property 를 사용할 때 주의사항 한가지가 있다. 
  바로 객체가 제거될 때 소멸자로 dealloc 이 호출되는데 
  property 들이 자동으로 소거되지 않으므로 명시적으로 release 를 사용하여 
  제거해 주어야 한다. 

- (void) dealloc {
[value release];
[super dealloc];
}

- 여기에서 AutoreleasePool 을 사용하여 drain 이라는 것도 사용할 수 있다. 
  GC(gabage collector) 가 없는 환경에서는 drain = release 이지만, 
  GC 가 있는 환경에서는 조금 차이가 있다. 
  drain 은 GC 에다가 알려주기만 하고 실제로 해제하지는 않는다. 
  iPhone 환경에서는 GC가 없으므로 drain 과 release 는 동일하지만 
  애플문서에 따르면 추후 GC 가 추가될 수 있는 점을 고려하여 
  drain 사용을 권장하고 있다. 


* Protocol 
-  쉽게 가상함수만 가지고 있는 클래스 같은 종류라고 할까
- 즉 프로토콜은 메소드 선언만을 가지고 있다. 
- 클래스를 선언할 때 이 프로토콜을 정의해주면 프로토콜에 선언만 되어 있는 
  메소드를 꼭 구현해줘야 한다. 

@protocol MyProtocol
-(void)requireMethod;

@optional
- (void)anOptionalMethod;
- (void)anotherOptionalMetod;

@required

-(void)anotherRequiredMethod;

@end

- 위 예제에서 @optional 아래는 안해줘도 상관이 없다. 
  그러나 @required 아래는 필수로 해줘야 한다. 
  아무것도 안쓰면 @required 가된다. 

- 조금 깊게 들어가보면 오브씨는 비정형프로토콜 (informal protocol) 이라고 불리는 
ad-hoc 프로토콜과, 정형프로토콜 이라고 불리는 컴파일러가 강제하는 프로토콜을 통해 
다중 상속을 지원한다. 

- Formal protocol 정형 프로토콜
포멀 프로토콜은 상속된 클래스에서 반드시 구현되어야만 하는 메소드들이다.
주어진 서비스를 위해 필요한 모든 것을 다룰 수 있는 지를 확인하는 클래스에 따른 검증으로 
보여질 수 있다.
클래스는 무제한 갯수의 프로토콜을 적용할 수 있다. 
오브씨에서 프로토콜은 특수한 개념이다. 
각진괄호로 표시한다. 

@protocol MouseListener
-(BOOL) mousePressed;
-(BOOL) mouseClicked;
@end

@protocol KeyboardListner
-(BOOL) keyPressed;
@end

@interface Foo : NSObject <MouseListener, KeyboardListener>{//프로토콜의 상속
...........
}
@end

클래스는 그 적용이 선언 없이도 모든 프로토콜의 매소드를 구현할 수 있다. 
포멀 프로토콜을 따르는 개체 타입은 프로토콜 그 자체의 이름이 각진 괄호 사이에 추가될 수 있다.

- infomal  protocol 비정형프로토콜
클래스가 특정 서비스를 다룰 수 있지만, 전체 프로토콜을 준수하도록 강요치 않게 
클래스가 프로토콜을 준수하게 하는 것이 가능하다. 
비정형 프로토콜은 클래스가 구현할 수 있는 매소드의 리스트이다. 
그 리스트는 문서에 명시되는데, 언어스펙에는 그 리스트를 표현하기 위한 문법이 없기때문이다.
비정형 프로토콜은 종종 선택적 매소드(optional method)를 포함하는데, 
이 매소드를 구현하면 클래스의 동작이 바뀔 수 있다. 


* Category 
- 메소드를 추가한 클래스 변종을 만들어 내는 방법이다. 
- 기존 클래스에 카테고리 명만 붙여도 메소드 추가한 변종을 만들 수 있다. 
- 단 메소드만 가능하다. 변수는 안된다는 얘기

*.h file
#import "ClassName.h"

@interface ClassName (CategoryName)
// method declarations
@end

*.m file

#import "ClassName + CategoryName.h"

@implementation ClassName  (CategoryName)
// method definitions
@end

- 이 예문은 ClassName 이라는 클래스에 CategoryName 이라는 카테고리 명을 붙여서 변종을 
  만들어 낸 예문이다. 

* for
- 다른 언어에서 종종 지원되는 어레이를 뒤지는 기능이 가능하다. 

NSArray *array = [NSArray arrayWithObjects:@"One",@"Two",@"Three",@"Four", nill];

for (NSString *element in array){
     NSLog(@"element:%@", element);
}

NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
@"quattuor",@"four",@"quinque",@"five",@"sex",@"six", nil];

NSString *key;
for (key in dictionary){
     NSLog(@"English:%@,Latin:%@", key, [dictionary valueForKey:key]);
}

NSArray *array = [NSArray arrayWithObjects:
@"One",@"Two",@"Three",@"Four",nil];

NSEnumerator *enumerator = [array reverseObjectEnumerator];
for (NSString *element in enumerator){
     if([element isEqualToString:@"Three"]){
          break;
     }
}

NSString *next = [enumerator nextObject];

-  예제를 실행해보면 in  뒤에 있는 어레이 숫자만큼 도는 것을 볼 수 있다. 
- next = "Two", 뒤집어서 "Three" 에 멈췄으니 다음은 "Two" 인 것이다. 

* 오브씨 유형과 타입
- 일단 주로 사용하는 유형과 타입에 대해 한번 쓱 훑어보고 시작하자.

유형
id  - 객체, 포인터라고 이해해도 될 듯.
Class - 클래스 객체
SEL - 매서드 이름을 식별하는 컴파일러 할당 코드
IMP - id 를 돌려보내는 매서드 구현 포인터
BOOL - Boolean 값 

여기서 Class 와 IMP는 크게 신경 쓸 필요 없이 걍 id 만 쓴다고 생각하자
id 는 어떤 종류의 객체, 클래스 또는 인스턴스를 유형짓기 위해 사용될 수 있다.
또한, 클래스의 인스턴스를 정적으로 유형짓기 위해 클래스 이름을 타입 이름으로 
사용할 수 있다. 정적으로 유형 지어진 인스턴스는 해당 클래스나 상위 클래스의 
인스턴스 포인터로 선언된다. 

타입
nil   |  null 객체 포인터
Nil  |  null 클래스 포인터

위 두 타입은 모두 같은 기능을 한다. 단지 객체와 클래스를 구별하기 위해 대소문자를 사용한다. 

* 컴파일러 지시문 
- 컴파일러 지시문은 " @ " 로 시작한다. 

@interface  - 클래스 또는 카테고리 인터페이스의 선언 시작
@implementation - 클래스 또는 카테고리의 정의 시작
@protocol - 정형 프로토콜의 선언 시작
@end - 클래스, 카테고리 또는 프로토콜의 선언/정의 종료
@private - 인스턴스 변수 범위를 이를 선언한 클래스로 한정 
@protected - 인스턴스 변수 범위를 클래스 선언 및 상속으로 한정
@public - 인스턴스 변수 범위의 한정 해제
@class - 다른 곳에서 정의된 클래스 이름을 선언 
@selector(method) - method 를 식별하는 컴파일러 셀렉터를 반환
@protocol(name) - 프로토콜 클래스의 인스턴스를 반환
@encode(spec) - spec 의 유형 구조를 인코딩하는 문자열을 산출 
@defs(classname) - classname 인스턴스의 내부 자료 구조를 산출 

* 파일확장자
- *.h : 선언이 들어가 있는 헤더 파일
- *.m : OC 또는 C 소스 파일 
- *.mm : C++ 소스파일 

* #import
- #include 같은 개념이지만 #import를 쓰면 해당 *.h 파일이 한번만 포함되도록 해준다.

* Comments
- 주석을 쓸때는 ' // ' 을 사용한다.

* SEL, @selector
- 셀렉터는 메소드 이름의 문자열 주소이다. 
- 주소가 같으면 동일 메소드이므로 이것을 고유식별자라고 생각해도 된다. 
- 오브씨에서는 이것을 SEL 이라는 자료형으로 표현한다. 
- 그리고 이것을 얻는 키워드가 @selector 이다. 

SEL sel1 = @selector(display); // display 메소드 고유 식별자 or 함수이름 주소
SEL sel2 = sel_getUid("display"); // display 메소드 고유 식별자 or 함수이름 주소 

- 두번째 형식의 경우 함수 문자열로 셀렉터를 얻을 수 있기 때문에 파일에 
  메소드 이름을 기록해 두면 이것을 이용해 나중에 메소드를 호출할 때 유용하다.
  하지만 이렇게 얻은 SEL 역시 혼자서는 아무 의미가 없다.
  이것은 메소드를 간접 호출할 때 다시 사용된다. 

SEL sel2 = sel_getUid("display");
[pbase performSelector:sel2];  //display call

- performSelector 는 셀렉터를 이용해 메소드를 간접 호출한다. 
  문자열 이름으로 메소드를 호출할 때 사용할 수 있지만, 메소드 인자를 전달하는
  데는 한계가 있다. 
  그래서 셀렉터를 이용해 IMP 를 얻은 다음에 IMP 로 직접 메소드를 호출한다면
  자유롭게 인자를 전달할 수 있다.

- 오브씨 컴파일러는 매서드를 식별하는 이름을 컴파일 할때 내부 표현으로 변환한다. 
이 매서드의 내부 표현을 선택기라고 메시지를 보내고 받는 뒷면은 이 셀렉터가 
교환되고 있다. 
하지만 매서드를 식별하기 위한 내부표현은 컴파일러에 의존하는 문제이고, 
개발자가 알아야 하는 범위는 없다. 
개발자에게 중요한 것은 이 선택기를 SEL 형식으로 취급할 수 있다는 사실이다. 

- 매서드가 어떤 데이터로 변환되고, 어떻게 인식되고 있다는 문제가 없다. 
하지만 오브씨는 이 내부 표현을 SEL 변수로 취급하는 것을 보장한다. 
즉, SEL 변수에는 매서드 이름을 확인하기 위하여 컴파일러가 할당 특수 코드를 
저장할 수 있는 것이다. 
매서드를 식별 선택기는 @selector 컴파일러 지시문을 사용하면 얻을 수 있다. 

@selector(method)

- method 는 메서드의 이름을 지정한다. 
지정된 매서드의 이름이 있는 여부는 메서드를 호출하는 경우 런타임에 
결정되므로 컴파일 타임에 계산되지 않는다. 

참고 
* ' * '   이 넘의 정체
- 이 넘을 알려면 먼저 포인터를 알아야 한다. 

'포인터는 변수의 일종으로 데이터를 갖고 있는 것이 아니라 메모리의 주소(address)를
표현하는 자료형이다'

포인터 변수는 어떤 데이터가 기억된 장소의 주소를 기억할 수 있는 변수를 말한다.
즉, 포인터가 가리키는 대상은 바로 어떤 데이터가 저장되는 메모리의 주소이며, 
포인터 변수의 내용은 데이터가 아니라 번지이다. 
이러한 번지를 이용하여 배열이나 구조체 데이터를 직접 메모리에서 꺼내거나 
기억할 수 있다. 

포인터 변수를 선언하기 위한 일반 형식 
type *var_name;
Int *p, float *q, char *r  등으로 선언하여 사용한다. 

여기서 type은 포인터형의 기본형으로 포인터가 가리킬 수 있는 객체의 형이다. 
변수이름 (var_name) 앞에 
'*'  는 컴퓨터에게 포인터 변수를 생성한다는 것을 알려준다.
즉,  간접참조(indirection reference) 또는 역참조(dereferencing) 연산자라 불리는 
' * ' 연ㅅㄴ자는 이 연산자 뒤에 오는 변수의 주소를 반환한다. 
예를 들어 p 라는 변수가 q 라는 다른 변수의 주소를 가지고 있다면, 
'p는 q를 가리킨다' 라고 표현한다. 

간접 연산자  '*' 는 포인터 변수에 저장된 번지의 내용물을 알려주는 연산자이다. 
여기에서 주의해야 할 부분은 포인터 변수에 저장된 번지를 알려주는 것이 아니라, 
포인터 변수에 저장된 번지에 저장물 내용물을 알려준다는 점이다. 
그러므로 *ptr 이라면 n에 저장된 값을 보여주는 것이다. 
즉 n 에 3을 저장했고, ptr 에 n 의 번지수를 저장했다면 
*ptr 은 n 의 값을 알아내는 간접 연산자가 된다. 

간접연산자 * 는 포인터변수에 저장된 변수를 이용하여 그 변수의 내용을 간접적으로 
참조할 수 있는 연산자이다. 

아직 사용해 보지는 않았지만 
const 라는 연산자도 있다. 이는  어떻게 보면 변경으로부터 변수를 보호하는 것인데 
사용예가 드물어 필요시 검색해서 사용하자
여기  >>>>  :http://ebcban.tistory.com/152

* 기본문법
- 객체는 정적 또는 동적으로 선언할 수 있다. 
- 정적 유형 객체는 클래스 포인터로 선언된다. 
- 동적 유형객체는  id 로 선언된다 
- 인스턴스 매서드의 선언은 ' - ' 표시하고 마이너스 다음 공백은 생략할 수 있다. 
   클래스 매서드는 ' + ' 로 표시 
- 매서드가 반환하는 값의 유형은 '-/+' 표시와 매서드 이름 사이에 괄호를 묶어 표현한다. 
  반환값이 없는 매서드는 void의 반환 타입을 가져야 한다. 

- (void) modifyArray ; 

- 매서드 인수의 유형은 괄호로 묶고, 인수의 키워드와 인수 사이에 배치한다. 

- (id)initWithName:(NSString*)name_type:(int)type;

- 마무리는 ' ; ' 로 한다 

* 클래스의 정의
- 오브씨에서는 클래스를 크게 두 부분으로 나누어 정의 할 수 있다. 

1. 인터페이스 (interface) : 클래스의 매서드와 인스턴스 변수를 선언하고, 필요하다면 클래스의 슈퍼클래스를 정의한다. 헤더파일
2. 구현 (implementation) : 실제로 클래스를 구현하는 부분이다. 여기서 인터페이스에서 선언한 함수들의 실제 동작을 구현하게 된다. 구현파일

- 일반적으로 클래스의 인터페이스는 '클래스이름.h' 파일에 선언된다. 이 헤더 파일은 핻ㅇ 클래스를 사용하고자 하는 부분에서 임포트(Import) 될 수 있다. 
- 클래스를 구현하는 코드를 '클래스이름.m' 파일에 저장된다. 이 코드는 프레임웤, 동적공유 라이브러리, 정적 라이브러리 또는 구현 파일의 형태로 클래스를 내장한 프로그램이 컴파일 될 때 사용된다. 
- 매서드 선언이나 구현은 ' -' 나 ' + ' 표시로 시작한다. 마이너스 표시는 인스턴스, 플러스는 클래스 객체에서 사용을 의미한다. 
- 매서드 구현 시 그 매서드가 정의된 클래스에 속한 객체에 한하여, 그 객체의 인스턴스 변수를 직접 참조 할 수 있다. 
- 매서드는 수신객체를 self로 지칭할 수 있고 이 변수는 객체가 자신의 매서드 정의 내에서 객체 자신에게 메세지를 보낼 수 있게끔 해준다. 

1. 클래스 인터페이스 : *.h파일
클래스는 @interface 와 @end 사이에 정의한다.