convenience init, mutating func

– 왜 class에서만 convenience를 붙여주는걸까?
– 왜 struct에서만 mutating을 붙여주는걸까?
이번 글에서는 위 두가지에 대해서 살펴보려고 합니다.

convenience init

convenience init은 초기화 단계에서 미리 지정된 값을 사용해서 최소한의 입력으로 초기화를 할 수 있도록 해주는 초기자입니다. convenience init 내에서 반드시 designated initialize가 호출돼야 합니다.
여기서 생긴 궁금증은 struct에서도 designated initialize이 호출되는 경우가 있는데 왜 class에서만 convenience키워드를 붙여줄까 였습니다.
class는 상속이 가능합니다. 여기서 문제점이 발생하였습니다. subClass에 designated init에서 super의 convenience init을 호출하는 경우 무한 루프에 빠질수 있습니다.
class AAA { var name: String init() { init(name: "abc") } init(name: String) { self.name = name } } class BBB: AAA { override init(name: String) { super.init() } } let bbb = BBB(name: "")
Swift
복사
위와같이 호출할경우 무한루프에 빠질수 있습니다.
위 상황을 방지하기 위해서 convenience 키워드를 이용하여 designated init을 호출하는 init이라고 명시를 해줍니다. 그래서 subClass에서는 호출이 되지않고 designated init만 호출하게 되는 것입니다. struct에서는 상속이 되지 않기때문에 위와같은 상황이 발생하지 않습니다.

struct에서는 왜 mutating키워드를 붙여줄까

func에서 ivar를 변경하는 경우 해당 func으로 하여금 struct 전체가 복사된다는걸 명시합니다. 그 명시가 mutating 키워드입니다. struct 전체가 복사되는 이유는 swift가 함수형 언어라서 불변성이 중요한 요소이기 때문입니다. (side effect를 줄이겠다.) struct가 원래 그런 구조 입니다. 예를들어 c언어에서는 구조체 전체가 복사되지 않고, 당연히 mutating키워드도 필요가 없습니다. 하지만 swift 벨류 타입의 핵심은 불변성이라서 그걸 통채로 갈아 엎습니다. 그렇게 되면 다중 쓰레드에서 세이프하게 작동할 수 있습니다.참고\[Swift Language Guide Book\]
다른 인스턴스의 변화는 그 인스턴스에만 영향을 끼치고 그것과 가른 인스턴스에는 아무런 영향도 없다는 것을 알 수 있습니다.
struct 내부의 프로퍼티만 변수로 선언하는게 아니라 struct자체가 변경되기 때문에 변경되는 struct도 var로 변수로 선언해야합니다. (아래코드의 var aaa = AAA(name: “abc”) 가 let aaa가 아니라 var aaa)
[##Image|t/cfile@995787355C1B90CC0E|alignCenter|width="800" height="428" data-origin-width="800" data-origin-height="428" data-ke-mobilestyle="widthContent"|||##]
위와같이 iOS 프로젝트에서 테스트할시 struct 내부에서 func으로 var를 변경하나 외부에서 var에 직접 접근해서 변경하나 메모리값이 바뀌는 모습을 볼수 있습니다. 즉 위에 설명한 내용과 일치하는 모습을 볼 수 있습니다.