옵젝시 클래스를 공부해보자:)

dqQQQ

·

2023. 11. 27. 21:39

개요

객체 지향에 있어 가장 기본인 클래스.

옵젝시에서의 클래스 정의, 상속, 클래스 인스턴스, 객체 소멸, 복사등을 알아보겠다.




클래스 정의

옵젝시에서 클래스를 정의할 때 컴파일러에 두가지 정보를 제공해야한다.

첫번째는 interface로 클래스 이름, 부모클래스, 인스턴스 변수의 정보, 클래스 메소드의 선언을 담고 있다.

두번째는 implementation으로 클래스 메소드를 구현한 코드이다.

#import <Foundation/Foundation.h>

@class Band;
@class Guitar;

@interface Rockstar: NSObject
{
    NSString *name;
    Band *band;
    Guitar *guitar;
}

- (void) sing;
- (void) playGuitar;
- (void) damage:(float) value;

@end

컴파일러는 클래스의 수퍼클래스에 대한 정보를 그냥 얻을 수 없기에 클래스가 들어있는 헤더파일을 import해야한다.

클래스 안에서 다른 클래스를 사용하고 싶다면 @class 지시자를 이용하면 된다.

Rockstar는 Band와 Guitar 타입의 변수를 가지고 있지만 헤더파일을 import하지 않는다.

그 대신 @class 지시자를 이용해 전방선언을 한다. 헤더파일을 import할 수도 있지만 @class를 사용하는게 더 좋다.

@class 지시자를 이용하면 의존성을 줄여 컴파일 시간을 단축시킬 수 있다.

band클래스 안에 Rockstar *guitarist;라는 변수를 가져 서로가 서로의 변수를 가지고 있다면 컴파일될 수가 없다. 이럴 때에도 @class를 사용한다.

구현부는 implementation이라고 부르며 @implementation으로 시작해 @end로 끝난다.

기본적으로 interface와 implementation은 다른 파일로 관리한다.

같은 파일로 관리하는 경우는 도우미 클래스가 다른 클래스의 내부에서만 사용할 때이다.

이 때 도우미 클래스를 같은 파일에 구현하여 그 클래스를 사용하는 파일에 import하면 된다.

모든 옵젝시 클래스의 root 클래스는 NSObject이다.

NSObject는 메모리 관리같은 오브젝트에 필요한 기본적인 메소드를 가지고 있어 runtime과 잘 동작하도록한다.

다른언어에서의 상속이나 추상클래스 같은 개념도 사용할 수 있다.

세미 추상 클래스라는 것도 있다. 처음들어보는 개념인데 검색해도 잘 나오진 않는다. 이런게 있다정도만 알면될듯

세미 추상클래스는 추상클래스인데 일반 클래스처럼 인스턴스를 만들어 사용할 기능을 부여할 수 있는 클래스이다.


동적 바인딩

옵젝시에서 어떤 객체가 그 메시지를 처리할 수 있는지 없는지, 어떻게 처리하는지는 실제로 메시지를 보낼 때 정해진다.

이렇게 송신된 메시지에 대응해서 어떤 메서드가 실행될지가 런타임 시에 결정되는 방식을 동적바인딩이라고 한다.

이 동적바인딩을 이용함으로써 다형성같은 특징을 사용할 수 있게 된다.

다형성이란 같은 메시지를 보내도 리시버 객체에 따라 적절한 메서드가 선택되어 실행되는 것을 말하는데 객체지향의 근본중 하나이다.

 

id형과 같은 자료형도 사용할 수 있게 되는데 id형은 void *로 어떤 객체도 담을 수 있기에 유연한 프로그램을 만들 수 있다.

클래스 명을 명시적으로 적으면 컴파일 할 때 메시지가 처리가능한지를 판별하지만 id형을 사용하면 런타임에 처리된다.

 

클래스 전방 선언도 특징중 하나인데 클래스 전방 선언이란 헤더 파일을 import하지 않고 @class 키워드를 이용해서 특정 클래스를 사용한다는 것을 선언한 것이다.

헤더를 import하면 되는데 이런것이 필요한 이유는 컴파일의 효율 때문이다. 헤더파일에는 다른 헤더파일등의 다양한 정보가 있다. 

이것을 재귀적으로 계속 읽어야하는데 규모가 커지면 단순히 클래스만 사용하고자 하는 의도와는 다르게 부담스러운 작업이 된다. 

따라서 @class 컴파일러 지시자로 컴파일 속도를 높일 수 있다. 당연히 클래스 구현 부분에서는 해당 헤더파일을 import해야 사용가능하다.


인스턴스 변수의 접근 제어

기본적으로 인스턴스 변수는 접근이 불가능하다. 따라서 getter, setter를 만들어서 접근하는데 접근제어 키워드를 이용해 특징을 바꿀수있다.

  • @private : 선언한 클래스만 접근 가능
  • @protected : 서브 클래스까지 접근 가능
  • @public : 어디서나 참조 가능
  • @package : 해당 프레임워크 내부에서만 public 외부에서는 private

클래스 객체

옵젝시는 클래스 자체도 하나의 객체라고 간주한다. 따라서 객체의 기능을 위한 자신만의 클래스 변수와 클래스 메소드가 있다.

Swift에서 static 함수, static 변수랑 동일한 개념이다. 옵젝시에서는 클래스 객체를 factory라고도 부르는데 대표적인 동작으로는 인스턴스 생성이 있다.

클래스 객체의 개념

클래스 객체는 프로그램을 실행하면 자동으로 클래스마다 하나씩 존재한다. 

인스턴스 메소드를 추가할 때 -를 붙였다면 클래스 객체는 +를 붙이면된다.

클래스 메소드 안에서는 인스턴스 변수를 참조하지 못한다. 어느 인스턴스에 있는 변수인지 모르니깐 당연히 못한다.

옵젝시에서 클래스 변수라는 것은 없다. 따라서 static을 이용해서 파일 내에서 전역변수처럼 사용할 수 있다.


프로퍼티

클래스에서 보면 @property 키워드를 이용해서 변수를 선언한다.

프로퍼티란 직역하자면 속성 클래스 안에서는 주로 해당 클래스의 특징을 나타내는 것들, 즉 변수 같은 것을 지칭한다.

옵젝시에는 선언 프로퍼티라는 개념이 있어 인스턴스 객체에 어떤 프로퍼티가 있는지를 선언한다.

또한 인스턴스 변수에 대응하는 getter, setter를 제공하고 해당 프로퍼티가 어떤 메모리 관리 특성을 가지고 있는지 명시할 수 있다.

이전에는 @synthesize를 사용해서 getter,setter를 만들었는데 2.0부터는 선언 프로퍼티를 이용하면 컴파일러가 자동으로 만들어준다.

프로퍼티는 메시징 방식을 사용하지 않고 dot을 이용해도 접근할 수 있다.

 

메소드 이름 지정 getter=이름 / setter=이름 getter,setter 이름을 명시적으로 지정
읽기/쓰기 속성 readonly 읽기 전용
readwrite 읽기쓰기 (기본값)
값 설정 방법 assign 대입으로 값 설정(기본값)
retain 객체는 retain 설정
unsafe_unretained assign과 같음 (ARC 환경)
strong retain과 같음 (ARC 환경)
weak 약한 참조 (ARC 환경)
copy 객체는 복사해서 설정
메모리 관리 속성 nonatomic 멀티스레딩에서 락을 사용하지 않음