GGURUPiOS

Swift 공식 문서 정리 - (9) Structures and Classes 본문

Swift/공식문서 정리 ( 문법 )

Swift 공식 문서 정리 - (9) Structures and Classes

꾸럽 2023. 4. 27. 20:28

Structures and Classes ( 구조체와 클래스 )

클래스와 구조체는 코드를 조직화 하기 위해 일반적으로 사용함
다른 언어와 다르게 인터페이스 및 구현 파일을 만들 필요가 없음
단일 파일에서 정의하고 클래스 또는 구조체에 대한 외부 인터페이스는 다른 코드에서 사용할 수
있도록 자동으로 제공 됨

클래스의 인스턴스는 전통적으로 객체라고 함. 그러나 스위프트의 구조체와 클래스는 다른 언어보다 기능면에서 인스턴스에 가까움. 그래서 이 장에서는 인스턴스로 부름.

구조체와 클래스 비교

스위프트의 구조와 클래스는 공통점이 많음.

  • 값을 저장하기 위한 프로퍼티 정의
  • 기능을 제공하기 위한 메소드 정의
  • subscript 문법을 이용해 특정 값을 접근할 수 있는 subscript 정의
  • 초기 상태를 설정할 수 있는 initializer 정의
  • 기본 구현에서 기능 확장
  • 특정한 종류의 표준 기능을 제공하기 위한 프로토콜 순응

그 외는 프로퍼티, 메소드, 서브스크립트, 초기화, 확장, 프로토콜 챕터 참조

구조체로는 불가능하고 클래스만 가능한 기능

  • 상속 : 클래스의 여러 속성을 다른 클래스에 물려줌
  • 타입 캐스팅 : 런타임에 클래스 인스턴스의 타입을 확인
  • 소멸자 (Deinitializers) : 할당된 자원을 해제 시킴
  • 참조 카운트 : 클래스 인스턴스에 하나 이상의 참조 가능
    • 구조체는 다른 코드로 전달 될 때 항상 복사되서 전달되고, 참조 카운트 사용 X

그 외는 상속, 타입캐스팅, 소멸자, 자동 참조 카운트 챕터 참조

선언 문법

구조체와 클래스 모두 선언문법은 비슷하다.

struct SomeStructure {
    // structure definition goes here
}
class SomeClass {
    // class definition goes here
}

/* 공식문서에서 
새로운 클래스나 구조체를 선언할 때 마다 새로운 타입을 선언하는 것임
그래서 이름이 다른 표준 스위프트 타입 (String, Int, Bool) 처럼 UpperCamelCase로 작성한다.
반대로 프로퍼티나 메소드는 lowerCamelCase로 선언함
*/

구조체와 클래스 선언의 예

struct Resolution {
    var width = 0
    var height = 0
}
class VideoMode {
    var resolution = Resolution()  // 위 Resolution 구조체를 값으로 사용
    var interlaced = false
    var frameRate = 0.0
    var name: String?
}

Resloution의 프로퍼티 width와 height 는 타입추론으로 자동으로 Int형을 갖게 됨

클래스와 구조체 인스턴스

클래스와 구조체 이름 뒤에 빈 괄호를 적으면 각각의 인스턴스를 생성할 수 있음

let someResolution = Resolution()    // 구조체 인스턴스 생성
let someVideoMode = VideoMode()    // 클래스 인스턴스 생성

프로퍼티 접근

점(dot) 문법을 통해 클래스,구조체 인스턴스의 프로퍼티에 접근 가능

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

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

someVideoMode.resolution.width = 1280 // 점 문법으로 1280 값 할당
print("The width of someVideoMode is now \\(someVideoMode.resolution.width)")
// "The width of someVideoMode is now 1280" 이 출력

구조체형의 멤버 초기화

모든 구조체는 초기화시 프로퍼티를 선언할 수 있는 초기자를 자동으로 생성해 제공

아래와 같은 멤버의 초기화는 구조체 안에 width, height 프로퍼티만 정의했다면 자동으로 사용가능하다는 의미임

구조체와 열거형은 값 타입

값 타입 ? → 함수에서 상수나 변수에 전달될 때 그 값이 복사되서 전달 된다는 의미임

let hd = Resolution(width: 1920, height: 1080)
var cinema = hd

위에서 hd와 cinema는 같은 인스턴스 일까? X

값이 참조가 아닌 복사되었기 때문에 다른 인스턴스임

cinema.width = 2048
print("cinema is now \\(cinema.width) pixels wide")
// "cinema is now 2048 pixels wide" 출력

print("hd is still \\(hd.width) pixels wide")
// "hd is still 1920 pixels wide" 출력

enum CompassPoint {
    case north, south, east, west
}
var currentDirection = CompassPoint.west
let rememberedDirection = currentDirection
currentDirection = .east
if rememberedDirection == .west {
    print("The remembered direction is still .west")
}
// "The remembered direction is still .west" 출력

클래스는 참조 타입

참조 타입은 변수나 상수에 값을 할당 하거나 인자로 전달할 때 그 값이 복사가 아닌 참조가 됨

참조? → 그 값을 갖고있는 메모리를 바라보고 있다는 뜻

let tenEighty = VideoMode() // VideoMode() 의 메모리 주소를 tenEighty가 바라보게 됨
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0

let alsoTenEighty = tenEighty // 여기서 alsoTenEighty 는 tenEighty를 복사하는게 아닌, VideoMode()의 메모리 주소를 똑같이 바라보게(참조) 됨

alsoTenEighty.frameRate = 30.0

print("The frameRate property of tenEighty is now \\(tenEighty.frameRate)")
// "The frameRate property of tenEighty is now 30.0" 출력

식별 연산자 (===, !==)

클래스는 참조 타입이기 때문에 여러 상수와 변수에서 같은 인스턴스를 참조할 수 있다.

두 클래스가 같은 인스턴스를 참조하고 있는지 비교하기 위해 식별 연산자를 사용

  • ===: 같은 인스턴스를 참조하고 있는 경우 참
  • !==: 다른 인스턴스를 참조하고 있는 경우 참

식별 연산자는 비교 연산자와 같지 않다. 식별 연산자는 참조를 비교, 비교 연산자는 값을 비교


구조체와 클래스 중에서 선택

구조체와 클래스는 둘의 유사성으로 서로를 선택하기 어려울 수 있음

그 때는 아래와 같이 권장사항을 고려하자

( 영문 판 공식 문서 )

  • 기본적으로 구조체를 사용하기
  • Objective-C와 상호 운용성이 필요할 때는 클래스를 사용하기
  • 데이터의 ID를 제어해야 하면 클래스를 사용하기
  • 프로토콜과 함께 구조체를 사용하여 구현을 공유하여 동작을 채택합니다.

( 번역 판 )

  • 구조체의 주 목적이 관계된 간단한 값을 캡슐화(encapsulate) 하기 위한 것인 경우
  • 구조체의 인스턴스가 참조되기 보다 복사되기를 기대하는 경우
  • 구조체에 의해 저장된 어떠한 프로퍼티가 참조되기 보다 복사되기를 기대하는 경우
  • 구조체가 프로퍼티나 메소드 등을 상속할 필요가 없는 경우

++++++

아래는 공식문서에 나와있는 내용임.

Use Structures and Protocols to Model Inheritance and Share-Behavior

Structures and classes both support a form of inheritance. Structures and protocols can only adopt protocols; they can’t inherit from classes. However, the kinds of inheritance hierarchies you can build with class inheritance can be also modeled using protocol inheritance and structures.

If you’re building an inheritance relationship from scratch, prefer protocol inheritance. Protocols permit classes, structures, and enumerations to participate in inheritance, while class inheritance is only compatible with other classes. When you’re choosing how to model your data, try building the hierarchy of data types using protocol inheritance first, then adopt those protocols in your structures.

즉 프로토콜은 클래스, 구조체, 열거형 모두 채택이 가능한데, 클래스 상속은 다른 클래스만 가능하기 때문에 데이터 모델링 방법을 선택할 때는 먼저 프로토콜을 사용해서 데이터 계층 구조를 만들고, 구조체에서 채택하라는 말인듯.