Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Archives
Today
Total
관리 메뉴

J

[Swift] self / Self 본문

Swift

[Swift] self / Self

yujaehui 2024. 4. 18. 00:36

1. `self`: 현재 인스턴스를 나타내는 키워드

`self`는 현재 인스턴스 자체를 참조.

Swift에서 모든 인스턴스 메서드와 이니셜라이저에는 암묵적으로 `self`가 포함되어 있으며, 필요한 경우 이를 명시적으로 사용 가능.

1.1 사용 목적

  • 현재 인스턴스 참조
    • 메서드나 이니셜라이저 내부에서 `self`를 사용하면, 해당 메서드가 호출된 인스턴스를 참조.
    • 이를 통해 인스턴스 프로퍼티에 접근하거나 인스턴스 메서드를 호출할 수 있음.
  • 이름 충돌 해결
    • 이니셜라이저나 메서드의 파라미터 이름이 인스턴스 프로퍼티와 동일한 경우, `self`로 인스턴스 프로퍼티를 참조.
  • 클로저 캡처
    • 클로저 내부에서 `self`를 사용하면, `self`가 클로저 외부의 인스턴스를 참조.

1.2 동작 원리와 예제

struct Car {
    var brand: String

    func displayBrand() {
        print("The car brand is \\(self.brand).") // self는 생략 가능
    }
}

let car = Car(brand: "Tesla")
car.displayBrand() // "The car brand is Tesla."
  • 현재 인스턴스 참조
    • `self`는 메서드 내부에서 암묵적으로 사용.
struct Rectangle {
     var width: Double
     var height: Double

     init(width: Double, height: Double) {
         self.width = width // self.width는 인스턴스 프로퍼티를 참조
         self.height = height
    }
}
  • 이름 충돌 해결
    • 이니셜라이저에서 지역 변수와 인스턴스 프로퍼티의 이름이 같을 경우 `self`를 사용해 구분.
class Counter {
     var count = 0

     func increment() {
         DispatchQueue.global().async { [weak self] in
             guard let self = self else { return }
             self.count += 1
             print("Count: \(self.count)")
         }
     }
 }
  • 클로저 캡처
    • 클로저 내부에서 `self`를 참조할 경우 강한 캡처가 발생하므로, 순환 참조를 방지하려면 `[weak self]` 또는 `[unowned self]`를 사용.

1.3 주의사항

  • 지역 변수와 이름이 겹치지 않으면 생략 가능
    • `self`는 필요하지 않은 경우 생략할 수 있으나, 명시적으로 사용하는 것이 코드 가독성을 높이는 경우도 존재.
  • 클로저에서의 `self`사용
    • 클로저가 `self`를 강하게 캡처할 경우, 순환 참조 문제가 발생할 수 있음.
  • 클래스와 구조체의 차이
    • 클래스의 경우 `self`는 참조 타입이며, 값이 변경되면 모든 참조에 영향을 미치게 됨.
    • 구조체에서는 값 타입이므로 메서드에서 `self`를 직접 수정하려면 `mutating` 키워드를 사용해야 함.

2. `Self`: 현재 타입을 나타내는 키워드

`Self`는 현재 타입을 참조.

Swift의 타입 시스템에서 `Self`는 특정 타입을 일반화하여 나타내며, 타입 메서드, 팩토리 메서드, 프로토콜의 연관 타입에서 주로 사용.

2.1 사용 목적

  • 현재 타입 참조
    • 타입 메서드에서 현재 타입을 참조할 때 사용되며, 이는 클래스, 구조체, 열거형 모두에서 유용.
  • 팩토리 메서드
    • 현재 타입의 새로운 인스턴스를 생성하여 반환하는 메서드를 작성할 때 사용.
  • 프로토콜과의 연관성
    • 프로토콜에서 `Self`를 사용하면, 구현체의 타입을 동적으로 참조할 수 있음.

2.2 동작 원리와 예제

struct Shape {
    static func createShape() -> Self {
        return Self() // 현재 타입 반환
    }
}
  • 현재 타입 참조
    • `Self`는 타입 메서드 내에서 현재 타입을 명확히 참조.
class Animal {
    class func createInstance() -> Self {
        return self.init() // Self를 사용해 현재 타입의 인스턴스 생성
    }

    required init() {}
}

class Dog: Animal {}

let dog = Dog.createInstance()
print(type(of: dog)) // Dog
  • 팩토리 메서드
    • 팩토리 메서드는 상속받은 클래스에서도 적절히 동작하도록 `Self`를 활용할 수 있음.
protocol Copyable {
    func copy() -> Self
}

class Document: Copyable {
    var content: String

    init(content: String) {
        self.content = content
    }

    func copy() -> Self {
        return type(of: self).init(content: self.content)
    }
}
  • 프로토콜에서의 사용
    • 프로토콜에서 `Self`는 구현체의 타입을 나타냄.
    • 위 코드에서 `Self`는 `Document` 타입으로 대체.

2.3 주의사항

  • 타입 제약이 있는 경우
    • `Self`는 주로 팩토리 메서드에서 사용되며, 클래스나 구조체의 초기화와 관련.
  • 프로토콜 구현 시의 중요성
    • 프로토콜에서 `Self`를 사용하면 구현체 타입을 동적으로 결정할 수 있지만, 이는 제네릭 타입보다 덜 직관적일 수 있음.
  • 하위 클래스에서의 동작
    • 팩토리 메서드에서 `Self`를 반환하면, 하위 클래스에서도 올바르게 동작.

3. `self`와 `Self`비교 요약

키워드 의미 주요 용도
`self` 현재 인스턴스 참조 메서드나 이니셜라이저 내부에서 현재 인스턴스를 참조하거나 전달
`Self` 현재 타입 참조 팩토리 메서드, 프로토콜의 연관 타입, 타입 메서드에서 사용

 


4. 결론

`self`와 `Self`는 Swift에서 각각 현재 인스턴스와 타입을 참조하며, 서로 다른 맥락에서 중요한 역할.

`self`는 인스턴스의 속성 및 메서드를 명확히 참조하거나 전달할 때 사용.

`Self`는 동적 타입 참조 및 팩토리 메서드 관련 작업에서 사용.

'Swift' 카테고리의 다른 글

[Swift] init  (0) 2024.04.18
[Swift] weak, unowned  (0) 2024.04.18
[Swift] associatedtype  (0) 2024.04.18
[Swift] Protocol  (0) 2024.04.18
[Swift] Generic  (0) 2024.04.15