🔥 구조체와 클래스 비교

628자
9분

구조체와 클래스는 Swift에서 사용자 정의 타입을 만들기 위한 강력한 도구로, 많은 공통점을 가지고 있습니다. 하지만 동시에 몇 가지 중요한 차이점도 존재하죠. 하나씩 살펴볼까요?

구조체와 클래스의 공통점

구조체와 클래스는 다음과 같은 기능을 공통적으로 제공합니다:

  • 값을 저장하기 위한 속성(Property) 정의
  • 기능을 제공하기 위한 메서드(Method) 정의
  • 첨자 연산(Subscript)을 통해 값에 접근하는 문법 제공
  • 초기 상태를 설정하기 위한 이니셜라이저(Initializer) 정의
  • 기본 구현 이외의 기능 확장(Extension)
  • 특정 종류의 표준 기능을 제공하기 위한 프로토콜(Protocol) 채택

이러한 공통점들 덕분에 구조체와 클래스는 Swift에서 매우 유연하고 강력한 도구로 사용될 수 있습니다.

클래스만의 추가 기능

하지만 클래스는 구조체에는 없는 몇 가지 추가 기능을 가지고 있습니다:

  • 상속(Inheritance)을 통해 다른 클래스의 특성을 물려받을 수 있음
  • 타입 캐스팅(Type Casting)을 통해 런타임에 클래스 인스턴스의 타입을 확인하고 해석할 수 있음
  • 디이니셜라이저(Deinitializer)를 통해 클래스 인스턴스가 할당한 자원을 해제할 수 있음
  • 참조 카운팅(Reference Counting)을 통해 하나의 클래스 인스턴스에 대한 여러 참조를 허용함

이러한 추가 기능들은 클래스를 더욱 유연하게 만들어주지만, 동시에 복잡성을 증가시키기도 합니다. 따라서 Apple의 가이드라인에 따르면 추론하기 쉬운 구조체를 선호하고, 필요할 때만 클래스를 사용하는 것이 좋다고 합니다. 실제로 대부분의 사용자 정의 타입은 구조체와 열거형으로 정의합니다.

구조체와 클래스 정의 문법

그럼 구조체와 클래스는 어떻게 정의할까요? 둘 다 매우 비슷한 문법을 가지고 있습니다. 구조체는 struct 키워드로, 클래스는 class 키워드로 도입하며, 각각의 전체 정의는 중괄호 {} 내에 위치합니다.

struct SomeStructure {
    // 구조체 정의
}
 
class SomeClass {
    // 클래스 정의
}
swift

간단한 예시를 통해 살펴보도록 하죠.

struct Resolution {
    var width = 0
    var height = 0
}
 
class VideoMode {
    var resolution = Resolution()
    var interlaced = false
    var frameRate = 0.0
    var name: String?
}
swift

위 예제에서는 먼저 Resolution이라는 새로운 구조체를 정의합니다. 이 구조체는 픽셀 기반 디스플레이 해상도를 나타내며, widthheight라는 두 개의 저장 속성을 가지고 있어요. 저장 속성은 구조체나 클래스의 일부로 묶여서 저장되는 상수 또는 변수를 말하죠. 두 속성은 초기값으로 0을 갖기 때문에 Int 타입으로 추론됩니다.

다음으로는 VideoMode라는 새로운 클래스를 정의합니다. 이 클래스는 비디오 디스플레이를 위한 특정 비디오 모드를 나타내며, 4개의 저장 속성을 가지고 있어요.

  • resolution: 새로운 Resolution 구조체 인스턴스로 초기화되며, Resolution 타입으로 추론됨
  • interlaced: false로 초기화되어 비월행주사(noninterlaced) 비디오를 나타냄
  • frameRate: 0.0으로 초기화되어 재생 프레임 레이트를 나타냄
  • name: 옵셔널 String 값으로, nil을 기본값으로 가짐

구조체와 클래스의 인스턴스 생성

위에서 정의한 Resolution 구조체와 VideoMode 클래스는 단지 해당 타입이 어떻게 생겼는지만 설명할 뿐, 실제 해상도나 비디오 모드를 나타내지는 않습니다. 이를 위해서는 해당 구조체나 클래스의 인스턴스를 생성해야 해요.

인스턴스를 생성하는 문법도 구조체와 클래스가 매우 유사합니다.

let someResolution = Resolution()
let someVideoMode = VideoMode()
 
swift

구조체와 클래스 모두 새로운 인스턴스를 위해 이니셜라이저 문법을 사용하죠. 가장 간단한 형태의 이니셜라이저 문법은 타입 이름 뒤에 빈 괄호()를 사용하는 것입니다. 이렇게 하면 해당 클래스나 구조체의 새 인스턴스가 생성되며, 모든 속성은 기본값으로 초기화됩니다.

속성 접근

인스턴스의 속성은 dot syntax를 사용하여 접근할 수 있습니다. dot syntax에서는 인스턴스 이름 바로 뒤에 점(.)을 붙이고, 띄어쓰기 없이 속성 이름을 작성합니다.

print("The width of someResolution is \(someResolution.width)")
// "The width of someResolution is 0" 출력
swift

위 예제에서 someResolution.widthsomeResolutionwidth 속성을 참조하며, 기본 초기값인 0을 반환하죠.

또한 서브 속성으로 내려가는 것도 가능합니다. 예를 들어 VideoModeresolution 속성 내부의 width 속성에 접근할 수 있어요.

print("The width of someVideoMode is \(someVideoMode.resolution.width)")
// "The width of someVideoMode is 0" 출력
swift

dot syntax를 사용하여 변수 속성에 새로운 값을 할당할 수도 있습니다.

someVideoMode.resolution.width = 1280
print("The width of someVideoMode is now \(someVideoMode.resolution.width)")
// "The width of someVideoMode is now 1280" 출력
swift

구조체 타입을 위한 멤버와이즈 이니셜라이저

모든 구조체는 memberwise initializer를 자동으로 생성합니다. 이를 통해 새로운 구조체 인스턴스의 멤버 속성을 초기화할 수 있죠. 새 인스턴스의 속성 초기값은 이름을 통해 멤버와이즈 이니셜라이저에 전달될 수 있습니다.

let vga = Resolution(width: 640, height: 480)
swift

반면에 클래스 인스턴스는 기본 멤버와이즈 이니셜라이저를 생성하지 않습니다.

지금까지 Swift에서의 구조체와 클래스에 대해 알아보았습니다. 둘 사이의 공통점과 차이점을 잘 이해하고, 상황에 맞게 적절히 사용할 수 있어야 합니다.