study record

[Swift] Struct 내 Class 프로퍼티는 복사될까? isKnownUniquelyReferenced? 본문

Swift/스위프트 정리

[Swift] Struct 내 Class 프로퍼티는 복사될까? isKnownUniquelyReferenced?

asong 2025. 2. 1. 23:13

Struct 내 Class 프로퍼티는 복사될까? 

Struct는 값 타입으로 값을 복사한다.

그렇다면 Struct 내의 Class 프로퍼티는 복사될까 아니면 참조 주소 값을 공유하게 될까?

 

 

정답은 Struct 내의 Class 프로퍼티는 참조 주소 값을 공유한다.

이에 다음과 같은 문제가 발생할 수 있다.

 

📌 "Struct의 class 프로퍼티에서 생길 수 있는 문제?

1. 문제 개요

Swift에서 struct(값 타입) 내에 클래스(참조 타입) 프로퍼티를 포함할 때, 참조 타입이므로 원본이 공유될 수 있는 문제가 있다.

특히 클래스가 상속(subclassing) 될 수 있는 경우, 원치 않는 변경이 발생할 수 있다.

 

2. 어떤 문제가 발생할 수 있나?

만약 struct 내에 참조 타입인 클래스 프로퍼티가 있고, 여러 변수가 해당 struct를 공유하면 한 곳에서 클래스의 속성을 변경하면 다른 곳에서도 변경이 반영된다.

이것은 struct의 값 타입(Value Type) 특성과 맞지 않으며, 예기치 않은 버그를 유발할 수 있다.

 

📌 isKnownUniquelyReferenced를 사용하여 해결

위 문제를 해결하려면 struct가 복사될 때 내부 참조 타입이 공유되지 않도록 보장해야 한다.

이를 위해 isKnownUniquelyReferenced(_:)를 활용하면 된다.

 

isKnownUniquelyReferenced(_:)란?

  • 참조 타입이 현재 유일하게 참조되고 있는지 확인하는 함수.
  • true이면, 해당 객체가 유일하게 참조됨(즉, 안전하게 변경 가능).
  • false이면, 해당 객체가 여러 곳에서 공유됨(즉, 변경 전 복사 필요).
struct Material {
    public var roughness: Float
    public var color: Color
    private var _texture: Texture

    // ✅ 프로퍼티 감시자에서 `isKnownUniquelyReferenced` 사용
    public var isSparkly: Bool {
        get { _texture.isSparkly }
        set {
            if !isKnownUniquelyReferenced(&_texture) {
                _texture = Texture(copying: _texture) // ✅ 복사본 생성하여 변경
            }
            _texture.isSparkly = newValue
        }
    }
}

 

 

위 코드에서 Texture(copying: _texture)라는 초기화 메서드는 Swift의 내장 기능이 아니라, 사용자가 직접 구현해야 하는 생성자이다.

Swift의 클래스는 기본적으로 복사 생성자(Copy Constructor)를 제공하지 않으므로, 명시적으로 "복사 생성자"를 만들어야 한다.

class Texture {
	var isSparkly: Bool
	// 기본 생성자
	init(isSparkly: Bool) {
	    self.isSparkly = isSparkly
	}
	
	// ✅ 복사 생성자 (Copy Initializer)
	init(copying texture: Texture) {
	    self.isSparkly = texture.isSparkly
	}
}

 

📌 ✅ copying 생성자 없이 NSCopying을 활용하는 방법

만약 Swift의 프로토콜 기반 복사를 원한다면, NSCopying을 채택하는 방법도 있다.

class Texture: NSCopying {
    var isSparkly: Bool

    init(isSparkly: Bool) {
        self.isSparkly = isSparkly
    }

    // ✅ NSCopying 프로토콜 구현
    func copy(with zone: NSZone? = nil) -> Any {
        return Texture(isSparkly: self.isSparkly)
    }
}

_texture = _texture.copy() as! Texture

 

 

 

참고

- https://developer.apple.com/videos/play/wwdc2019/415/