Structures and Classes

이원희·2021년 3월 11일
0

 🐧 Swift

목록 보기
29/32
post-thumbnail

오늘은 struct와 class에 대해서 알아보자.
둘의 차이점에 초점을 맞춰서 알아보려 한다.

Struct 그리고 Class

참고

structclass 프로그램에서 범용적이고 유연한 구조를 가진 코드 블록이다.
상수, 변수, 함수를 정의할때와 같은 구문으로 structclass에 기능을 추가하는 property와 method를 정의한다.


Struct와 Class를 비교해보자.

structclass프로그램을 구성하는데 필요한 블록을 만드는 용도이다.
그렇다면 structclass의 공통점과 차이점에 대해 알아보자.

공통점

  • 값을 저장하기 위해 property를 정의
  • 기능 수행을 위해 method를 정의
  • subscript 문법을 통해 struct 또는 class property에 접근할도록 subscript 정의 가능
  • 초기화될 때의 상태를 지정하기 위해 이니셜라이저 정의 가능
  • extension을 통해 확장 가능
  • 특정 기능을 수행하기 위해 특정 프로토콜 준수 가능

struct는 불가능하지만 class는 가능한 추가적인 기능

  • 상속 가능
  • 타입 캐스팅 가능
  • Deinitializer로 클래스의 인스턴스가 할당된 리소스를 해제 가능
  • reference counting

class의 추가 기능은 복잡성이 증가한다.
일반적으로는 추론이 쉬운 struct를 권장하고, 필요할 때 class를 사용하라고 한다.


struct와 class의 가장 큰 차이점

위에서 structclass의 공통점과 차이점에 대해 알아봤다.
위의 차이점 말고도 structclass의 가장 큰 차이점이 있다.
struct는 value type이고, class는 reference type이다.
하나씩 살펴보자.


struct is value type

value type은 변수 또는 상수에 할당되거나 함수에 전달 될때 값이 복사되는 유형이다.
Swift의 모든 기본 유형(integers, floating-point, numbers, Booleans, strings, arrays, dictionaries)들은 value type이고, struct로 구현되어 있다.

모든 structenum은 Swift에서 value type이다.
즉, 코드에서 전달될 때 항상 복사된다.

Array, dictionary, string 같은 표준 라이브러리에 의해 정의된 collection은 복사 성능 비용을 줄이는 최적화를 사용한다.
이런 collection은 바로 복사본을 만드는 대신 원본 인스턴스와 복사본 간에 메모리를 공유한다.
collection의 복사본 중 하나가 수정되면 수정 직전에 요소가 복사된다.

struct Resolution {
	let width: Int
    let height: Int
}

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

hd에 Resolution 인스턴스를 선언했다.
cinemahd를 선언했다.

그리고 이후에

cinema.width = 2048

cinema의 width 값을 변경했다.

  • struct는 value type으로 변수 또는 상수에 전달 될때 값이 복사된다고 했다.
  • 하지만 복사는 최적화로 인해 곧바로 일어나지 않고 복사본 중 하나가 수정되면 수정 직전에 요소가 복사된다고 했다.
  • 복사 이전에는 원본 인스턴스와 복사본 간에 메모리를 공유하고 있다.

위의 사항을 생각하면서 코드를 다시 살펴보자.


var cinema = hd

cinemahd를 지정했으므로 cinema가 생성된다.
아직 수정이 일어나지 않았으므로 원본 인스턴스와 메모리를 공유한다.


cinema.width = 2048

cinema의 프로퍼티 값을 변경했으므로 이제 복사본이 생성된다.


class is reference type

reference type은 value type과 다르게 변수 또는 상수에 할당되거나 함수에 전달될 때 복사되지 않는다.
복사본 대신 원본 인스턴스의 참조를 사용한다.

class VideoMode {
	let resolution: String
    let interlaced: Bool
    let name: String
    let frameRate: Double
}

let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0

let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0

tenEighty에 VideoMode 인스턴스를 선언했다.
alsoTenEightytenEighty를 선언하고, alsoTenEighty의 frameRate 값을 변경했다.

VideoMode는 reference type으로 reference를 공유한다고 했다.
따라서 After 상태를 보면 tenEightyalsoTenEighty가 같은 인스턴스인 것을 확인할 수 있다.

alsoTenEighty의 frameRate 값을 변경했지만 tenEighty와 같은 인스턴스이기 때문에

print(tenEighty.frameRate)

를 하게되면 30.0이 출력되는 모습을 확인할 수 있다.


Identity Operators

class는 reference type이므로 tenEightyalsoTenEighty처럼 같은 인스턴스를 참조하고 있을 수 있다.
상수 또는 변수가 동일한 클래스 인스턴스를 참조하는지 확인하기 위한 연산자가 있다.

  • ===
  • !==

흐음... 딱 생긴게 위에꺼는 같은 인스턴스인지 아래는 같은 인스턴스가 아닌지를 구별하는거네...ㅋㅋㅋ


그럼 언제 struct를 사용하고 언제 class를 사용할까

Apple에서 친절하게 가이드 해주고 있다.

structclass는 앱에서 데이터를 저장하고 동작을 모델링하는데 좋은 선택이지만 유사성으로 인해 서로를 선택하기 어려울 수 있다.
(맞아요...)
앱에 새 데이터 type을 추가할 때 적합한 옵션을 선택하려면 아래의 권장 사항을 고려해 봐라!
(네..)

  • 기본적으로 struct를 사용
  • Objective-C와 상호 운용이 필요할 때에는 class 사용
  • 모델링하는 데이터의 ID를 제어해야 할 때에는 class 사용
  • 구현부를 공유하면서 동작을 채택할 때에는 protocol과 함께 struct를 사용

하나씩 살펴보자.


기본적으로 struct를 사용

Swift의 struct에는 다른 언어에서는 class에서만 사용할 수 있는 기능들을 사용할 수 있다.
Swift의 structprotocol을 채택해 기본 구현을 얻을 수 있다.
(structclass와 달리 상속 받을 순 없지만 protocol을 채택함으로써 공통적으로 가져야 하는 구현부를 공유할 수 있다는 얘기 같음)

struct는 value type이기 때문에 struct의 변경은 의도적으로 다른 곳으로 전달하지 않는 한 표시되지 않는다.
(reference type인 경우 reference를 공유하기 때문에 하나가 변경되면 다른 곳의 변수 혹은 상수도 변경된다.)
따라서 struct 인스턴스 변경은 명시적으로 변경된다.
(즉, 해당 struct 인스턴스를 변경해도 다른 인스턴스에는 영향이 없다는 말)


Objective-C와 상호 운용이 필요할 때에는 class 사용

데이터를 처리해야하는 Objective-C API를 사용하거나 Objective-C 프레임워크에 정의된 클래스에 데이터 모델을 적용해야하는 경우 class를 사용해야 한다.


모델링하는 데이터의 ID를 제어해야 할때에는 class 사용

Swift의 class는 reference type으로 ID 개념이 내장되어 있다.
두 개의 서로 다른 클래스 인스턴스가 동일한 값을 가질 때 ===(ID 연산자)로 서로 다른 인스턴스임을 알 수 있다.

class 인스턴스는 다른 상수 혹은 변수와 reference를 공유할 수 있으므로 인스턴스가 변경된다면 reference를 공유하는 모든 곳에서 변경을 알 수 있다.


구현부를 공유하면서 동작을 채택할 때에는 protocol과 함께 struct를 사용

structclass는 모두 상속을 지원한다.
(오잉... 우리 여태 struct는 상속이 불가능하다고 했는데...!)

structclass를 상속할 수는 없지만 protocol을 채택해 상속을 지원할 수 있다.
class 상속 계층 구조를 protocolstruct를 사용해 모델링 할 수 있다.
(오호... 그럼 class 상속은 안되지만 protocol을 이용해 상속 비스무리하게 할 수 있나보다!)

protocolclass, struct, enum 모두 채택할 수 있어 상속을 지원할 수 있지만, class 상속은 class에서만 호환된다.

protocol로 상속을 지원할 때에는 우선 protocol 상속을 통해 상속 계층을 모델링 한뒤, struct에서 protocol을 채택하도록 해라.


정리

structclass를 결정하는때 Apple에서 제공하는 고려 사항을 알아봤다.
Apple은 다음 조건 중 하나 이상에 해당한다면 struct를 사용하는 것을 권장한다.

  • 연관된 간단한 값의 집합을 캡슐화하는 것만이 목적일 때
  • 캡슐화한 값을 참조하는 것보다 복사하는 것이 합당할 때
  • struct에 저장된 property가 value type이며 참조하는 것보다는 복사하는 것이 합당할 때
  • 다른 타입으로부터 상속받거나 자신을 상속할 필요가 없을 때

struct를 사용하면 안 될때는 언제가 있을까?

  • Singleton에서는 하나의 인스턴스를 여러 곳에서 공유하면서 사용해야 한다.
  • View와 ViewController의 경우도 공유되어야 한다.

마무리

오늘은 structclass에 대해 알아봤다.
사실 깊게 들어가면 끝도 없지만...!
오늘은 이정도로 마무리!
그럼 이만👋

0개의 댓글