프로그래밍/Objective-C2010. 7. 16. 11:52
* 애니메이션의 또 다른 방법

  - CATransition : 다른 프레임워크를 사용
  - UICalloutView : 유저들이 만들어버린 것. 헤더파일 형태로 제공. 주로 풍선 도움말 같은 것을 만들 때 쓴다. 유저들이 만들었기 때문에 공식적인 애플의 SDK가 아니고, 각각의 소스마다 형태가 약간씩 다를 수 있다. 사실상 UIView에서 상속받아 만들어지는 형태가 대부분임.

* CATransition

  - Core Animation Transition의 약자임.
  - 뷰가 아니라 뷰를 담는 레이어에서 동작함
  - Quartz 코어 프레임워크에서 제공되므로 QuartzCore.framework를 링크하고, QuartzCore/QuartzCore.h 파일을 import 해주어야 함

* CATransition 타입

  - kCATransitionFade : 서서히 사라지는 효과. subtype 없음
  - kCATransitionMoveIn : 레이어가 미끄러지듯이 나타남. subtype으로 kCATransitionFrom의 방향을 지정할 수 있음
  - kCATransition

* 뷰 컨트롤러

  - 뷰 관리 모델을 담당하는 가장 기본적인 클래스
  - UITabBarController나 NavigationController도 이러한 UIViewController로 부터 상속 받아서 만들어진다
  - 프로퍼티
UIView *view: 화면에 출력될 뷰
UINavigationController *navigationController
UITaBarController *tabBarController
UIViewController *modalViewController
NSString * title     <- NavigationController에서는 제목으로 화면에 출력되며 일반적으로는 뷰의 이름입니다.

* 인터페이스 빌더를 써서 xib 파일에 만들어진 뷰(IBOutlet을 사용하는 뷰)는 awakeFromNib를 통해서 로드된다.

* 그냥 코딩으로 구현된 뷰(IBOutlet이 없는 뷰)는 loadView 메소드를 통해서 로드된다.

* 뷰 화면과 관련된 메소드

  - viewDidLoad : 뷰가 로딩된 후 호출
  - viewWillAppear:(BOOL)animated : 뷰가 화면에 나타나기 직전에 호출
  - viewDidAppear:(BOOL)animated : 뷰가 화면에 나타나고 애니메이션이 종료된 후 호출
  - viewWillDisappear:(BOOL)animated : 뷰가 화면에서 사라지기 직전에 호출
  - viewDidDisappear:(BOOL)animated : 뷰가 화면에서 사라지고 난 후 호출

* 뷰의 방향 전환과 관련된 메소드

  - (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
  - 이 메서드의 return 값이 YES이면 방향 전환을 지원하고 NO이면 지원하지 않는다
  - UIInterfaceOrientation은 회전 방향 열거형이다
  - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration : 방향 전환이 이루어지기 직전에 호출되는 메소드
  - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation : 방향 전환이 끝난 후 호출되는 메소드

* Touch 이벤트

   - UIResponder로부터 상속받는 모든 객체에서 발생하는 이벤트. 메소드 재정의만 하면 사용 가능하다
   - UITouch: 터치에 관련된 정보를 저장하기 위한 클래스로 아래와 같은 멤버를 소유하고 있다
NSTimeInterval timestamp: 터치가 발생한 시간을 저장하는 프로퍼티(readonly)
UITouchPhase phase: 터치의 상태를 저장하는 프로퍼티(readonly)로 값은 UITouchPhaseBegan, UITouchPhaseMoved, UITouchPhaseStationary, UITouchPhaseBeganEnded, UITouchPhaseCancelied
NSUInteger tapCount: 터치 한 횟수
UIView *view: 터치가 최초로 발생한 뷰
UIWindow *window: 터치가 최초로 발생한 윈도우
(CGPoint)locationView:(UIView *)view     <– view좌표계에서 터치한 위치
(CGPoint)previousLocationView:(UIView *)view      <– view좌표계에서 터치한 이전 터치의 위치 정보

   - UIEvent: 하나 이상의 터치 정보를 가지고 있는 클래스로 UITouch 객체들을 NSSet 의 형태로 저장해서 반환하며 아래와 같은 프로퍼티와 메서드 소유
NSTimeInterval timestamp: 터치가 발생한 시간을 저장하는 프로퍼티(readonly)
-(NSSet *)allTouches: 모든 UITouch 객체
-(NSSet *)touchesForWindow:(UIWindow *)window: window에서 발생한 모든 터치 객체

  - UIResponder의 터치 이벤트 메서드
- (void)touchedBegan:(NSSet *) touches withEvent:(UIEvent *)event;  <- 터치가 시작할 때 발생
- (void)touchedMoved:(NSSet *) touches withEvent:(UIEvent *)event;  <- 터치해서 이동하는 중에 발생
- (void)touchedEnded:(NSSet *) touches withEvent:(UIEvent *)event;  <- 터치를 마치면 발생
- (void)touchedCancelled:(NSSet *) touches withEvent:(UIEvent *)event;  <-터치 중 시스템 이벤트가 발생한 경우 발생

  - 멀티 터치는 객체의 MultipleTouch 속성이 YES 일 때만 가능
 
  - 멀티 터치를 지원하기 위해서는 view의 User Interaction Enabled 속성이 YES, Multiple Touch 속성이 YES 여야 한다




Posted by windship
프로그래밍/Objective-C2010. 7. 15. 09:45
* 스크롤 뷰

  - 컨텐츠 사이즈가 뷰 사이즈보다 클 경우 스크롤 기능을 이용해서 보여줄 수 있는 뷰
  - 자체적으로 줌 기능을 가지고 있기 때문에 한번에 보여주는 크기인 Frame 사이즈와 전체의 컨텐츠 크기인 ContentsSize 2가지의 사이즈를 설정해야 한다
  - 인터페이스 빌더는 기본 뷰 이상의 크기를 편집할 수 없기 때문에 스크롤 뷰는 인터페이스 빌더로 설정하기 어렵다(코딩으로 만든다)
  - 항상 setScrollEnabled 속성을 Yes로 주어야만 스크롤이 가능해진다 <-- 주의!
  - 이미지의 사이즈는 직접 계산할 필요가 없다. Xcode의 Resources에만 등록해 두면 알아서 크기와 사용 용량을 알아서 구한다

  - 예제 1: 스크롤 없음
-(void)loadView 
{
 UIImage* image = [UIImage imageNamed:@"tri2.jpg"];  // 이미지 파일로 UIImage 객체를 생성
 UIImageView * imageView = [[UIImageView alloc]initWithImage:image];  // UIImage 객체를 기반으로
                                                                                     // UIImageView 객체를 생성
                                                                                     // (frame - (0,0,가로크기,세로크기)
 [imageView setUserInteractionEnabled:YES];  // ImageView가 사용자의 터치 이벤트를 받을 수 있도록 설정
                                                                   // (없으면 터치 이벤트 사용 못함)  <-- 중요!
 [image release];  // UIImage 객체를 release. viewController나 view는 다른 객체
 self.view = imageView;
 [imageView release];
}

  - 예제 2: 스크롤 가능
- (void)loadView 
 {
UIImage* image = [UIImage imageNamed:@"tri2.jpg"];
UIImageView * imageView = [[UIImageView alloc]initWithImage:image];
[imageView setUserInteractionEnabled:YES];
CGSize imageSize = [image size];
[image release];
CGRect rect;
rect.origin.x = 0;
rect.origin.y = 0;
rect.size.width = 320;
rect.size.height = 480;
UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:rect]; // ScrollView를 한번에 보여주고자 
                                                                                                         // 하는 크기만큼으로 설정
[scrollView setScrollEnabled:YES]; // 스크롤을 가능하도록 설정
[scrollView setContentSize:imageSize]; // 전체 컨텐츠 크기를 대상 이미지 크기만큼으로 설정
[scrollView addSubview:imageView]; // 스크롤뷰에 출력할 컨텐츠를 설정
[imageView release];
self.view = scrollView; // 현재 뷰는 스크롤 뷰로 설정
[scrollView release];
 }

  - 줌 기능을 사용하려면 줌의 최대, 최소 사이즈를 추가로 지정해 주어야 한다
  - delegate에 메소드를 가지고 있는 객체를 지정해 줘야 하며, UIScrollViewDelegate 프로토콜을 따른다
  - 뷰는 가만히 있지만 그 안에 보여지는 컨텐츠가 줌을 수행하는 것

  - 예제 3: 줌 기능 추가
~~~ViewController.h 파일

#import <UIKit/UIKit.h>

@interface _715_1ViewController : UIViewController <UIScrollViewDelegate> 
{
UIImageView * returnView;
}

@end

~~~ViewController.m 파일 #1

- (void)loadView 
 {
UIImage* image = [UIImage imageNamed:@"tri2.jpg"];
UIImageView * imageView = [[UIImageView alloc]initWithImage:image];
[imageView setUserInteractionEnabled:YES];
CGSize imageSize = [image size];
[image release];
CGRect rect;
rect.origin.x = 0;
rect.origin.y = 0;
rect.size.width = 320;
rect.size.height = 480;
 UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:rect]; // ScrollView를 한번에 보여주고자 
                                                                                                         // 하는 크기만큼으로 설정
[scrollView setScrollEnabled:YES]; // 스크롤을 가능하도록 설정
[scrollView setContentSize:imageSize]; // 전체 컨텐츠 크기를 대상 이미지 크기만큼으로 설정
[scrollView addSubview:imageView]; // 스크롤뷰에 출력할 컨텐츠를 설정
 
scrollView.maximumZoomScale = 2.0f;
scrollView.minimumZoomScale = 0.5f;
 
scrollView.delegate = self;
 
returnView = [imageView retain];
 
[imageView release];
 
self.view = scrollView; // 현재 뷰는 스크롤 뷰로 설정
 
[scrollView release];
 }

-(UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
{
return returnView;
}

~~~ViewController.m 파일 #2

UIImage* image = [UIImage imageNamed:@"tri2.jpg"];
UIImageView * imageView = [[UIImageView alloc]initWithImage:image];
returnView = [imageView retain];
[imageView setUserInteractionEnabled:YES];
CGSize imageSize = [image size];
[image release];
CGRect rect;
rect.origin.x = 0;    rect.origin.x = 0;
rect.size.width = 320;  rect.size.height = 480;
UIScrollView *scrollView = [[UIScrollView alloc]initWithFrame:rect];
[scrollView setScrollEnabled:YES];
[scrollView setContentSize:imageSize];
[scrollView addSubview:imageView];
[scrollView setMaximumZoomScale:2.0];
[scrollView setMinimumZoomScale:0.5f];
[scrollView setDelegate:self];
[imageView release];
self.view = scrollView;
[scrollView release];

-(UIView*)viewForZoomingInScrollView:(UIScrollView*)scrollView
{
return returnView;
}


* UIView Animation

  - 위치변화, 크기변화, 투명도변화, 회전 등이 가능
  - +(void)beginAnimations:(NSString *)animationID context:(void *)context    <-- 시작 구문
  - +(void)commitAnimations   <-- 종료 구문
  - 위 2개 메소드 사이에 애니메이션의 효과를 지정하면 된다
Posted by windship
프로그래밍/Objective-C2010. 7. 14. 09:38
* View의 생성방법

  1. 코드로 생성하는 방법  
     - UIView * 객체명 = [[UIView alloc]initWithFrame : (CGRect)rect];
        rect 부분은 CGPoint Origin(CGFloat x, y), 또는 CGSize Size(width, height) 등으로도 가능
     - [window 객체 addSubview : 뷰 객체명];
     - 코드로 생성시, xib 파일을 사용하는 부분이라면 m 파일의 loadview 부분에서 생성하면 안되고 viewDidLoad 부분에서 해야 한다.

- (void)viewDidLoad 
{
UIButton * button = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 150, 30)];

[button setTitle:@"버튼" forState:UIControlStateNormal];   // 버튼의 초기 타이틀 설정. 

[self.view addSubview:button];   // 버튼을 현재 뷰 컨트롤러의 뷰의 서브뷰로 초기화함
[button release];    // SubView가 NSArray * 타입이라서 추가나 제거가 될 때 
                                    // retain과 release를 자동으로 수행하게 된다.
                            // 따라서 임시 변수를 이용해서 대입했다면 반드시 release를 해야 한다.
[button addTarget:self action:@selector(redView) forControlEvents:64];    // 버튼의 TouchUpInside  
                                                                                                                   // 이벤트에 redView 메소드를 
                                                                                            // 연결
    [super viewDidLoad];
}

-(void)redView
{
self.view.backgroundColor = [UIColor redColor];
}

  2. 인터페이스 빌더로 생성하는 방법
     - 인터페이스 빌더로 뷰를 생성하고 IBOutlet으로 멤버 변수와 연결한다
     - 만들기는 가장 쉬우나 사후 관리가 귀찮음

  3. UIView로부터 상속받는 클래스를 생성해서 사용자 정의 뷰를 만든 후 사용하는 것
     - 사람마다 필요로 하는 기능이 모두 조금씩 다를 수 있기 때문
     - 만들고자 하는 것이 기본적인 모양이 아닐 경우 이 방법을 사용해 만든다
     - 주로 테이블 뷰에 가장 많이 사용하게 된다(사람들마다 셀을 사용하는 형태가 다르기 때문)


* Objective-C의 콜렉션 : NSArray, NSDictionary, NSSet
  - 삽입이나 삭제시에 retain 과 release 이용


*  IBAction과 void는 기본적으로 같다. 인터페이스 빌더에서 인식하느냐 못하느냐의 차이일 뿐. 둘 다 리턴값이 없다.


* 인터페이스 빌더의 버튼 이벤트를 코딩으로 구현하려면 열거형으로 해서 값을 줘도 된다. (UIControlEvents 도움말에 잘나와있음)


* 앱 만들때 배경그림 까는 법
  - 인터페이스 빌더에서 Image View를 배경화면 크기로 깔아버리고 시작


* NSArray 오브젝트들의 배열

  1. 생성
    arrayWithObject : 객체
    arrayWithObjects : 객체 나열, nil
    arrayWithArray : 배열명

NSArray * ar = [NSArray arrayWithObjects : @"1", @"2", @"3", nil];
NSArray * ar1 = [NSArray arrayWithArray : ar];    <-- COPY이다.

ar1 = ar;
ar1 = [ar retain];      <-- 동작결과는 똑같지만 이게 더 좋은 방식. release에 있어서 더 자유롭다.

  2. 초기화
   array -> init
   공간은 있지만 데이터가 없는 경우임

  3. 추가 및 삭제
   -(NSArray *) arrayByAddingObject : 객체
   -(NSArray *) arrayByRemove : 객체

원래 3까지 있는 배열 ar을 만들고

[ar arrayByAddingObject : @"4"] <-- 이렇게 하면 가상본을 만들어서 4를 추가한다.
ar = [ar arrayByAddingObject : @"4"] 로 하여 다시 한번 ar에 집어넣어야 한다.

추가를 해서 처음에 정해진 배열크기보다 큰 부분에 데이터가 들어오면 자동적으로 원래 배열이 아니라 다른 곳에 큰 배열을 만들어서 추가해 버린다(위에서 말한 가상본). 실제 기기에서는 이런 부분이 메모리를 낭비하게 되어 아주 치명적인 누수를 일으킨다. 따라서 위의 방법은 사용하지 않는다.

NSArray * temp = [ar arrayByAddingObject : @"4"];
...
[ar release];

ar = [temp retain];
[temp release];

이것이 Objective-C에서 가장 일반적으로 배열을 만들고 추가/삭제를 하는 방법이다.

  4. 멤버 접근

   1) index 이용 :
      -(id)ObjectAtIndex:(id)index
      멤버 접근에 가장 쉽고 일반적인 방법

   2) Enumerator 이용:
      -(NSEnumerator *)ObjectEnumerator
      반복자. 어떤 형태의 멤버에든 접근하기 쉽게 하기 위해서 만들어진 것.
      배열은 규칙적으로 반복되기 때문에 읽기가 쉬우나, 실제 프로그램 작성시에는 그렇게 자료가 규칙적인 경우가 많지 않다.
      이 때문에 반드시 배워야 하는 개념이 Linked List. 이 경우에는 규칙적이지 않으므로 인덱스를 사용하지 못한다.
      무엇인가에 각각의 멤버의 주소만 전부 가지도록 하게 만들면 그 이후부터는 그것만으로 모든 멤버를 참조할 수 있다
      
NSEnumerator * 변수 = [ar ObjectEnumerator];

id sender;

while((sender = [변수 nextObject])!=nil)
{
...
}

   3) for ~ in 사용가능:

id sender;   // <-- 데이터 타입이 무엇이 들어있을지 모르기 때문에 대부분의 타입을 받을 수 있는 id 형을 사용

for(id sender in ar)

    자료들의 크기가 커지면 커질수록 속도면에서 유리해지는 방법이다.


  5. 배열의 요소 개수

    -(NSInterger) count



* 2차원 배열

  - Objective-C에서는 기본적으로 2차원 배열이 없다.
  - 때문에 2x2의 배열을 만든다고 할 경우는 이렇게 한다.

NSArray * ar1 = [NSArray arrayWithObjects: @"1", @"2", nil];
NSArray * ar2 = [NSArray arrayWithObjects: @"3", @"4", nil]; // 2개의 1차원배열을 만든 뒤

NSArray * ar = [NSArray arrayWithObjects: ar1, ar2, nil]; // 그 배열 2개를 모아 다른 배열을 선언

[ar1 release];
[ar2 release];

  - 주의

NSArray * copyAR = [NSArray arrayWithArray: ar];
ar = [ar arrayByAddingObject: ar3];
[[ar ObjectAtIndex: 0] arrayByAddingObject: @"10"];

  - 흔히 얕은 복사라고 함. 한번의 복사만을 해준다.
  - 이것을 방지하기 위해서는 메모리 상의 처리보다 파일처리 같은 외부 기억장소로 빼내서 처리하는 방법을 이용하는 것이 좋다


* ImageView

  - 이미지 한 장을 화면에 출력하기 위한 정적인 뷰. 이벤트 사용할 수 없다
  - Image 속성을 이용해 이미지 리소스를 연결한다
  - contentMode 속성으로 배치 모양을 결정한다
      UIViewContentModeScalToFill : 프레임의 긴 쪽에 맞춰서 확대/축소
      ScaleAspectFit : 작은 쪽에 맞춰줌 . 가로/세로 비율을 맞춰서 확대/축소

Posted by windship
프로그래밍/Objective-C2010. 7. 12. 09:29
* 컨트롤
  - UIKit가 제공하는 재사용 가능한 작은 부품
  - 일종의 뷰라고 할 수 있다
  - UIButton, UIDatePicker, UIPageControl, UISegmentControl, UITextField, UISlider, UISwitch...
  - 능동 컨트롤 : 사용자의 실제 이벤트를 연결하는 컨트롤. 일반적으로 버튼 등이 해당
  - 정적 컨트롤 : 
  - 수동 컨트롤 : 일반적으로 텍스트 필드 등이 해당

* UILabel
  - 정적 텍스트를 출력하기 위한 읽기 전용 뷰로 UIView로부터 상속. 컨트롤이 아님.
  - UIresponder로부터 상속받은 속성은 사용이 가능하지만 UIControl에 있는 이벤트는 사용 불가
  - 간단한 텍스트를 출력하기 위한 용도로 사용
  - lineBreakMode 프로퍼티가 중요. 출력 영역을 벗어났을 때의 처리.
  - numberOfLines : 몇줄까지 출력 가능한가라는 의미

* 타이머(NSTimer)
  - 일정 주기, 일정 시간에 대한 기능을 사용할 때 쓰는 클래스
  - NSTimer.h에 정의되어 있으나, Foundation에 포함되어 있으므로 기본적으로 인클루드는 안해도 된다.
  - +(id) scheduledTimerWithTimeInterval : 실행주기 Target : 수행할 메소드가 있는 객체 selector : @selector(수행할 메소드) userinfo : (id)부가 정보를 저장할 객체 repeats: (BOOL) 반복여부];
  - 수행할 메소드가 있는 객체 : 대개는 self
  - 수행할 메소드 : 시간이 되었을 때 수행할 명령. 매개변수도 없고 리턴값도 없어야 함
  - 반복여부 : yes / no
  - 타이머 종료시에는 invalidate 메소드를 호출해서 무효화시킴.

* 인터페이스 빌더로 만든 것은 dealloc으로 해제
* 프로퍼티를 만든 것은 synthersize로 해제

* UITextField
  - 사용자로부터 키보드 입력을 받기 위한 컨트롤
  - 문자가 아니라 숫자만 입력하면 될 경우는 Number Pad로 변경한다

* 키입력시 키보드가 화면을 가려버리는 문제의 해결
  1. 특정 키를 누를 때 키보드에 할당된 입력 이벤트를 강제로 회수해 버리면 된다
      - < UITextFieldDelegate>프로토콜을 따르도록 설정하고 (Bool)textFieldShouldReturn:(UITextField*)theTextField 메서드에서 매개변수가 resignFirstResponder 메서드를 호출
  2. Did End on Exit 이벤트를 이용
  3. 텍스트 필드에 이벤트가 발생할 때 버튼을 화면 위로 올리
  4. 뷰 클래스나 뷰 컨트롤러 클래스에서 터치 이벤트를 이용해서 텍스트 필드에서 FirstResponder를 해제


Posted by windship
* 아이폰 프로젝트의 구조

  - MainWindow.xib : UI가 만들어지는 출발
  - File's Owner : 각종 디자인 객체들을 제어하기 위한 클래스  
  - First Responder : 현재 활성화되어 사용자로부터 무엇인가 리액션을 받고 있는 객체의 클래스. 어떤 개체(예를 들어 키보드)가 First Responder가 되면 가상키보드가 뜨고 사용자로부터 입력을 기다린다. 프로그램에서 키보드의 First Responder를 해제하면 자동으로 키보드가 사라진다
  - XCode와 인터페이스 빌더는 별개의 프로그램이므로, 인터페이스 빌더에서 만든 객체와 XCode 상의 코드를 연결시키는 작업을 해 주어야 한다. 하지만 XCode의 모든 코드들이 인터페이스 빌더로 넘어오지는 못한다. 이 때문에 IBOutlet(변수)과 IBAction(메소드) 키워드가 존재한다. 이것이 붙으면 인터페이스 빌더에서 인식하게 되며, XCode상에서는 별다른 의미를 갖지 못한다(타입도 void임)
  - 주 실행이 되는 main 함수는 main.m에 위치하게 된다
  - AppDelegate : 주 프로그램 실행을 위한 처리들을 담당. 시작하기 전에 팝업창을 띄워 뭔가를 확인한다든가 할 때에 사용한다. 다른 모든 클래스는 File's Owner에 있지만 유일하게 윈도우에 대한 것은 AppDelegate에 있다
  - UIApplication : 아이폰에서 실행되도 좋은 프로그램인지 검사
  - WillTerminate : 종료 직전에 호출되는 메소드. 프로그램 종료 후 나중에 다시 실행했을 때 마지막에 하고 있던 작업이 그대로 남아있게 하는 처리를 여기에서 한다. 같은 이유로 프로그램 종료시에 없어져야 하는 객체, 해제해야 하는 메모리의 작업도 여기에서 해 주어야 한다. 이때 뜨는 윈도우의 디자인을 바꾼다거나 할 때에는 //Override point for customization after app launch 주석 바로 다음에 해준다.
  - [window addSubview:viewController.view];  <-- 뷰 위에는 얼마든지 다른 것이 올라갈 수 있지만 윈도우는 하나밖에 깔 수 없다


* 인터페이스 빌더의 xib 편집창
  - 기본적으로 항상 가운데의 계층형으로 창 표시 타입을 놓고 보는 버릇을 들이자


* 변수 연결하기
  - IBOutlet으로 지정해서 인터페이스 빌더와 연결
  - dealloc으로 해제


* Inspector 창 - 첫번째 탭 속성창
  - Drawing - Opaque를 체크 : 뒤쪽을 투명하지 않게 하므로 속도가 빨라진다. 다만 텍스트 필드에서는 사용하지 않는 것이 좋다
  - Clear Context Before Drawing : 무엇인가 객체를 그릴 때 뒤쪽을 지우고 새로 그리는가 아닌가를 설정
  - Clip Subview : 화면상에서 보이지 않는 부분을 그리지 않는다. 
  - Interaction - User Interaction Enabled : 유저 터치 입력을 받는다. 항상 켜두어야 함
  - Multiple Touch : 멀티터치 입력을 가능하게 한다


* XCode - .plist 파일
  - 아이콘에 쓸 png파일은 Finder에서 찾아서 XCode의 Resources 트리에 끌어다 놓으면 등록된다
  - plist 파일의 Icon file 란에 등록한 파일명을 입력하면 완료
  - 아이콘 사이즈는 60x60 이상을 넘어가면 안된다
  - 이미지는 기본적으로 확대/축소에 기대하지 말고 큰 것과 작은 것을 두개 다 준비해 두는 것이 좋다
  - Bundle이라는 용어가 많이 등장하는데 기본적으로 '내 애플리케이션'을 일컫는다고 생각하면 된다
  - Bundle Version을 사용해서 버전번호를 표기한다. 업데이트가 필요할 때에도 아이폰이 이 버전번호를 비교하여 업데이트 여부를 유저에게 알려주게 된다
  - plist 파일은 우클릭한 뒤 Open as -> Plain Text File 하면 XML 파일로 읽게 된다


* 디자인 패턴
  - 이벤트를 생성하는 것을 디자인 패턴이라고 한다

  - Delegation : 하나의 객체가 delegate 지정된 다른 객체에 주기적으로 메시지를 전달 -> 메시지를 처리할 수 있다면 처리해 달라고 요청하는 것
  - 상위 클래스로부터 모두 상속받아서 사용하는 것이 아니라, 원하는 클래스 이름에 delegate를 붙여서 그 클래스의 원하는 부분만 선택(프로토콜)하여 받아오는 것
  - -(void)applicationDidFinishLaunching:(UIApplication *)application
  - -(void)applicationWillTerminate:(UIApplication *)application

  - MVC 패턴 : 모션, 뷰, 컨트롤러로 구별해서 동작을 정의한다 . 테이블 뷰 형식의 프로그램을 이 방식으로 한다.

  - Target-Action 패턴 : 객체에 메시지를 보내서 객체를 제어하게 한다. 일반적으로 이벤트 처리에 가장 많이 사용된다
  - IBAction 키워드를 사용해서 넘기면 이 방식이 된다 . 리액션에 따라 개체가 바뀌는 경우(눌리는 버튼 등)에는 원래의 자기 객체가 무엇인지도 기억해놓고 있어야 하므로 -(IBAction) click(id)sender와 같이 sender를 사용해줘야 한다. 이 때에는 형변환을 해줘야 한다
  - 코딩으로 만들어도 된다. [객체 AddTarget : 메소드소유객체명 action : @selector(메소드명) forControlEvents : (UIControlEvents) 이벤트 이름 과 같은 형식이 된다
  - 소유 객체명은 Target-Action 방식에서는 거의 self가 되지만 MVC 패턴에서는 소유 객체와 구현부가 다르므로 self를 사용할 수 없다는 것에 주의


* 윈도우기반 어플리케이션
  - 기본적으로 윈도우 하나만이 존재한다
  - 만든 뒤 UIViewController의 서브클래스를 추가
  - 새로 클래스파일을 추가할 때에 3개의 옵션 체크가 중요하다(xib 파일도 함께 만드느냐 그렇지 않느냐 등등)
  - xib 파일도 함께 만들면 처음에는 classes 폴더에 함께 생기므로 Resources 폴더로 옮겨 준다


* 예제 - AppDelegate.h

//
//  _709_2AppDelegate.h
//  0709_2
//
//  Created by iMac2_13 on 10. 7. 9..
//  Copyright __MyCompanyName__ 2010. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "TestViewController.h" // 추가한 뷰 컨트롤러의 헤더 파일을 import함

@interface _709_2AppDelegate : NSObject <UIApplicationDelegate> {
    UIWindow *window;
TestViewController * viewController; // 윈도우에 추가할 뷰 컨트롤러의 변수 선언
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@property (nonatomic, retain) TestViewController * viewController; // 추가한 뷰 컨트롤러의 멤버에 쉽게 접근하기 위한 프로퍼티 설정

@end


* 예제 - AppDelegate.m

//
//  _709_2AppDelegate.m
//  0709_2
//
//  Created by iMac2_13 on 10. 7. 9..
//  Copyright __MyCompanyName__ 2010. All rights reserved.
//

#import "_709_2AppDelegate.h"

@implementation _709_2AppDelegate

@synthesize window;

@synthesize viewController; // 프로퍼티로 지정한 변수의 synthersize 지정


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    

    // Override point for customization after application launch

viewController = [[TestViewController alloc]init]; // 추가한 뷰 컨트롤 변수에 메모리 할당, 초기화
[window addSubview:viewController.view]; // 윈도우에 추가한 뷰 컨트롤러의 뷰 붙이기. 중요함!
    [window makeKeyAndVisible];
return YES;
}


- (void)dealloc {
[viewController release]; // 지정한 인스턴스 변수 release
    [window release];
    [super dealloc];
}


@end


* 이벤트 객체 알아내기

  - IBOutlet 변수 이용하기
  - 어떤 메소드로부터 호출된 것인지 알기 위해서 Tag라는 속성을 줄 수도 있다. 다만 이 경우에는 절대로 같은 Tag를 설정해 주면 안된다. 
  - Tag를 사용하게 되면 IBOutlet은 쓸 필요가 없어진다
  - 
Posted by windship
* selector

  - 오브젝티브 C에서 C 언어의 함수 포인터나 다른 언어에서의 delegate에 해당하는 기능
  - 다형성을 구현하기 위해서 사용.
  - 메소드를 실행시 동적으로 결정하기 위한 개념. 이 때문에 없는 매개변수를 참조하거나 하면 에러 메시지를 발생시키는 것이 아니라, 실행하고 나서야 변수를 찾아보고 없으면 바로 튕겨 버린다
  - 자료형일 때에는 SEL
  - 대입할 때에는 @selector(메소드명)으로 메소드의 주소를 리턴받아서 대입시킴
  - 매개변수가 있을 때에는 @selector(메소드명:)   <-- 콜론이 붙는 것에 주의
  - 셀렉터에 지정되는 메소드는 반드시 매개변수가 객체여야 한다.

-(void)Disp;                 <- 가능
-(void)Disp:(id)sender; <- 가능
-(void)Disp:(int)n;       <- 불가능

  - 사용예
    [ 객체 performSelector : (SEL) 변수];

    SEL dele;
    if(조건)
      dele = Disp;
    else
      dele = Print;

    [객체 performSelector : dele];


[객체 addTarget : delegate action : @selector(메소드)];

* 다형성 구현에 대한 개념

if(sel == 1)
  dele = @selector(Disp);
else
  dele = @selector(Print);
[Obj performSelector : dele];

  - 위 소스에서 sel 이 1이라면 Disp를, 아니라면 Print를 수행한다
  - 이와 같이 아래의 한 문장이 여러 가지 기능을 수행할 수 있도록 하기 위해 다형성을 구현한다
  - 보통의 C 에서는 오버라이딩을 통해 다형성을 구현하지만 이것은 상속받지 않으면 사용할 수 없다는 단점이 있다
  - 그 때문에 오브젝티브 C에서 새로 도입된 개념이 selector 이다

@interface Test:NSObject

-void(Disp);
@end

@implements Test
-void(Disp)
{
  NSLog(@"Hello");
}
@end

int main()
{
  Test * Obj = [Test new];
  [Obj Disp];

  if([Obj respondsToSelector : @selector[Disp)] == YES)
    [Obj Disp];
  else
    {예외 발생};

  return 0;

  - Disp라는 함수가 구현이 되어 있을 경우는 문제가 없지만 위와 같이 코딩을 해두면 Disp가 없어서 예외가 발생했을 경우에 대한 처리가 가능해진다
  - 기본적으로 여러 사람에 의한 공동 작업을 상정해 만들어진 기능이라고 생각하면 된다

* 카테고리

  - 클래스의 기능을 확장하기 위해 일부 메소드를 구현한 모듈을 말한다 . 사용자 정의 클래스나 프레임워크가 제공하는 클래스의 기능을 확장하고 싶을 때에 사용한다(즉 기본 SDK에서 제공되는, 사용자가 마음대로 고칠 수 없는 것들을 좀 편하게 사용할 때에 주로 사용한다)
  - 기존 클래스의 정의를 변경하지 않은 상태에서 원하는 메소드만 추가하여 사용할 수 있다
  - 인스턴스 변수의 선언은 할 수 없다(할당받는 메모리의 사이즈가 달라져 버리므로)
  - 기본적으로 원래의 클래스를 import로 가져온 뒤 별도의 소스 파일을 하나 추가해서 두개를 더한 클래스를 만들어 버리는 방식이다

* 프로토콜

  - 아이폰 SDK의 프로토콜 이름은 거의 대부분 사용자가 유추할 수 있다

<클래스명 Delegate>
<클래스명 Datasource>

  - Did나 Will로 시작되는 것들도 많다
  - 어떤 메소드를 사용해야 하는지를 프로토콜 이름을 보고 추정하여 찾아가는 습관을 갖는 것이 좋다
  - 프로토콜 적용

@interface 클래스명 : 슈퍼클래스명<프로토콜 이름>

  - 프로토콜도 상속이 가능하며, 콤마로 구분하여 여러개를 붙여서 다중 상속도 가능하다

* 인스턴스와 매개변수의 제약
  - 인스턴스 변수 선언시 오브젝티브 C는 id 타입으로 선언하면 아무 제약 없이 모든 클래스의 인스턴스를 생성할 수 있다
  - 이 때 생성되는 인스턴스에 제약을 가하고자 하는 경우에도 프로토콜을 사용할 수 있다. 이렇게 되면 동적이 아니라 정적으로 타입을 점검하게 된다

* 프로토콜의 선택/필수 구분
  - 프로토콜에 선언되는 메소드 앞에 @optional을 적으면 메소드를 구현해도 되고 안해도 된다
  - @required라고 쓰면 반드시 구현해야 한다

* NSObject
  - 최상위 클래스로서 모든 클래스는 여기에서 상속받아 사용해야 한다. 그렇지 않으면 인스턴스를 만들 수 없다

* 메모리 생성과 해제
self = [super init];    // <-- 메모리를 초기화
if(self != nil)        // <-- 초기화가 잘 되었는지 확인
{
   처리내용
}
return self;

  - 굉장히 정형화된 표현으로서 거의 대부분 저런식으로 이루어진다
  - 유저는 거의 처리 내용만을 입력하게 된다

UIButton * button = [[UIButton alloc]init];
버튼 사용
release

  - 직접 코딩으로 버튼을 만드는 경우. 이 경우는 메모리 할당과 초기화 한번으로 끝난다

IBOutlet UIbutton *button
버튼 사용
[[UIbutton alloc]init]retain]
button release

 - 인터페이스 빌더로 만들고 나면 IBOutlet으로 들어가게 되는데, 이 경우는 메모리를 할당한 뒤 그것을 복사하여 2개가 된다. 다 사용하고 뷰를 없앴을 때에는 아래쪽에서 retain 문으로 retain Count가 1 감소하게 되지만 원래의 하나는 남아 있기 때문에 메모리 누수의 원인이 된다. 이런 식으로 했을 때는 반드시 button release를 한번 더 해줘야 한다.

* iPhone SDK

  - 프로젝트 만들 때에 Navigation Based는 주소록 기반이라는 뜻
  - OpenGL ES : 그래픽 처리 관련
  - Split View Based : 아이패드용
  - Tab Bar : 보통 잘 안쓴다. Tab bar는 Navigation Based를 포함할 수 있지만 반대는 안된다.
  - Utility : 주식효과 같은 프로그램에 사용. 화면이 앞뒤로 뒤집어지는 처리를 기본으로 함. 모양새일 뿐 별로 의미는 없다.
  - View Based : 기본적인 화면 하나를 두고 거기에서 처리하는 프로그램.
  - Window Based : 창 하나를 띄우고 거기에 추가하여 만드는 프로그램. 가장 추천이 되고 기본이 되는 타입.

* 프로젝트 설정 후 왼쪽 폴더
  - Classes : 가장 많이 코딩하게 되는 곳.
  - Other Sources : 프로젝트 실행에 관련된 파일들이 존재
  - Resources : 각종 그래픽이나 사운드 등의 외부 자원들이 등록되는 곳. 
                       XIB 파일 : 화면처리와 디자인에 관한 것들
                       plist : 
  - Frameworks : 참조해야 하는 헤더 파일들의 모음
                         UIKit
                         Foundation
                         CoreGraphics
                         위 3가지 이외에도 필요에 따라 필요한 프레임워크를 링크하여 사용할 수 있다.
  - Products : 유저가 만드는 앱이 등록되는 곳.

* 인터페이스 빌더
  - Library : 끌어다 놓음으로서 만들 수 있는 것들.
view에 끌어다 놓아서 화면의 디자인을 할 수 있는 것들이 있고, xib 파일에 끌어다 놓는 컨트롤과 같은 것들도 있다.
  - Inspector : 설정창. 아주 중요하다.
      Attributes : 각종 속성을 설정한다
      Connections : View상에 배치된 객체와 연결시켜서 속성을 설정
      Size : 객체의 위치와 크기 등의 설정
      Class : 객체의 제어권 설정
  - 하나의 작업이 끝나면 인터페이스 빌더는 바로 저장하고 꼭꼭 닫아주는 버릇을 들이는 것이 좋다. 창이 계속해서 새로 떠 버리기 때문에 헷갈리게 된다. 

* 아이폰 시뮬레이터
  - 그냥 Run 하면 나온다(...)
  - 프로젝트를 하나씩 지우는 것은 실제 아이폰에서 하듯이 하면 됨 (아이콘 오래 클릭)
  - 화면 회전은 Command + 방향키
  - 멀티 터치는 Option + 마우스 드래그
  - 왼쪽 위의 버전은 대개 시뮬레이터로 세팅. 3.2는 아이패드용이므로 쓰지말자(...)

* 외부와 연결시 변수는 IBOutlet으로, 액션은 IBAction으로 연결되어야 한다.
Posted by windship
* iPhone에서의 상속은 거의 모두 NSObject 또는 NSProxy로부터 받는다

* id 타입이란 일반 C 코딩에서의 "주소"와 거의 같은 개념이다.

* 실행 중간의 디버깅 및 값 확인은 NSLog를 써서 콘솔 창에서 확인하는 것이 좋다.

* 유저가 만드는 클래스는 크게 2가지 뿐.
  - 데이터 모델 (구조체)
  - 상위로부터 상속받아 사용하는 클래스

* delegate는 상위 클래스나 SDK에 구현되어 있는 기능을 빌려와서 사용할 때 쓰는 것. 거의 대부분은 self(C++ 에서는 this)를 통해 자신을 참조하게 하여 사용한다. 

* 상위 클래스의 멤버와 같은 이름의 멤버를 하위 클래스에서 선언, 또는 재정의(오버라이딩)하면 상위 클래스의 원래 멤버가 가려져서 부를 수 없게 되므로, 자신이 정의한 메소드는 this를 이용해 호출하고 상위 클래스의 원래 멤버는 super를 이용해서 호출해야 한다.

* 대개 아이폰 SDK에 구현되어 있는 기본적 기능을 이용할 경우(메모리나 화면에 관련된 처리) 이러한 super를 이용해 상위 클래스의 멤버를 호출해 오버라이딩을 사용한다.

* typedef
  - 자료형에 별명을 붙일 때 사용하는 예약어.
  - typedef [대상자료형] [별명으로 사용할 이름];

* 전처리기(Preprocessor)
  - 일반적 C와 같음
  - #으로 시작함
  - 꼭 오브젝티브 C의 문법일 필요는 없음
  - 끝에 ; 표시를 쓰지않음

* #define
  - 상수값에 심벌명을 부여한다
  - 연산자의 재정의도 가능. 즉 #define AND &&, 또는 #define SAME == 와 같은 것도 가능하다. 

* 매크로 함수
  - #define 문을 사용해서 수식 을 대치함.
  - 실제의 함수는 아니지만 마치 함수처럼 사용할 수 있기 때문에 매크로 함수라고 부른다.
  - 매크로명을 모두 대문자로 써서 구분하는 것이 일반적.

* C의 배열은 사용가능하지만 가능한 한 사용하지 않는 것이 좋다.
  - 경계가 없다. 첨자가 3인 배열에서 -1이나 10도 넣거나 읽을 수 있다.
  - 값을 잘못 넣으면 기존에 있는 변수의 값을 건드려 바꿔버릴 수도 있다.

* CGPoint, CGRect, CGSize

CGPoint pt;
pt.x = 10;
pt.y = 20;

CGPoint pt = {10, 20};

CGPoint pt = CGPointMake(10, 20);

 CGRect
 {
    CGPoint origin;
    CGSize size;
  }
Posted by windship
* 오브젝티브 C의 클래스
  - NSObject 클래스로부터 상속받는다
  - 선언부와 구현부가 분리되어 있다

* 선언부
@interface 클래스명 : 상위클래스명                            // 클래스는 일종의 Template
 {
      멤버변수 선언;
 }
 +- 메소드 선언;
 @end
 
  - static이나 const를 내부에서 선언할 수 없다. 오로지 멤버 변수만 가능.

* 구현부
@implements 클래스명
+- 메소드 구현
@end

@class NSObject
#import <Foundation / Foundation.h>

* 클래스 선언과 사용
  - 클래스는 무조건 포인터로 받는다
  - 클래스명 * 객체명;       <-- 객체 선언이지만 이 상태에서는 사용할 수 없다.
  - 객체명 = 다른 객체;     <-- Assign
  - 객체명 = [다른 객체 retain];           <-- Retain. Assign과 동작결과는 같지만 복사 구문이 아니다. 참조 카운터만 1 감소시키며,
                                                                할당된 메모리는 그대로 남아 있다. 참조 카운터가 0이 되었을 때 비로소 메모리가 해제
                                                                된다. 메모리 누수의 주된 원인 중의 하나이므로 반드시 메모리 해제를 해 줄것. 특히
                                                                인터페이스 빌더 등을 사용할 때 빈번하게 일어난다.
  - 객체명 = [다른 객체 copy];
  - 객체명 = [클래스명 alloc];             <-- 순수하게 메모리 할당만 받는다
  - 객체명 = [클래스명 new];              <-- 메모리 할당을 받고 초기화까지 해준다
  - 객체명 = [클래스명 allocWithZone : (NSZone *)zone];            <-- 하나의 Heap을 생성한다. 아이폰4의 멀티태스킹 작업에
                                                                                                          유리하게 사용될 것이다.
  - 객체명 = [클래스명 ? with ?];        <-- with라는 단어가 나오면 무조건 생성자나 초기화 역할을 하는 것. 앞에 무엇이 붙는가가 중요하다. 앞에 init가 붙지 않으면 생성자이며, init가 붙으면 초기화이다.

* 같은 기능을 하는 메소드지만 여러가지 종류가 있을 수 있다. 예를 들면
   awakeFromNib
   loadview
   viewDidLoad
  와 같은 것들인데, 결과는 같지만 실행 우선순위와 메모리 해제 시점이 다르기 때문에 이에 따라서 먼저 실행되는 부분이 결과가 나타나지 않는 경우가 많이 발생한다. 이 경우에는 retain 이 사용된 부분을 가장 우선적으로 검토하는 것이 좋다.

* 클래스 추가
  - XCode > File > New File > iPhone OS/Mac OS X > Cocoa Touch Class > Objective-C Class > NSObject를 선택.
  - 이름을 결정하면 class.h와 class.m이 바로 만들어진다.
  - 그러나 대개는 XCode의 왼쪽 구조창 중 class부분에서 오른쪽 클릭을 눌러 추가하는 방식이 일반적이다.

* 함수와 메소드의 차이
  - 함수 : C 스타일 함수, 또는 매크로 함수
  - 메소드 : 클래스 안에 선언된 함수
  - 오브젝티브 C에서는 기본적으로 C 스타일의 함수는 만들지 않는다. 만든다면 거의 매크로임.

* 메소드 선언
(결과형) 메소드 이름 : (자료형) 매개변수 이름  별명 : (자료형) 매개변수 이름

예) -(void) UIApplication : int XXX Section int YYY

  - 메소드 이름 부분은 대개 "누구", "어디" 라는 타겟, 장소를 의미하게 된다.
  - 별명 부분은 대개 "동작"을 의미한다.
  - " - "나 " + "를 붙인다.
  - " - "를 붙일 경우 의미가 인스턴스라는 뜻. 즉 멤버라는 뜻이 된다.
  - " + "가 붙을 경우 클래스라는 뜻.
  - 오버라이딩은 있지만 오버로딩은 없다.
 
* 변수
  - 인스턴스(멤버) 변수 : 클래스 내에서 선언되는 변수. 이 인스턴스 변수에만 접근 지정자 선언이 가능하다. (메소드나 클래스에는 사용 불가. 메소드나 클래스는 무조건 public이다)
     @private : 클래스 내부에서만 사용가능
     @protected : 클래스 내부에서, 그리고 상속받은 클래스에서도 사용가능
     @public : 클래스 내부, 상속받은 클래스, 객체에서 사용가능

  - 지역(Auto)변수 : 메소드 내에서 선언되어 그 안에서만 사용된다. Auto 키워드는 쓰거나 안쓰거나 자유지만 가능한 한 안쓰는 게 좋다.
  - static 변수
  - const 변수
  - static과 const는 File의 개념이므로 큰 의미가 없다
  - extern은 자료 교환을 위한 타입이지만 없어지지 않으므로 위험하다. (윈도우 모바일의 DLL과 비슷함. 한번 로드하면 메모리 해제를 해도 사용만 못하게 될 뿐 계속 남아있으므로 문제가 크다. 거의 사용할 필요가 없음.)

* getter와 setter의 개념
  - 멤버 변수와 메소드의 이름이 같아도 된다(오브젝티브 C만의 특성).
  - getter는 멤버 변수의 이름과 동일하게 사용하는 것을 권장한다.
  - setter는 set 변수명 으로 사용하는 것을 권장한다. 변수명의 첫 글자는 대문자.

{
int result;
}

-(int) result;      //  <-- getter
-(void) setResult : (int) temp;      //  <-- setter

-(int) result {return result;}      //  <-- getter
-(void) setResult : (int) temp {result = temp;}      //  <-- setter

[Obj setResult : 10];
NSLog(@"%d", [Obj result]);


* 프로퍼티
  - 위 방식은 메소드 갯수가 너무 많아지는 단점이 있기 때문에 도입된 것이 프로퍼티이다
  - setter와 getter 를 대신해서 사용할 수 있는 개념

  - 선언 :
   
@property (특성) 자료형 변수명;

    이렇게 씀으로서 setter와 getter의 선언이 완료된다.
    예 : @property int result;
    이것은 스레드 관련 권한의 처리도 겸하기 있기 때문에 권장되는 기능이다.

  - 구현 :

@synthersize 변수명;

    property문을 보고 구현해주는 역할만을 함.
    예 : @synthersize result;

* 프로퍼티의 특성
  - non atomic : 멀티 스레드를 제어하지 않는다. (속도를 빠르게 함) 지금까지는 아이폰에서 멀티태스킹을 할 필요가 없었기 때문에 거의 대부분이 이것을 사용해 퍼포먼스를 좋게 했었지만 앞으로는 이것을 지양해야 할 것이다.
  - setter, getter : 특성은 존재하지만 거의 안쓴다
  - assign, retain, copy : 객체에만 적용된다. 일반 value형 변수들은 값만을 사용하므로 의미가 없고 heap 메모리를 사용할 때에만 필요하다. copy는 "얕은 복사"라고 많이 표현하는데, 배열의 마지막 데이터가 아니라 첫번째 데이터만을 복사한다. 전체를 다 복사하는 "깊은 복사"는 archiving이라고 구분하여 표현한다.
  - read only, read//write : 읽기 전용 속성과 읽기/쓰기 속성. 이런 것이 있기 때문에 const를 사용하지 않는다. 읽기/쓰기 속성은 디폴트 값으로서, 따로 지정해 주지 않으면 이 속성이 되므로 거의 쓰지 않는다.
  - 위 속성들은 " , " 기호로 함께 사용할 수 있다. 다만 그 특성상 함께 쓸 수 없는 것들도 있다.
  - " . " 기호를 이용해서 접근 가능. " = " 기호(assign, 즉 할당 연산자)의 왼쪽에 " . " 기호가 사용되면 자동적으로 set이 호출된다.
    즉,
    [Obj setResult : 10];
    위 구문은
    Obj.result = 10;
    이렇게도 사용할 수 있다.
  - @synthersize _result = result;  <-- C에서 많이 사용되는 관습적 문법. 가능은 하지만 오브젝티브 C에서는 일반적인 문법은 아니다.

* Static 변수
  - 클래스 내부에 생성해서 모든 객체가 공유하기 위한 변수
  - 근본적으로 객체가 사용하게 된다.
  - 객체들 간의 통신에 사용한다.

static int sequence = 1;

-(id) init
{
self = [super init];
if(self != nil)    // 메모리를 제대로 받았는가 검사
{
    result = sequence++;
{
return self;
}
   
 
Posted by windship
* import
  - C/C++의 include와 비슷하지만 몇 가지가 다르다.
  - 몇 번을 선언해도 한번만 실행됨.
  - 아이폰 프로그래밍에서는 거의 Foundation 하나만 import하면 끝난다.

* 앞에 NS가 붙는 것은 NextStep의 약자로 스몰토크 시절부터 내려온 함수라는 뜻.

* NSAutorelease : 아주 중요한 함수. 메모리 할당 후 나중에 drain으로 알아서 해제하겠다는 선언.
  -  [[NSAutorelease alloc] init] : alloc으로 메모리 할당. init로 초기화. 이 두가지를 한번에 하고 싶다면 new로 바꿔 쓸 수 있다.

* NSLog : C의 printf와 거의 같다.
  - NSLog(@"%d", 10);  <-- "%d"는 서식, 10은 데이터. 앞에 @가 붙는 것을 제외하면 같다.
  - C의 printf는 UTF-8 아스키 코드를 출력하지만 NSLog는 유니코드로 출력한다.

* 서식
  - %d, %i, %x, %o, %u
  - %f, %g
  - %c
  - %s : 주소부터 바이트 단위로 읽어서 null을 만날 때까지 문자로 출력
  - %@ : description 메소드 출력. C에는 없고 오브젝티브 C에만 있음. NSString, NSNumber, NSDate는 이것밖에 지원 안한다.

* 오브젝티브C에서는 기본적으로 데이터에 숫자처리는 없고 문자열로 취급한다.
  - 숫자데이터 10과 문자데이터 Hello가 있을 경우 이 둘을 합치고 싶으면 단순히 10 + "Hello" 해 버리면 됨.
  - 숫자데이터 10을 문자열로 바꾸고 싶을 경우 단순히 10 + "" 해버리면 됨.

* 자료형
  - 기본적으로 C의 자료형은 다 사용할 수 있다.
  - Value 타입 : C와 거의 같다. 없는 것은 BOOL 타입. BOOL 타입의 예:1, 아니오:0.
  - Reference 타입 : C의 포인터와 같다. 객체라는 뜻. 대개 주소라서 앞에 *을 붙이지만 id는 *가 붙지 않아도 주소로 받는다.
  - id는 C의 void *와 유사하다. 모든 데이터 타입의 주소를 기억할 수 있다. 동적 데이터 할당 - 자료가 들어올 때 그에 맞게 기억장소를 할당.

int a = 20;
float f = 10.7f;
void * vp = &a;
vp = &f;

  - 이 경우 printf("%d", *vp); 라고 하면 에러가 난다. void *는 시작주소는 기억하지만 사이즈는 기억하지 못하기 때문. 그래서 C언어에서는 (Cint *)vp)와 같이 vp를 int로 형변환을 해서 알아낸다.
  - 그러나 오브젝티브C에서는 자료 저장시에 이미 자료의 크기도 함께 저장한다. 따라서

id x = &a;
printf("%d", *x);

이렇게 하면 가능해진다.
 - 다만 id는 모든 자료타입을 다 받을 수 있기 때문에 차후 관리가 어렵다. 가능하면 사용하지 말고 형변환을 통해 사용하는 것을 추천.

* enum : 열거형 상수.
  - 아이폰 프로그래밍에서 매우 자주 사용하게 됨.
  - enum test {Zero, One, Two}; -> {K=10, Z, A} 와 같이 주었을 경우 Z는 11, A는 12가 된다(초기값부터 시작해 증가하게 됨).

* 연산자와 제어문은 C와 같다.

* 오브젝티브 C의 클래스
  - 선언부와 구현부가 분리되어 있다.
  - 선언부가 .h 파일에 들어가고, 구현부는 .m 파일에 들어간다.
  - 따라서 기본적으로 한 쌍으로 사용되며, 이름도 같은 것이 보통이다.

  - 선언 문법

@ interface 클래스명 : 상속되는 클래스                 // 반드시 상속되는 클래스가 필요하다
{
인스턴스 변수 선언;
}

+- (리턴타입) 메소드명;
@end

  - 구현 문법

@ implementation 클래스명                                   // 상속클래스명은 필요없다
+- (리턴타입) 메소드명;
{
정의
}
@end


* 메소드

  - "-"가 붙으면 인스턴스 메소드(객체).

(리턴타입) 메소드이름 : (매개변수 자료형) 매개변수명

+(void) disp : (int) a
{
    NSLog(@"%d", a);
}

  - 객체 생성
    클래스명 * 객체명 = [클래스명 alloc]; new

  - "+"가 붙으면 클래스 메소드.

Posted by windship
프로그래밍/Cocos2D2010. 7. 2. 17:57
비록 예제를 위한 게임이지만 3단계까지 진행한 상태에서는 별반 감흥이 없다. 이유는 바로 소리(배경음악, 효과음)가 없기 때문이다. 지금까지 게임 개발의 문외한 이었지만 "게임은 종합 예술"이라는 말을 자주 들었었다. 정말 그렇다. 아주 간단한 게임조차 그래픽과 사운드는 필수 요소이다.

사운드 샘플은 원문의 샘플을 그대로 사용하기로 한다. 아니면 Cocos2D에서 소개하는 게임 관련 리소스(Game Resources)를 이용해도 좋을 것 같다.

배경 음악과 효과음 추가
다음 두 개의 파일을 다운 받아 Xcode 프로젝트의 Resources 폴더에 추가한다.
우선 MammothHuntingScene.h에 다음 임포트 문을 추가한다.

#import "SimpleAudioEngine.h"


init 메소드에 다음과 같이 배경음악을 시작하는 코드를 추가하자. 마지막 부분에 추가하면 된다.

[[SimpleAudioEngine sharedEngineplayBackgroundMusic:@"background-music-aac.caf"];


그리고 ccTouchesEnded 메소드에 총알 발사 효과음을 추가한다.

[[SimpleAudioEngine sharedEngineplayEffect:@"pew-pew-lei.caf"];


빌드앤런! 이제 배경 음악과 효과음을 들을 수 있다.

게임 진행 로직 추가
다음은 간단한 게임 진행 로직을 추가할 것이다. 프로젝트에 GameOverScene 이라고 새로운 클래스를 추가하자. 그리고 다음과 같이 GameOverScene.h와 GameOverScene.m을 수정한다.

[GameOverScene.h]

@interface GameOverLayer : CCColorLayer {

CCLabel *_label;

}


@property (nonatomicretain) CCLabel *label;


@end




@interface GameOverScene : CCScene {

GameOverLayer *_layer;

}


@property (nonatomicretain) GameOverLayer *layer;


@end



[GameOverScene.m]

#import "GameOverScene.h"

#import "MammothHuntingScene.h"



@implementation GameOverLayer


@synthesize label = _label;



-(id) init {

if ((self=[super initWithColor:ccc4(255,255,255,255)])) {

CGSize winSize = [[CCDirector sharedDirectorwinSize];

self.label = [CCLabel labelWithString:@"" fontName:@"Arial" fontSize:32];

_label.color = ccc3(0,0,0);

_label.position = ccp(winSize.width/2, winSize.height/2);

[self addChild:_label];

[self runAction:[CCSequence actions:

 [CCDelayTime actionWithDuration:3],

 [CCCallFunc actionWithTarget:self selector:@selector(gameOverDone)],

 nil]];

}

return self;

}



- (void)gameOverDone {

[[CCDirector sharedDirectorreplaceScene:[MammothHuntingScene scene]];

}



- (void)dealloc {

[_label release];

_label = nil;

[super dealloc];

}



@end



@implementation GameOverScene


@synthesize layer = _layer;



- (id)init {

if ((self = [super init])) {

self.layer = [GameOverLayer node];

[self addChild:_layer];

}

return self;

}



- (void)dealloc {

[_layer release];

_layer = nil;

[super dealloc];

}



@end


위 소스에서 한 가지 주목할 것은 하나의 파일에 두 개의 서로 다른 객체, 즉 Layer와 Scene이 있다는 점이다. 보통 하나의 Scene은 여러 개의 Layer를 포함할 수 있다. 그러나 본 예제에서는 오직 하나의 Layer만 사용한다. 화면의 중앙에 라벨을 그리는 Layer이다.

마지막으로, 단순한 게임 진행 로직 추가를 위해, MammothHuntingScene.h에 다음의 멤버 변수를 추가하자. 

int _projectilesDestroyed;


MammothHuntingScene.m에는 다음 임포트 구문을 추가한다.

#import "GameOverScene.h"


그리고 게임의 승리 조건을 판단하기 위해 update 메소드의 targetsToDelete 루프에 다음 코드를 추가한다.

_projectilesDestroyed++;

if (_projectilesDestroyed > 30) {

GameOverScene *gameOverScene = [GameOverScene node];

[gameOverScene.layer.label setString:@"You Win!"];

[[CCDirector sharedDirectorreplaceScene:gameOverScene];

}


다음 spriteMoveFinished 메소드의 sprite.tag == 1 조건 부분에 아래의 코드를 추가한다.

GameOverScene *gameOverScene = [GameOverScene node];

[gameOverScene.layer.label setString:@"You Lose :["];

[[CCDirector sharedDirectorreplaceScene:gameOverScene];


드디어 아주 아주 간단한 게임 개발이 끝이 났다. 다시 빌드앤런! 추가된 게임 로직이 제대로 작동될 것이다.

MammothHunting 프로젝트 소스
Posted by windship