TIL: self vs Self

Royce·2025년 3월 29일

Swift 문법

목록 보기
57/63

self vs Self

self 키워드의 사용 (소문자)

  • Swift에서 self는 인스턴스를 참조하거나, 타입 내부의 특정 상황에서 타입 자체를 지칭할 때 사용된다

인스턴스를 가리키기 위해 사용

  • 클래스 또는 구조체의 인스턴스를 초기화하거나 프로퍼티에 접근할 때 self를 사용하여 인스턴스 자신을 참조한다
class Person {
    var name: String
    init(name: String) {
        self.name = name  // 인스턴스의 프로퍼티에 값을 할당할 때 self 사용
    }
}

값 타입(구조체, 열거형)에서 인스턴스 값 자체를 치환하기 위해 사용

  • 구조체 또는 열거형에서 self를 사용하여 기존 인스턴스를 새로운 인스턴스로 완전히 교체할 수 있다
  • 이는 값 타입에서만 가능한 방식이다
struct Calculator {
    var number: Int = 0

    mutating func plusNumber(_ num: Int) {
        number += num
    }

    mutating func reset() {
        self = Calculator()  // 새로운 인스턴스를 생성하여 치환
    }
}

타입 멤버에서 사용하면, 인스턴스가 아닌 타입 자체를 가리킴

  • 클래스, 구조체 또는 열거형의 타입 속성이나 타입 메서드를 정의할 때 self는 해당 타입 자체를 의미한다
struct MyStruct {
    static let club = "iOS부서"

    static func doPrinting() {
        print("소속은 \(self.club)입니다.")  // self는 타입 자체를 가리킴
    }
}

타입 인스턴스와 메타타입

타입 인스턴스

  • 타입 인스턴스란, 특정 타입을 직접 나타내는 것을 의미한다 (예: SomeClass.self)
  • 타입 인스턴스를 사용하면 타입 자체를 참조할 수 있으며, 이때 self를 사용하여 타입 인스턴스를 가리킬 수 있다
class SomeClass {
    static let name = "SomeClass"
}

let classTypeInstance: SomeClass.Type = SomeClass.self  // 타입 인스턴스 참조

메타타입 (Metatype)

  • 메타타입은 타입 자체를 나타내는 특별한 타입이다
  • 즉, 클래스, 구조체, 열거형 등의 타입 정보를 나타낸다
  • 메타타입은 타입의 인스턴스를 가리키는 것이 아니라, 타입 자체를 가리킨다
  • Type 접미사를 사용하여 메타타입을 표현한다
class Animal {
    static let species = "Mammal"
}

let animalType: Animal.Type = Animal.self  // 메타타입 사용


print(Animal.species)        // "Mammal"
print(Animal.self.species)    // "Mammal"
  • 여기서 Animal.TypeAnimal 타입의 메타타입을 의미한다
  • 즉, animalTypeAnimal 타입 자체를 나타내는 객체이다
  • 다음과 같이 메타타입으로도 타입의 속성에 접근할 수 있다

Self 키워드의 사용 (대문자)

  • Swift에서 Self는 해당 타입 자체를 의미하며, 특정 타입 내부에서 사용된다

타입 선언 위치에서 사용

  • 특정 타입의 선언 위치에서 Self는 타입 이름 대신 사용될 수 있다
extension Int {
    static let zero: Self = 0  // Self는 Int 타입을 의미

    // 인스턴스 계산 속성
    var zero: Self {  // 타입을 선언하는 위치에서 사용
        return Self.zero  // Self로 타입을 표현
    }
}

동일한 예제를 타입 이름을 사용하여 작성한다면?

extension Int {
    var zero: Int {
        return Int.zero  // 타입 이름(Int)을 직접 사용하여 반환
    }
}

타입 속성/메서드에서 사용

  • 타입 내부의 타입 속성 또는 타입 메서드에서 Self를 사용하여 타입 자체를 가리킨다
extension Int {
    static func toZero() -> Self {
        return Self.zero  // 타입 메서드 내부에서 Self 사용
    }
}

인스턴스 메서드에서 사용

  • 인스턴스 메서드에서 self는 인스턴스 자체를 의미하며, Self는 타입을 의미한다
extension Int {
    func toZero() -> Self {
        return Self.zero  // 타입의 초기값을 반환
    }
}

프로토콜에서의 Self 사용

  • Swift에서 Self는 프로토콜 내에서 해당 타입을 가리킬 때 사용된다
  • 프로토콜 메서드가 Self를 반환 타입으로 가지는 경우, 구현하는 타입이 해당 메서드를 구현할 때 반드시 같은 타입을 반환해야 한다
protocol Clonable {
    func clone() -> Self  // 구현하는 타입을 반환하는 메서드
}

struct User: Clonable {
    var name: String

    func clone() -> Self {
        return User(name: self.name)
    }
}

BinaryInteger 프로토콜 사용 예시

  • Swift의 BinaryInteger 프로토콜을 채택하는 타입 (Int, UInt 등)에서도 Self를 사용할 수 있다
  • 프로토콜의 기본 구현 메서드에서 Self를 사용하여 타입이 정확히 지정되지 않아도 제네릭하게 동작하도록 할 수 있다
extension BinaryInteger {
    // 프로토콜 확장을 통해 모든 BinaryInteger 타입에 squared() 메서드를 추가
    // Self는 메서드를 호출하는 타입 자체를 의미 (예: Int, UInt)
    func squared() -> Self {  
        return self * self  // 현재 인스턴스(self)의 값을 자기 자신과 곱한 값을 반환
    }
}

// Int 타입의 값을 정의하고 squared() 메서드를 호출
let intValue: Int = 8
print(intValue.squared())  // 출력 결과: 64 (8 * 8)

// UInt 타입의 값을 정의하고 squared() 메서드를 호출
let uintValue: UInt = 12
print(uintValue.squared())  // 출력 결과: 144 (12 * 12)

요약

  • self: 인스턴스를 가리키거나, 타입 내부의 특정 상황에서 타입 자체를 지칭할 때 사용된다
  • Self: 특정 타입 내부에서 타입 자체를 가리키거나, 프로토콜에서 해당 타입을 의미할 때 사용된다
  • 타입 인스턴스: 특정 타입 자체를 참조하기 위한 인스턴스로, self를 사용하여 참조할 수 있다
  • 메타타입: 타입 자체를 가리키는 특별한 타입으로, Type 접미사를 사용하여 표현한다
  • 프로토콜에서 Self를 사용하면, 제네릭하게 타입을 정의하고, 확장할 수 있다
profile
iOS 개발자 지망생

0개의 댓글