안녕하세요, 오늘은 swift에서 가장 기초적이라고 할 수 있는 Class 와 Structure에 대한 정의를 찾아보고, 이해된 내용을 정리 해보았습니다!
class와 structure 모두 property를 정의하고 method를 추가하여 특별한 기능을 더한 새로운 사용자 정의 데이터 타입을 만들어 내는데 사용됩니다.
또한 사용자 데이터 타입은 데이터를 저장하고, 모델링 하는데 유용하게 사용됩니다.
다른 프로그램 언어와 다르게 Swift에서는 별도의 interface와 implementaition 파일 없이 class와 structure모두 커스텀이 가능합니다.
또한 class 혹은 structure를 단일 파일 안에 여러 번 정의 가능하고, class 또는 structure의 외부 interface는 다른 코드가 사용 할 수 있도록 자동 제공됩니다.
class와 structure는 비슷한점이 있으면서도 차이점도 분명히 존재합니다.
따라서 개발자들은 차이점을 분명히 인지 하고 무엇을 사용할지 적절히 선택하여야 하며, 이는 프로젝트 상의 데이터 저장과 모델링에 있어 매우 효율적일 것 입니다.
(아래에서 더 자세히 알아보겠습니다!)
💡NOTE
An instance of a class is traditionally known as an object. However, Swift structures and classes are much closer in functionality than in other languages, and much of this chapter describes functionality that applies to instances of either a class or a structure type. Because of this, the more general term instance is used.
클래스의 instance는 전통적으로 Object라고 알려져 있지만, Swift에서의 Class 와 Structure는 기능적으로 훨씬 더 다른 언어보다 밀접하기 때문에 더 일반적인 용어인 instance를 사용합니다.
class 와 structure를 적절히 선택하여 사용하기 위해 각각이 가지고 있는 특징에 대해 자세히 알아볼 필요가 있습니다.
우선class와 structure 모두 가지고 있는 기능에 대해 나열해 보겠습니다.
다음은 structure에 없는 class만 가지고있는 추가적인 기능입니다.
class와 structure의 차이점
sturctures 와 enumrations은 Value Type 이다.
class는 Reference Type이다.
class는 Reference Type이기 때문에 RC(Reference Counting)을 사용한다.
- Reference Counting은 클래스 instance의 다중 참조를 허용한다.
즉, structure에 비해 기능이 많은 class를 항상 사용 할 것 같지만, 개발자는 적절한 판단 하에 class와 sturct의 사용을 결정 해야 합니다.
💡 잠깐!! ValueType 과 Reference Type?
Value Type : 변수나 상수에 접근하거나 함수에 전달 될 때, 해당 값을 복사하는 Type
Reference Type : Value Type과 다르게 변수나 상수에 접근, 함수에 전달 될 때에도 값을 복사하지 않고, 동일한 instance의 참조가 사용됩니다.
아래 코드를 보시면 조금 이해가 편하실 것 같습니다!
// Value Type (struct Bottle)
let blueBottle = Bottle(color: "blue", capacity: "200ml")
var greenBottle = blueBottle
greenBottle.color = "green"
print("greenBottle is \(greenBottle.color) color")
print("but blueBottle is still \(blueBottle.color) color")
-----------------------------------------------------------
"greenBottle is green color"
"but blueBottle is still blue color"
-----------------------------------------------------------
// Reference Type (class Bottle)
let redBottle = Bottle(color: "red", capacity: "200ml")
var blackBottle = redBottle
blackBottle.color = "black"
print("blackBottle is \(blackBottle.color) color")
print("redBottle have to red color but redBottle is \(redBottle.color) color")
-----------------------------------------------------------
"blackBottle is black color"
"redBottle have to red color but redBottle is black color"
-----------------------------------------------------------
지금까지 class와 structure의 차이점을 알아봄으로써 각각의 특징을 알아보았습니다!
그렇다면 지금부터는 어떻게, 어떤 기준에 따라서 선택하는지에 대해 알아보겠습니다.😀
Appple Developer에서는 다음과 같이 제안합니다.
또한 각각의 케이스에 대해 자세한 설명을 적었는데, 이를 바탕으로 이해한 내용을 적어보겠습니다.
일반적인 데이터 표현에는 structure로 충분합니다.
Swift의 structure는 다른 언어의 class에서만 사용되는 많은 기능들을 포함하기 때문이며, 게다가 protocol을 구현하여 적용할 수 있습니다.
Swift Foundation의 자주 사용되는 타입인 Number, String, Array 역시 structure를 사용하였습니다.
structure는 Value Type이기 때문에 Local의 변화를 앱에 의도적으로 전달하지 않는 한 앱에 표시되지 않기 때문에 개발자가 앱 전체의 상태를 고려하지 않고 코드의 일부분을 쉽게 판단할 수 있습니다.
Objective-C API를 사용하여 데이터를 처리하거나, Objective-C Framework에 존재하는 클래스의 상속을 받아 데이터 모델을 맞추어야 할때 class 혹은 class 상속을 사용하여야 합니다.
class는 Reference Type이기 때문에 identity 기능이 내장되어 있습니다.
즉, 두 개의 서로 다른 class instance에 저장된 값이 동일한 경우에도 (===) 연산자에 의해 서로 다른 것으로 간주됩니다.
또한 앱에서 class instance를 앱 안에서 공유할 때는 instance에 대한 변경 사항이 해당 instance를 참조하는 코드의 모든 부분에 적용됩니다.
위와 같은 instance가 필요 할 때 class를 사용하세요.
💡Important
Treat identity with care. Sharing class instances pervasively throughout an app makes logic errors more likely. You might not anticipate the consequences of changing a heavily shared instance, so it's more work to write such code correctly.
identity를 다룰때에는 신중해야합니다. class instance들을 앱 전체에서 광범위 하게 공유하는것은 논리 오류를 발생 시킬 확률이 높아집니다.
광범위 하게 공유된 instance를 변경하면 결과를 예상할 수 없을 수도 있습니다. 따라서 이러한 코드를 올바르게 작성하는 것이 중요합니다.
모델링 데이터가 entity의 정보를 포함하고, identity에 대한 신경을 쓸 필요가 없을때, structure를 사용합니다.
예를 들면 앱이 외부 데이터베이스의 데이터를 참조 할때와 같습니다
struct PenPalRecord {
let myID: Int
var myNickname: String
var recommendedPenPalID: Int
}
var myRecord = try JSONDecoder().decode(PenPalRecord.self, from: jsonResponse)
외부 데이터 베이스에서 가져온 JsonResponse를 "PenPalRecord"로 decode 하여 시용합니다.
마지막으로 structure와 class는 모두 상속을 지원합니다만, structure와 protocol은 protocol만을 적용 할 수 있고, class로부터 상속 받을 수 없습니다.
하지만 class를 상속하여 작성하는 유형은 protocol 상속과 structure를 사용하여 모델링할 수도 있습니다.
처음부터 상속 관계를 구축한다면, protocol 상속을 더 선호해 주세요. protocol은 class, structure, enumration이 상속에 참여할 수 있도록 해주는 반면에 class 상속은 다른 class에만 호환되기 때문입니다.
당신이 데이터 모델을 어떻게 할지 선택할때는 먼저 protocol 상속을 사용하여 데이터 타입의 계층을 생성하고, 해당 protocol을 structure에 적용시켜보세요.
Apple에서 제안하는 class와 structure를 선택하는 기준을 알아보았습니다.
모든 내용을 숙지하기 어려워 제가 중요하다고 생각하는 부분만 캐치하여도 좋고,
이 글을 완벽히 정독을 하여도 좋지만, Apple의 원문을 보고 자기 자신만의 해석을 가지는것도 좋다고 생각합니다!
(해석은 사람마다 다를수 있지만, 결국 지향하는 바는 같을테니까요!)
기준을 적으면서 가장 인상 깊었던 내용은 structure를 기본으로 생각하고, class의 상속 계층은 protocol과 sturcture를 통해 구현이 가능하다는 점 이였습니다 😯
지금까지 class를 먼저 생각했던 저를 반성합니다 .. 😅
각각의 기준을 무조건 지켜야 하는것은 아니지만, 적재적소에 활용한다면 더욱 효율적인 코드, 앱이 되겠지요?!
이번 포스팅은 "가장 먼저 알고있어야 하는데 .. 봐야하는데.. 공부해야하는데.. "라고 미뤄두었던 오래된 숙제를 끝낸 느낌입니다.
이 글을 작성하기 전과 이후로 class 와 structure를 대하는 마음가짐이 달라졌다고 저는 확신합니다! (자신감이 +1 상승하였습니다.)
이렇게 미뤄두었던 숙제를 하나씩 끝내면 언젠가는 예습을 하게되는 날도 오겠죠?!
그날까지 열심히 달려보겠습니다.
마지막으로 위에서 말씀드린것과 같이 개인적인 견해를 적은 글임을 다시한번 알려드리며 이번 포스팅을 마치려합니다.
틀린부분에 대한 지적은 언제나 환영합니다 !! 🥺
읽어주셔서 감사합니다!! 🙇
출처
- https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html
- https://developer.apple.com/documentation/swift/choosing_between_structures_and_classes