Objective-C 기초 문법

z-wook·2025년 2월 21일
1
post-thumbnail

Objective-C 클래스 구조

  1. @interface : 클래스, 메서드 선언
  2. @implementation : 메서드 구현
  3. 프로그램 : 실행 프로그램 코드

특징

Objective-C에서는 첫 번째 매개변수에는 별도 이름을 붙일 수 없다.
(대신 메서드 이름 자체를 더 직관적으로 만들어서 해결해야 한다.)

-와 +는 메서드가 인스턴스 메서드인지, 클래스 메서드인지를 나타내는 구분자

기호의미
- (빼기)인스턴스 메서드 (객체를 통해 호출됨)
+ (더하기)클래스 메서드 (클래스 자체에서 호출 가능)

기본 구문

#import <Foundation/Foundation.h>

@interface SampleClass : NSObject
// 메서드 선언
- (void)print;
- (void)setNumber: (int)num1 setAnotherNum: (int)num2;
- (int)plusNumber;
- (int)minusNumber;
@end

@implementation SampleClass
int firstNum;
int secondNum;

- (void)print {
    NSLog(@"%i, %i", firstNum, secondNum);
}

- (void)setNumber: (int)num1 setAnotherNum:(int)num2 {
    firstNum = num1;
    secondNum = num2;
}

- (int)plusNumber {
    return firstNum + secondNum;
}

- (int)minusNumber {
    return firstNum - secondNum;
}
@end

// 프로그램 부분
int main(int argc, const char * argv[]) {
    @autoreleasepool {
//        SampleClass *sampleClass = [SampleClass alloc]; // 메모리 공간 할당
//        sampleClass = [sampleClass init];               // 초기화
        
//        SampleClass *sampleClass = [[SampleClass alloc] init];  // 한 줄로 결합 가능
	    SampleClass *sampleClass = SampleClass.new; // 대체 가능
        
        [sampleClass setNumber:4 setAnotherNum:3];
        
        int sum = [sampleClass plusNumber];
        NSLog(@"%i", sum);
        
        int minus = [sampleClass minusNumber];
        NSLog(@"%i", minus);
        
        [sampleClass print];
    }
    return 0;
}

@property 사용 유무

Case1: @property 사용 안한 경우

@interface SampleClass : NSObject {
    int height;
}
- (void)setHeight:(int)height;
- (int)getHeight;
@end

@implementation SampleClass
- (void)setHeight:(int)newHeight {
    height = newHeight;
}

- (int)getHeight {
    return height;
}
@end

int main(void) {
    SampleClass *sampleClass = [[SampleClass alloc]init];
    [sampleClass setHeight:4];
    NSLog(@"%d", [sampleClass getHeight]);
}

Case2: @property 사용한 경우

@interface SampleClass : NSObject
@property int height;
@end

@implementation SampleClass
@end

int main(void) {
    SampleClass *sampleClass = [[SampleClass alloc]init];
    sampleClass.height = 4;
    NSLog(@"%d", sampleClass.height);
}

case1, case2 코드의 동작은 동일하지만 case2처럼 @property를 사용하는 것이 편리 + 안전하다.

직접 인스턴스 변수를 선언해야 하는 경우(case1의 경우)

  • Getter/Setter에 추가 로직이 필요할 때
  • struct, 배열 등을 사용할 때(@property로 선언 불가능)
  • 메모리 관리를 직접 해야 할 때(malloc/free 사용 시)
  • 성능 최적화가 필요한 경우(getter/setter 호출 오버헤드 줄이기)

@property를 사용하지 못하는 경우 인스턴스 변수 직접 지정해줘야 함

struct Book {
    NSString *title;
    NSString *author;
    int bookID;
};

@interface SampleClass : NSObject {
    struct Book myBook;
}

- (void)setBook:(NSString *)title author:(NSString *)author bookID:(int)bookID;
- (void)printBook;
@end

@implementation SampleClass
- (void)setBook:(NSString *)title author:(NSString *)author bookID:(int)bookID {
    myBook.title = title;
    myBook.author = author;
    myBook.bookID = bookID;
}

- (void)printBook {
    NSLog(@"Title: %@", myBook.title);
    NSLog(@"Title: %@", myBook.author);
    NSLog(@"Title: %d", myBook.bookID);
}
@end

int main(void) {
    SampleClass *sampleClass = [[SampleClass alloc]init];
    [sampleClass setBook:@"파우스트" author:@"괴테" bookID:1234];
    [sampleClass printBook];
}

클래스 * 객체

@interface Box : NSObject {
    double length;
    double breath;
    double height;
}

@property(nonatomic, readwrite) double height;
- (double) volume;
@end

@implementation Box
@synthesize height;

- (id)init {
    length = 1.0;
    breath = 1.0;
    return self; // 현재 객체(self)를 반환
}

- (double) volume {
    return length * breath * height;
}
@end

int main(void) {
    Box *box1 = [[Box alloc]init];
    box1.height = 10;
    NSLog(@"%f", [box1 volume]);
}
  • @property 사용시 getter/setter을 자동으로 생성되기 때문에 명시하지 않아도 된다.

  • id는 Objective-C에서 모든 객체 타입을 나타내는 동적 타입이다. 간단히 말하면, 어떤 클래스의 객체가 될 수 있는 모든 객체를 나타내는 타입이다.(구체적인 클래스 타입을 명시하지 않고 모든 객체를 받아들일 수 있다.)

@property의 주요 속성(Attributes)

속성의미
nonatomic멀티스레드 안전성 보장 X, 성능 빠름 (일반적으로 사용)
atomic멀티스레드에서 안전하지만 성능 저하
strong객체를 소유하며 해제되지 않도록 보장 (ARC에서 기본 설정)
weakARC에서 참조를 유지하지 않음 (순환 참조 방지에 사용)
assign객체가 아닌 기본 타입(int, float, BOOL 등)에 사용
readonlysetter가 없으며 읽기 전용 속성
readwrite읽기/쓰기 가능 (기본값)
copy객체를 복사하여 소유 (ex. NSString 같은 변경 가능한 객체에서 사용)

atomic/nonatomic 차이점

  • 멀티 스레드 환경에서 동시에 해당 프로퍼티에 접근할 때, 자동으로 해당 프로퍼티의 getter/setter에 Lock 기능을 제공하는 것이 automic입니다.(Data race 방지)
  • atomic으로 선언할 경우 안전해 보이긴 하지만, 그만큼 성능 저하가 일어난다.
  • UI 업데이트와 관련된 작업은 보통 메인 스레드에서 이루어지므로, 스레드 안전을 보장할 필요가 없는 경우가 많습니다. 따라서 UI 요소를 다룰 때nonatomic을 사용하는 것이 더 효율적입니다.

상속

@interface Person : NSObject {
    NSString *personName;
    NSInteger personAge;
}

- (id)initWithName: (NSString *)name andAge: (NSInteger)age;
- (void)print;
@end

@implementation Person
- (id)initWithName:(NSString *)name andAge:(NSInteger)age {
    personName = name;
    personAge = age;
    return self;
}

- (void)print {
    NSLog(@"Nname: %@", personName);
    NSLog(@"Age: %ld", personAge);
}
@end

@interface Employee : Person {
    NSString *employeeEducation;
}

- (id)initWithName:(NSString *)name andAge:(NSInteger)age andEducation:(NSString *)education;
- (void)print;
@end

@implementation Employee
- (id)initWithName:(NSString *)name andAge:(NSInteger)age andEducation:(NSString *)education {
    personName = name;
    personAge = age;
    employeeEducation = education;
    return self;
}

- (void)print {
    NSLog(@"Name: %@", personName);
    NSLog(@"Age: %ld", personAge);
    NSLog(@"Education: %@", employeeEducation);
}
@end

int main(void) {
    NSLog(@"Base class Person Object");
    Person *person = [[Person alloc]init];
    person = [person initWithName:@"han" andAge:29];
    [person print];
    
    NSLog(@"Inherited Class Employee Object");
    Employee *employee = [[Employee alloc]init];
    employee = [employee initWithName:@"lee" andAge:34 andEducation:@"CS"];
    [employee print];
}

확장

@interface SampleClass : NSObject {
    NSString *name;
}

- (void)setInternalID;
- (NSString *)getExternalID;
@end

@interface SampleClass() {
    NSString *internalID;
}
@end

@implementation SampleClass
- (void)setInternalID {
    internalID = [NSString stringWithFormat:@"UNIQUEINTERNALKEY%dUNIQUEINTERNALKEY",arc4random()%100];
}

- (NSString *)getExternalID {
    return [internalID stringByReplacingOccurrencesOfString:@"UNIQUEINTERNALKEY" withString:@""];
}
@end

int main(void) {
    SampleClass *sampleClass = [[SampleClass alloc]init];
    [sampleClass setInternalID];
    NSLog(@"%@", [sampleClass getExternalID]);
}

프로토콜

@protocol PrintProtocolDelegate <NSObject>
- (void)processCompleted;
@end

@interface PrintClass : NSObject {
    id delegate;
}

- (void) printDetails;
- (void) setDelegate: (id)newDelegate;
@end

@implementation PrintClass
- (void)printDetails {
    NSLog(@"Printting Details");
    [delegate processCompleted];
}

- (void)setDelegate:(id)newDelegate {
    delegate = newDelegate;
}
@end

@interface SampleClass : NSObject<PrintProtocolDelegate>
- (void)startAction;
@end

@implementation SampleClass
- (void)startAction {
    PrintClass *printClass = PrintClass.new;
    [printClass setDelegate:self];
    [printClass printDetails];
}

- (void)processCompleted {
    NSLog(@"Printing Process Completed");
}
@end

int main(void) {
    SampleClass *sampleClass = [[SampleClass alloc]init];
    [sampleClass startAction];
}

typedef

typedef struct Books {
    NSString *title;
    NSString *author;
    NSString *subject;
    int bookID;
} Book;

int main(void) {
    Book book;
    book.title = @"Objective-C Programming";
    book.author = @"han";
    book.subject = @"Programming";
    book.bookID = 100;
    
    NSLog(@"%@", book.title);
    NSLog(@"%@", book.author);
    NSLog(@"%@", book.subject);
    NSLog(@"%d", book.bookID);
}

define & const

define

#define PI 3.14159

int main(void) {
    double radius = 5.0;
    double area = PI * radius * radius;
    NSLog(@"Circle Area: %f", area);
}

const

const double PI = 3.14159;

int main(void) {
    double radius = 5.0;
    double area = PI * radius * radius;
    NSLog(@"Circle Area: %f", area);
}
  • define은 단순 치환, const는 메모리에 저장

define vs const 차이점

구분#defineconst
메모리 할당없음 (단순 문자열 치환)있음 (메모리에 값 저장)
자료형 존재 여부없음 (타입이 지정되지 않음)있음 (명확한 자료형을 가짐)
디버깅 가능 여부어려움 (컴파일 전에 치환됨)쉬움 (변수처럼 사용 가능)
스코프(범위)전역 (어디서든 사용 가능)선언된 블록 내에서만 사용 가능
상수 값 변경 가능 여부변경 불가능변경 불가능 (const 키워드)
profile
🍎 iOS Developer

0개의 댓글