ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Swift 개발자를 위한 Objective-C 문법 요약
    Apple🍎/Objective-C 2025. 5. 23. 15:34

     

    1. 기본 구문 차이

    파일 확장자와 구조

    Swift와 Objective-C는 파일 구조부터 차이가 있습니다.

    Swift

    • 파일 확장자: .swift
    • 단일 파일에 모든 코드 포함 가능

    Objective-C

    • 헤더 파일(.h) - 인터페이스 선언
    • 구현 파일(.m) - 실제 구현 코드

    예를 들어 Person 클래스를 생성할 때

    Objective-C 헤더 파일 (Person.h)

    #import <Foundation/Foundation.h>
    
    @interface Person : NSObject
    
    @property (nonatomic, strong) NSString *name;
    @property (nonatomic, assign) NSInteger age;
    
    - (void)introduceYourself;
    
    @end
    

    Objective-C 구현 파일 (Person.m)

    #import "Person.h"
    
    @implementation Person
    
    - (void)introduceYourself {
        NSLog(@"Hello, my name is %@ and I am %ld years old", self.name, (long)self.age);
    }
    
    @end
    

    Swift 파일 (Person.swift)

    import Foundation
    
    class Person {
        var name: String
        var age: Int
        
        init(name: String, age: Int) {
            self.name = name
            self.age = age
        }
        
        func introduceYourself() {
            print("Hello, my name is \(name) and I am \(age) years old")
        }
    }
    

    주요 차이점

    • Objective-C는 헤더(.h)와 구현(.m) 파일을 분리합니다.
    • Objective-C는 @interface와 @implementation 블록을 사용합니다.
    • Swift는 더 간결한 구문을 가지며 헤더 파일이 필요하지 않습니다.

    2. 변수와 상수 선언

    Objective-C에서의 변수 선언

    // 변수 선언
    NSString *name = @"John";
    NSInteger age = 30;
    CGFloat height = 175.5;
    BOOL isStudent = YES;
    
    // 포인터와 값 타입
    NSString *text;       // 객체형 (참조 타입) - 항상 포인터를 사용
    NSInteger number;     // 기본 값 타입 (포인터 사용 안함)
    

    Swift에서의 변수와 상수

    // 변수 선언
    var name = "John"
    var age = 30
    var height = 175.5
    var isStudent = true
    
    // 상수 선언
    let maxValue = 100
    

    주요 차이점:

    • Objective-C에서는 객체 타입에 항상 포인터(*)를 사용합니다.
    • Objective-C는 const를 사용해 상수를 선언하지만, Swift는 let을 사용합니다.
    • Objective-C에서 문자열은 @ 심볼로 시작합니다.
    • Objective-C는 YES/NO를 사용하고, Swift는 true/false를 사용합니다.

    3. 데이터 타입 비교

    기본 데이터 타입

    Objective-C Swift 설명

    NSInteger, int Int 정수형
    CGFloat, float, double Float, Double, CGFloat 부동 소수점
    BOOL (YES/NO) Bool (true/false) 불리언 타입
    char Character 문자
    NSString * String 문자열
    NSArray * Array<Element> 배열
    NSDictionary * Dictionary<Key, Value> 딕셔너리(해시맵)
    NSSet * Set<Element> 집합

    컬렉션 타입 예제

    Objective-C 배열

    // 불변 배열
    NSArray *immutableArray = @[@"Apple", @"Banana", @"Orange"];
    
    // 가변 배열
    NSMutableArray *fruits = [NSMutableArray array];
    [fruits addObject:@"Apple"];
    [fruits addObject:@"Banana"];
    [fruits insertObject:@"Orange" atIndex:1];
    

    Swift 배열

    // 배열 선언
    let immutableArray = ["Apple", "Banana", "Orange"]
    
    // 가변 배열
    var fruits = [String]()
    fruits.append("Apple")
    fruits.append("Banana")
    fruits.insert("Orange", at: 1)
    

    Objective-C 딕셔너리

    // 불변 딕셔너리
    NSDictionary *person = @{
        @"name": @"John",
        @"age": @30,
        @"isStudent": @NO
    };
    
    // 가변 딕셔너리
    NSMutableDictionary *settings = [NSMutableDictionary dictionary];
    [settings setObject:@"Dark" forKey:@"theme"];
    [settings setObject:@YES forKey:@"notifications"];
    

    Swift 딕셔너리:

    // 딕셔너리 선언
    let person = [
        "name": "John",
        "age": 30,
        "isStudent": false
    ] as [String: Any]
    
    // 가변 딕셔너리
    var settings = [String: Any]()
    settings["theme"] = "Dark"
    settings["notifications"] = true
    

    4. 함수와 메서드

    Objective-C 메서드

    // 인스턴스 메서드 (- 기호로 시작)
    - (NSString *)fullNameWithFirstName:(NSString *)firstName lastName:(NSString *)lastName {
        return [NSString stringWithFormat:@"%@ %@", firstName, lastName];
    }
    
    // 클래스 메서드 (+ 기호로 시작)
    + (Person *)personWithName:(NSString *)name age:(NSInteger)age {
        Person *person = [[Person alloc] init];
        person.name = name;
        person.age = age;
        return person;
    }
    

    Swift 함수와 메서드

    // 인스턴스 메서드
    func fullName(firstName: String, lastName: String) -> String {
        return "\(firstName) \(lastName)"
    }
    
    // 정적 메서드 (타입 메서드)
    static func person(withName name: String, age: Int) -> Person {
        return Person(name: name, age: age)
    }
    

    주요 차이점

    • Objective-C에서는 -로 인스턴스 메서드, +로 클래스 메서드를 표시합니다.
    • Objective-C 메서드는 매개변수 이름이 메서드 이름의 일부입니다 (예: initWithName:age:).
    • Swift는 더 간결한 함수 선언 구문을 사용합니다.
    • Objective-C에서는 반환 타입을 괄호 안에 명시합니다: - (ReturnType *).

    메서드 호출 비교

    Objective-C

    // 메서드 호출
    Person *john = [Person personWithName:@"John" age:30];
    NSString *greeting = [john greetWithMessage:@"Hello" formal:YES];
    
    // 여러 매개변수를 가진 메서드 호출
    [self presentViewController:viewController animated:YES completion:^{
        NSLog(@"Presentation completed");
    }];
    

    Swift

    // 메서드 호출
    let john = Person.person(withName: "John", age: 30)
    let greeting = john.greet(message: "Hello", formal: true)
    
    // 여러 매개변수를 가진 메서드 호출
    present(viewController, animated: true) {
        print("Presentation completed")
    }
    

    5. 클래스와 객체

    Objective-C 클래스

    // 헤더 파일 (MyClass.h)
    @interface MyClass : NSObject
    
    // 속성
    @property (nonatomic, strong) NSString *title;
    @property (nonatomic, assign) NSInteger count;
    
    // 메서드
    - (void)doSomethingWithParam:(NSString *)param;
    + (instancetype)sharedInstance;
    
    @end
    
    // 구현 파일 (MyClass.m)
    @implementation MyClass
    
    + (instancetype)sharedInstance {
        static MyClass *instance = nil;
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            instance = [[self alloc] init];
        });
        return instance;
    }
    
    - (void)doSomethingWithParam:(NSString *)param {
        NSLog(@"Doing something with %@", param);
    }
    
    @end
    

    Swift 클래스

    class MyClass {
        // 속성
        var title: String?
        var count: Int = 0
        
        // 싱글톤
        static let shared = MyClass()
        
        // 메서드
        func doSomething(with param: String) {
            print("Doing something with \(param)")
        }
    }
    

    객체 초기화

    Objective-C

    // 할당과 초기화를 분리
    Person *person = [[Person alloc] init];
    person.name = @"John";
    person.age = 30;
    
    // 또는 편의 메서드 사용
    Person *person = [Person personWithName:@"John" age:30];
    

    Swift

    // 초기화
    let person = Person(name: "John", age: 30)
    
    // 또는 타입 메서드 사용
    let person = Person.person(withName: "John", age: 30)
    

    6. 속성 (Properties)

    Objective-C 속성

    // 헤더 파일
    @interface Person : NSObject
    
    // 속성 선언과 속성 특성
    @property (nonatomic, strong) NSString *name;     // 강한 참조 (ARC)
    @property (nonatomic, weak) UIView *parentView;   // 약한 참조 (ARC)
    @property (nonatomic, assign) NSInteger age;      // 값 타입
    @property (nonatomic, copy) NSString *identifier; // 복사본 저장
    
    // 읽기 전용 속성
    @property (nonatomic, readonly) NSString *uuid;
    
    // 자동 getter/setter 생성 방지
    @property (nonatomic, strong) NSString *customProp;
    
    @end
    
    // 구현 파일
    @implementation Person
    
    // 커스텀 getter/setter
    - (void)setCustomProp:(NSString *)customProp {
        _customProp = [customProp uppercaseString];
    }
    
    - (NSString *)customProp {
        return [_customProp stringByAppendingString:@"!"];
    }
    
    @end
    

    Swift 속성

    class Person {
        // 일반 속성
        var name: String
        var age: Int
        
        // 약한 참조
        weak var parentView: UIView?
        
        // 계산 속성
        var fullName: String {
            return "\(name) Smith"
        }
        
        // 프로퍼티 옵저버
        var score: Int = 0 {
            willSet {
                print("Will change score from \(score) to \(newValue)")
            }
            didSet {
                print("Changed score from \(oldValue) to \(score)")
            }
        }
        
        // 지연 속성
        lazy var expensiveResource: Resource = {
            return Resource()
        }()
        
        // 초기화
        init(name: String, age: Int) {
            self.name = name
            self.age = age
        }
    }
    

    속성 특성 설명 

    1. 스레드 안전성 관련 (Thread Safety)

    atomic (기본값)

    @property (atomic, strong) NSString *name;
    // 또는 단순히
    @property (strong) NSString *name;  // atomic이 기본값
    

    atomic 속성은 getter와 setter가 원자적(atomic)으로 실행됩니다. 즉, 한 번에 하나의 스레드만 이 속성에 접근할 수 있습니다. 이는 스레드 안전성을 보장하지만 성능 오버헤드가 있습니다.

    nonatomic (권장)

    @property (nonatomic, strong) NSString *name;
    

    nonatomic은 스레드 안전성을 포기하는 대신 더 나은 성능을 제공합니다. iOS 개발에서는 대부분의 UI 작업이 메인 스레드에서 실행되므로 일반적으로 nonatomic을 사용합니다.

    // atomic - 내부적으로 이런 식으로 구현됨
    - (NSString *)name {
        @synchronized(self) {
            return _name;
        }
    }
    
    - (void)setName:(NSString *)name {
        @synchronized(self) {
            _name = name;
        }
    }
    
    // nonatomic - 단순한 접근
    - (NSString *)name {
        return _name;
    }
    
    - (void)setName:(NSString *)name {
        _name = name;
    }
    

    2. 메모리 관리 관련 (Memory Management)

    strong (기본값, ARC 환경)

    @property (nonatomic, strong) NSArray *items;
    

    strong은 "이 객체를 강하게 붙잡고 있겠다"는 의미입니다. 참조 카운트를 증가시키며, 이 속성이 해제되거나 다른 객체로 설정될 때까지 참조된 객체는 메모리에 유지됩니다.

    // 내부 구현 개념
    - (void)setItems:(NSArray *)items {
        [_items release];        // 기존 객체 해제 (ARC가 자동 처리)
        _items = [items retain]; // 새 객체 유지 (ARC가 자동 처리)
    }
    

    weak

    @property (nonatomic, weak) UIView *parentView;
    @property (nonatomic, weak) id<MyDelegate> delegate;
    

    weak는 순환 참조(retain cycle)를 방지하기 위해 사용됩니다. 참조된 객체가 해제되면 이 속성은 자동으로 nil이 됩니다.

    주요 사용 사례를 살펴보겠습니다

    // 부모-자식 관계에서 순환 참조 방지
    @interface Parent : NSObject
    @property (nonatomic, strong) NSArray<Child *> *children;  // 부모가 자식들을 소유
    @end
    
    @interface Child : NSObject
    @property (nonatomic, weak) Parent *parent;  // 자식은 부모를 약하게 참조
    @end
    
    // 델리게이트 패턴
    @interface NetworkManager : NSObject
    @property (nonatomic, weak) id<NetworkDelegate> delegate;  // 델리게이트는 보통 weak
    @end
    

    assign

    @property (nonatomic, assign) NSInteger count;
    @property (nonatomic, assign) CGFloat height;
    @property (nonatomic, assign) BOOL isVisible;
    

    assign은 주로 기본 데이터 타입(primitive types)에 사용됩니다. 단순히 값을 할당하며, 참조 카운팅과 관련이 없습니다. 객체에 사용하면 위험할 수 있습니다.

    // 위험한 사용 예시 - 하지 말 것!
    @property (nonatomic, assign) NSString *dangerousString;
    
    // 이렇게 되면...
    NSString *temp = @"Hello";
    self.dangerousString = temp;  // temp가 해제되면 dangerousString은 댕글링 포인터가 됨
    

    copy

    @property (nonatomic, copy) NSString *title;
    @property (nonatomic, copy) NSArray *itemsCopy;
    

    copy는 할당할 때 객체의 복사본을 만듭니다. 특히 NSString과 같은 불변 객체나, 외부에서 변경될 수 있는 가변 객체를 안전하게 저장할 때 유용합니다.

    copy의 중요성을 보여주는 예시입니다

    // copy 없이 사용할 때의 문제점
    @property (nonatomic, strong) NSMutableArray *dangerousArray;
    
    NSMutableArray *externalArray = [NSMutableArray arrayWithObjects:@"A", @"B", nil];
    self.dangerousArray = externalArray;  // 같은 객체를 참조
    [externalArray addObject:@"C"];       // 외부에서 변경하면 우리 속성도 변경됨!
    
    // copy를 사용하면 안전
    @property (nonatomic, copy) NSArray *safeArray;
    
    NSMutableArray *externalArray = [NSMutableArray arrayWithObjects:@"A", @"B", nil];
    self.safeArray = externalArray;       // 복사본이 생성됨
    [externalArray addObject:@"C"];       // 외부 변경이 우리 속성에 영향 없음
    

    3. 접근 제어 관련

    readonly

    @property (nonatomic, readonly) NSString *identifier;
    @property (nonatomic, readonly, strong) NSDate *createdAt;
    

    readonly는 외부에서 setter를 사용할 수 없게 만듭니다. 클래스 내부에서는 직접 인스턴스 변수에 접근하여 값을 설정할 수 있습니다.

    // 헤더 파일
    @interface User : NSObject
    @property (nonatomic, readonly) NSString *userID;
    @end
    
    // 구현 파일
    @implementation User
    
    - (instancetype)initWithUserID:(NSString *)userID {
        if (self = [super init]) {
            _userID = [userID copy];  // 내부에서는 직접 설정 가능
        }
        return self;
    }
    
    @end
    

    readwrite (기본값)

    @property (nonatomic, readwrite, strong) NSString *name;
    // 또는 단순히
    @property (nonatomic, strong) NSString *name;
    

    readwrite는 getter와 setter 모두 생성합니다.

    7. 제어 흐름

    조건문

    Objective-C

    // if-else 문
    if (age >= 18) {
        NSLog(@"Adult");
    } else if (age >= 13) {
        NSLog(@"Teenager");
    } else {
        NSLog(@"Child");
    }
    
    // switch 문
    switch (statusCode) {
        case 200:
            NSLog(@"Success");
            break;
        case 404:
            NSLog(@"Not Found");
            break;
        default:
            NSLog(@"Unknown status");
            break;
    }
    
    // 3항 연산자
    NSString *status = (age >= 18) ? @"Adult" : @"Minor";
    

    Swift

    // if-else 문
    if age >= 18 {
        print("Adult")
    } else if age >= 13 {
        print("Teenager")
    } else {
        print("Child")
    }
    
    // switch 문 (break 필요 없음)
    switch statusCode {
    case 200:
        print("Success")
    case 404:
        print("Not Found")
    default:
        print("Unknown status")
    }
    
    // 3항 연산자
    let status = (age >= 18) ? "Adult" : "Minor"
    

    반복문

    Objective-C

    // for 루프
    for (int i = 0; i < 10; i++) {
        NSLog(@"%d", i);
    }
    
    // 배열 열거
    for (NSString *fruit in fruits) {
        NSLog(@"%@", fruit);
    }
    
    // while 루프
    int count = 0;
    while (count < 10) {
        NSLog(@"%d", count);
        count++;
    }
    
    // do-while 루프
    int value = 0;
    do {
        value++;
        NSLog(@"%d", value);
    } while (value < 5);
    

    Swift

    // for 루프
    for i in 0..<10 {
        print(i)
    }
    
    // 배열 열거
    for fruit in fruits {
        print(fruit)
    }
    
    // while 루프
    var count = 0
    while count < 10 {
        print(count)
        count += 1
    }
    
    // repeat-while 루프
    var value = 0
    repeat {
        value += 1
        print(value)
    } while value < 5
    

    8. 메모리 관리

    Objective-C의 ARC (Automatic Reference Counting)

    // 강한 참조
    @property (nonatomic, strong) NSObject *strongReference;
    
    // 약한 참조 (ARC가 0이 되면 nil이 됨)
    @property (nonatomic, weak) UIView *weakReference;
    
    // 미소유 참조 (ARC가 0이 되면 댕글링 포인터가 됨)
    @property (nonatomic, unsafe_unretained) NSObject *unsafeReference;
    
    // __block 변수 (블록 내에서 변수를 변경할 수 있게 함)
    __block NSInteger count = 0;
    

    Swift의 ARC

    // 강한 참조 (기본값)
    var strongReference: NSObject?
    
    // 약한 참조
    weak var weakReference: UIView?
    
    // 미소유 참조
    unowned var unownedReference: Controller
    
    // 클로저의 캡처 리스트
    let closure = { [weak self, unowned controller] in
        self?.doSomething()
        controller.update()
    }
    

    9. 블록과 클로저

    Objective-C 블록

    // 블록 타입 정의
    typedef void(^CompletionBlock)(BOOL success, NSError *error);
    
    // 블록 변수
    CompletionBlock completion = ^(BOOL success, NSError *error) {
        if (success) {
            NSLog(@"Operation succeeded");
        } else {
            NSLog(@"Error: %@", error.localizedDescription);
        }
    };
    
    // 메서드 내 블록 사용
    - (void)downloadDataWithCompletion:(CompletionBlock)completion {
        // 비동기 작업...
        BOOL success = YES;
        NSError *error = nil;
        
        // 블록 호출
        if (completion) {
            completion(success, error);
        }
    }
    
    // 호출 예시
    [self downloadDataWithCompletion:^(BOOL success, NSError *error) {
        // 처리
    }];
    

    Swift 클로저

    // 클로저 타입 정의
    typealias CompletionHandler = (Bool, Error?) -> Void
    
    // 클로저 변수
    let completion: CompletionHandler = { success, error in
        if success {
            print("Operation succeeded")
        } else if let error = error {
            print("Error: \(error.localizedDescription)")
        }
    }
    
    // 메서드 내 클로저 사용
    func downloadData(completion: CompletionHandler?) {
        // 비동기 작업...
        let success = true
        let error: Error? = nil
        
        // 클로저 호출
        completion?(success, error)
    }
    
    // 호출 예시
    downloadData { success, error in
        // 처리
    }
    

    주요 차이점

    • Objective-C 블록은 ^ 기호로 시작합니다.
    • Swift 클로저는 더 간결한 구문을 사용합니다.
    • Swift는 후행 클로저 구문을 지원합니다.
    • Objective-C는 블록 내에서 외부 변수를 수정하기 위해 __block을 필요로 합니다.

    10. 오류 처리

    Objective-C 오류 처리

    // NSError를 통한 오류 처리
    - (BOOL)saveData:(NSData *)data error:(NSError **)error {
        if (!data) {
            if (error) {
                *error = [NSError errorWithDomain:@"MyApp" 
                                             code:100 
                                         userInfo:@{NSLocalizedDescriptionKey: @"Data cannot be nil"}];
            }
            return NO;
        }
        // 저장 로직...
        return YES;
    }
    
    // 메서드 호출
    NSError *error = nil;
    BOOL success = [manager saveData:data error:&error];
    if (!success && error) {
        NSLog(@"Save failed: %@", error.localizedDescription);
    }
    
    // @try/@catch를 사용한 예외 처리
    @try {
        // 예외가 발생할 수 있는 코드
        NSArray *array = @[@1, @2, @3];
        id item = array[10]; // 예외 발생!
    }
    @catch (NSException *exception) {
        NSLog(@"Exception: %@", exception.reason);
    }
    @finally {
        // 항상 실행되는 코드
        NSLog(@"Cleanup code");
    }
    

    Swift 오류 처리

    // Error 프로토콜 구현
    enum SaveError: Error {
        case nilData
        case diskFull
        case permissionDenied
    }
    
    // throws를 사용한 오류 처리
    func saveData(_ data: Data?) throws -> Bool {
        guard let data = data else {
            throw SaveError.nilData
        }
        // 저장 로직...
        return true
    }
    
    // 호출
    do {
        let success = try manager.saveData(data)
        print("Save successful")
    } catch SaveError.nilData {
        print("Save failed: Data is nil")
    } catch {
        print("Save failed: \(error)")
    }
    
    // try? 및 try! 사용
    // 오류 무시, 실패 시 nil 반환
    let success = try? manager.saveData(data)
    
    // 오류가 발생하지 않을 것이라고 확신할 때만 사용
    // 오류 발생 시 앱 충돌
    let definiteSuccess = try! manager.saveData(validData)
    

    11. 프로토콜과 델리게이션

    Objective-C 프로토콜

    // 프로토콜 정의 (헤더 파일)
    @protocol DataSourceDelegate <NSObject>
    
    // 필수 메서드
    - (NSInteger)numberOfItems;
    - (NSString *)titleForItemAtIndex:(NSInteger)index;
    
    // 선택적 메서드
    @optional
    - (void)didSelectItemAtIndex:(NSInteger)index;
    
    @end
    
    // 프로토콜 채택 (헤더 파일)
    @interface MyViewController : UIViewController <DataSourceDelegate, UITableViewDelegate>
    
    @property (nonatomic, weak) id<DataSourceDelegate> dataSource;
    
    @end
    
    // 구현 (구현 파일)
    @implementation MyViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        // 프로토콜 메서드 호출
        NSInteger count = [self.dataSource numberOfItems];
        
        // 선택적 메서드 호출 전 확인
        if ([self.dataSource respondsToSelector:@selector(didSelectItemAtIndex:)]) {
            [self.dataSource didSelectItemAtIndex:0];
        }
    }
    
    // 프로토콜 메서드 구현
    - (NSInteger)numberOfItems {
        return 10;
    }
    
    - (NSString *)titleForItemAtIndex:(NSInteger)index {
        return [NSString stringWithFormat:@"Item %ld", (long)index];
    }
    
    @end
    

    Swift 프로토콜

    // 프로토콜 정의
    protocol DataSourceDelegate: AnyObject {
        // 필수 메서드
        func numberOfItems() -> Int
        func title(forItemAt index: Int) -> String
        
        // 선택적 메서드
        func didSelectItem(at index: Int)
    }
    
    // 기본 구현 제공
    extension DataSourceDelegate {
        func didSelectItem(at index: Int) {
            // 기본 구현
            print("Item selected at index \(index)")
        }
    }
    
    // 프로토콜 채택
    class MyViewController: UIViewController, DataSourceDelegate, UITableViewDelegate {
        // 약한 참조로 델리게이트 선언
        weak var dataSource: DataSourceDelegate?
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            // 프로토콜 메서드 호출
            let count = dataSource?.numberOfItems() ?? 0
            
            // 선택적 메서드는 기본 구현이 있으므로 항상 호출 가능
            dataSource?.didSelectItem(at: 0)
        }
        
        // 프로토콜 메서드 구현
        func numberOfItems() -> Int {
            return 10
        }
        
        func title(forItemAt index: Int) -> String {
            return "Item \(index)"
        }
    }
    

    12. Swift와 Objective-C 상호 운용성

    Bridging Header (브리징 헤더)

    Swift 프로젝트에서 Objective-C 코드를 사용하려면 브리징 헤더를 설정해야 합니다:

    // MyProject-Bridging-Header.h
    #import "ObjCClass.h"
    #import "AnotherObjCClass.h"
    

    @objc 및 @objcMembers

    Swift 코드를 Objective-C에서 사용하려면 @objc 어트리뷰트를 사용합니다:

    // 단일 메서드에 @objc 추가
    class MySwiftClass {
        @objc func methodForObjC() {
            // Objective-C에서 호출 가능
        }
        
        func swiftOnlyMethod() {
            // Objective-C에서 호출 불가
        }
    }
    
    // 클래스 전체에 @objcMembers 추가
    @objcMembers
    class MyObjCCompatibleClass {
        var name: String = ""
        func allMethodsAvailableToObjC() {
            // 모든 메서드가 Objective-C에서 호출 가능
        }
    }
    

    13. nil 처리와 옵셔널

    Objective-C nil 처리

    // nil 확인
    if (person == nil) {
        NSLog(@"Person is nil");
    }
    
    // nil 메시지 전송 (안전함, 아무 일도 일어나지 않음)
    [nil doSomething]; // 충돌 없음
    
    // nil 체이닝 (수동으로 체크해야 함)
    if (person.address) {
        NSString *city = person.address.city;
    }
    
    // 조건부 초기화
    NSString *name = person.name ?: @"Unknown";
    

    Swift 옵셔널

    // 옵셔널 선언
    var name: String?
    var age: Int?
    
    // 옵셔널 강제 추출 (위험할 수 있음)
    let unwrappedName = name!
    
    // 옵셔널 바인딩
    if let unwrappedName = name {
        print("Name: \(unwrappedName)")
    }
    
    // 가드 구문
    guard let unwrappedAge = age else {
        print("Age is nil")
        return
    }
    
    // 옵셔널 체이닝
    let city = person?.address?.city
    
    // nil 병합 연산자
    let displayName = name ?? "Unknown"
    

    주요 차이점

    • Objective-C는 nil을 포인터에만 사용할 수 있지만, Swift는 모든 타입을 옵셔널로 만들 수 있습니다.
    • Swift는 명시적인 옵셔널 타입(?)과 강제 추출(!)을 제공합니다.
    • Swift는 안전한 옵셔널 체이닝과 바인딩을 제공합니다.
    • Objective-C에서 nil 메시지 전송은 안전하지만, Swift에서 nil 옵셔널 강제 추출은 충돌을 일으킵니다.

    댓글

Designed by Tistory.