-
Structures And Classes (Swift)Swift/Swift Language 2021. 11. 1. 16:38
안녕하세요 ! 이번에는 Structure 과 Class 에 대해 Apple Documentation 을 번역하면서 공부할게요 .
Structures and Classes
Structures 와 Classes 는 많은 용도로 다양하게 쓰일 수 있는 constructs 이고, 이것들을 이용해서 program 의 code 가 구성되요. Structures 와 classes 에 properties, methods 를 정의하는 방식으로 기능을 추가할 수 있고, syntax 는 constants, variable,s functions 를 만들때와 같아요.
다른 프로그래밍 언어들과는 다르게 Swift 는 custom structures, classes 에 대해 별개의 interface 와 implementation files 을 만들지 않아도 돼요. 여기서는 structures 또는 classes 를 하나의 파일에 만들면 자동으로 다른 코드에서도 만든 것에 대한 외부 interface 가 사용 가능해집니다.
Note
Class 의 instance 는 object 라고 많이 불리지만 Swift 의 structures 과 classes 는 다른 언어들에 비해 'functionality' 에 훨씬 가깝습니다. 그리고 이번 chapter 에서는 structure, class type 의 instance 에 사용되는 functionality 에 대해 다루겠습니다. 이러한 이유로 'object' 보다 더 general 한 용어 'instance' 가 사용됩니다.Comparing Structures and Classes
Swift 의 Structures 와 classes 는 아래와 같은 많은 공통점을 갖습니다. 둘 모두
- 값을 저장하기 위한 properties 를 정의할 수 있습니다.
- 기능을 주기 위한 methods 를 정의할 수 있습니다.
- values 로 접근하기 위한 subscript 를 정의할 수 있습니다. (subscript syntax 사용)
- deafult implementation 이상으로 functionality 가 확장될 수 있습니다.
- protocol 을 conform 할 수 있습니다.
Classes 가 structures에 비해 추가로 할 수 있는 것들은 다음과 같습니다.
- Inheritance 가 가능합니다. (상속, 다른 class 의 cahracteristics 를 가질 수 있게 함)
- Type casting 이 가능합니다. (runtime 시 class 의 type 을 확인 가능 )
- Deinitialize 할 수 있습니다. (class 의 instance 가 갖고 있던 memory 를 해제 )
- 하나의 instance 에 대해 여러개의 reference 를 가질 수 있습니다.
Class 를 사용할 시 위와 같은 이점을 가질 수 있지만, 그에 따라 복잡성 또한 증가합니다. 가이드라인을 드리자면, 어떻게 코드가 작동하는지 이해하기 비교적 쉽기때문에 structures 사용을 먼저 고려해보고, classes 가 필요하거나 혹은 더 적당한 상황일 때는 class 를 사용하세요. 실제 코드를 작성할 때 대부분의 custom data type은 structures 와 enumerations 가 될겁니다.
Note
Classes 와 actors (Concurrency) 는 많은 특징들과 작동방식에 대해 공통점을 갖습니다.Definition Syntax
Structures 와 classes 를 작성하는 syntax는 비슷하게 생겼어요. 각각 'struct', 'class' keyword 를 앞에 써주시면 되고, definition 전체는 중괄호안에 넣어주세요.
Structures and classes have a similar definition syntax. You introduce structures with the struct keyword and classes with the class keyword. Both place their entire definition within a pair of braces:
struct SomeStructure { // structure definition goes here } class SomeClass { // class definition goes here }
NOTE
새로운 structure 또는 class 를 정의하는 것은 새로운 Swift type 을 정의하는 것과 같습니다. 그렇기때문에 UpperCamelCase names 로 지어주세요 (String, Int, Bool 과 같이 SomeStructure, SomeClass ) .
Properties 와 methods 는 lowerCamelCase 로 type names 와 구분되게 이름을 지어주시면 됩니다.아래는 structure 과 class definition 에 대한 정의입니다.
struct Resolution { var width = 0 var height = 0 } class VideoMode { var resolution = Resolution() var interlaced = false var frameRate = 0.0 var name: String? }
위 예시에서 새로운 Resolution structure 에 대해 정의합니다. 이 structure 은 두개의 stored properties (width, height) 를 갖습니다. Stored properties 는 structure 또는 class 의 일부로 함께 존재하는 constants or variables 입니다. 두 properties 는 모두 초기값 0 을 가지며 Int type 으로 inferred 됩니다.
VideoMode 라는 class 또한 정의하고, 이 class 는 4 개의 variable stored properties 를 갖습니다. 그 중 'resolution' 은 Resolution structure 의 instance 이고, 따라서 property type 은 Resolution 입니다. 'name' 은 optional String type 이고, 초기값으로 nil 을 갖습니다.
Structures and Class Instances
Resolution structure 와 VideoMode class 는 Resolution, VideoMode 가 어떤 것인지에 대해서만 정의합니다. 그것들 자체로는 특정한 resolution 이나 video mode 에 대한 정보를 갖지 않습니다. 갖게 하기 위해서는, instance 를 생성하시면 됩니다.
Structures, Classes 의 instance 를 만드는 syntax 는 아주 비슷합니다.
let someResolution = Resolution() let someVideoMode = VideoMode()
Structures 와 classes 모두 새로운 instance 에 대해 initializer 를 사용합니다. 가장 단순한 형태의 initializer syntax 로 structures, classes 의 type name 뒤에 '()' 를 써주었습니다 ( Resolution(), VideoMode() ) . 이렇게 하면 새로운 instance 가 생기게되고, 모든 properties 는 default values 를 갖습니다.
Accessing Properties
instance 의 properties 에 접근하기 위해 . 을 사용합니다. instance 이름 바로 뒤에 . 을 찍고 property name 을 쓰면 됩니다. (공백없이)
print("The width of someResolution is \(someResolution.width)") // Prints "The width of someResolution is 0"
위 예시에서, someResolution.width 는 someResolution 의 'width' 를 가리키고, 기본 초기값인 0 을 return 합니다.
여러번 사용하면 subproperties(property 의 property) 로 접근할 수도 있습니다.
print("The width of someVideoMode is \(someVideoMode.resolution.width)") // Prints "The width of someVideoMode is 0"
Variable property 에 새로운 값을 할당해줄 때도 . 을 사용합니다.
someVideoMode.resolution.width = 1280 print("The width of someVideoMode is now \(someVideoMode.resolution.width)") // Prints "The width of someVideoMode is now 1280"
Memberwise Initializers for Structure Types
모든 structures 는 자동으로 생성되는 memberwise initializer 를 갖고, 새로운 instances 를 생성할 때 사용할 수 있습니다. 새로운 instance 의 properties 에 할당할 초기값들을 memberwise initializer 내에서 이름별로 전달할 수 있습니다.
All structures have an automatically generated memberwise initializer, which you can use to initialize the member properties of new structure instances. Initial values for the properties of the new instance can be passed to the memberwise initializer by name:
let vga = Resolution(width: 640, height: 480)
Structures 와는 달리 class instances 는 memberwise intializer 가 기본으로 주어지지는 않습니다.
Structures and Enumerations Are Value Types
'value type' 은 variable, constant 에 할당될 때 (또는 function 에 전달될 때 ), 값이 복사되는 type 입니다. 이미 많이많이 사용해보셨을거에요. Swift 의 모든 basic types 는 (Int,Float,Bool, String, Array, Dictionary) 는 value types 이고, 내부에서 구현되어있습니다. Swift 에서 모든 structures, enumerations 는 value types 입니다. 따라서, 모든 structure, enumeration instances (그것들이 properties 로 가지는 value types 포함 ) 는 code 내에서 어딘가 전달될 때 항상 '복사' 됩니다.
NOTE
Standard Library 에서 정의된 Collections (arrays, dictionaries, strings) 는 copy 에 필요한 performance 비용을 줄이기 위해 optimization 을 사용합니다. 다시말하면 직접적으로 복사하는 대신, elements 가 저장되어있는 memory 를 공유합니다. 만약 어떤 복사본의 값이 바뀌게 되면, 바뀌게 되기 바로 전에 복사되는 방식입니다. 따라서 우리가 볼 때는 항상 '복사' 가 일어난 것처럼 보입니다.아래 예시를 한번 보도록 해요.
let hd = Resolution(width: 1920, height: 1080) var cinema = hd
여기서 'hd' 를 Resolution instance(full HD, 1920 x 1080) 인 constant 로 선언해주었습니다. 그 후 'cinema' variable 을 선언하고 'hd' 의 현재 값으로 설정하였습니다. Resolution 이 structure 이기 때문에, 현재 instance 의 복사본이 만들어져 'cinema' 에 할당됩니다. 현재 'hd' 와 'cinema' 는 같은 값을 갖지만, 내부적으로는 전혀 다른 두 instances 입니다.
다음으로, cinema 의 width property 에 2048 을 넣습니다.
cinema.width = 2048
확인을 해보면 실제로 2048 로 값이 변경되었음을 알 수 있습니다.
print("cinema is now \(cinema.width) pixels wide") // Prints "cinema is now 2048 pixels wide"
다음으로 hd 의 width 값을 확인했을 때 여전히 1920 을 값으로 갖고 있음을 볼 수있습니다.
print("hd is still \(hd.width) pixels wide") // Prints "hd is still 1920 pixels wide"
cinema 에 hd 의 현재 값이 주어졌을 때, hd 에 저장된 값이 cinema instance 로 복사됩니다. 결국 두개의 전혀 다른 instances 가 같은 값을 가지고 있게 됩니다. 둘은 별개의 값이기 때문에, cinema width 값을 바꾸는 것은 hd 의 width 값에 어떠한 영향도 주지 않습니다. 그림으로 보면 아래와 같습니다.
Enumerations 도 이와 같은 방식으로 작동합니다.
enum CompassPoint { case north, south, east, west mutating func turnNorth() { self = .north } } var currentDirection = CompassPoint.west let rememberedDirection = currentDirection currentDirection.turnNorth() print("The current direction is \(currentDirection)") print("The remembered direction is \(rememberedDirection)") // The current direction is north // The remembered direction is west
rememberedDirection 에 currentDirection 의 값이 할당될 때, 그 값의 복사본으로 저장됩니다. 따라서 currentDirection 의 값을 바꿔도 rememberedDirection 에 있는 복사본에는 영향을 주지 않습니다.
Structures and Enumerations Are Value Types
Value types 과는 다르게, reference types 는 variable or constant 에 할당되거나 함수에 전달될 때 복사되지 않습니다. 대신, 같은 instance 에 대한 reference 가 사용됩니다.
아래는 VideoMode class 를 이용한 예시 입니다.
let tenEighty = VideoMode() tenEighty.resolution = hd tenEighty.interlaced = true tenEighty.name = "1080i" tenEighty.frameRate = 25.0
예시에서 새로운 constant tenEighty 을 선언하고, VideoMode class 의 instance 를 만들어 refer 하게 설정합니다. 그 후 video mode instance 의 resolution, interlaced, name, frameRate 에 값들을 저장합니다.
그 다음으로, 새로운 alsoTenEighty constant 에 tenEighty 가 할당하고, alsoTenEighty 의 frameRate 를 30.0 으로 변경합니다.
let alsoTenEighty = tenEighty alsoTenEighty.frameRate = 30.0
Classes 는 reference types 이기 때문에, tenEighty 와 alsoTenEighty 는 사실상 같은 VideoMode instance 를 가리킵니다. 다시말하면, 이 둘은 같은 instance 를 갖지만 다른 이름을 가집니다.
tenEighty 의 frameRate 값을 확인하면 alsoTenEighty 와 같은 instance 를 가진다는 것을 볼 수 있습니다.
print("tenEight.frameRate: \(tenEighty.frameRate)") // tenEight.frameRate: 30.0
이 예시는 reference types 을 사용했을 때 코드가 이해하기 어려워 질 수 있다는 것을 보여줍니다. 만약 tenEighty 와 alsoTenEighty 가 code 에서 멀리 떨어져 있다면, video mode 가 바뀌는 방식을 찾아내기 어려울 수 있습니다. tenEighty 를 쓰는 곳마다 alsoTenEighty 를 사용하는 코드 또한 고려해야하고 반대의 경우도 마찬가지입니다. 반면에, value types 는 소스파일 내에서 같은 값을 사용하는 코드가 서로 가까이 있기때문에 더 이해하기 쉽습니다.
tenEighty 와 alsoTenEighty 는 constants 로 선언되었지만 값들(주소) 그 자체는 변하지 않기 때문에 여전히 이 상수들의 properties 를 바꿀 수 있습니다. tenEighty 와 alsoTenEighty 는 VideoMode 의 instance 를 저장하는 대신, 내부에서 가리킵니다. 변하는건 frameRate property (VideoMode 안에 있는 ) 이지 reference 가 아닙니다.
Identity Operators
Classes 가 reference types 이기 대문에, 여러개의 constants 와 variables 가 class 의 instance 하나를 가리키는게 가능합니다 (enum, structure 는 안되요) . 종종 두 constants 나 variables 가 같은 instance 를 가리키는지 확인하면 좋을 때가 있습니다. 이때 사용할 수 있도록 Swift 는 identity operators 를 제공합니다.
- Identical to (===)
- Not identical to (!==)
두가지 operators 를 사용하면 두 constants or variables 가 같은 instance 를 가리키는지 확인할 수 있습니다.
if tenEighty === alsoTenEighty { print("tenEighty and alsoTenEighty refer to the same VideoMode instance.") } // Prints "tenEighty and alsoTenEighty refer to the same VideoMode instance."
'Identical to'(===) operator 는 'equal to' (==) operator 와 다릅니다. Identical to 는 같은 instance 를 가리키는지 확인할 때 사용하고, equal to 는 (type 에 따라 약간 다를 수 있지만) 같은 값을 갖는지 확인합니다. 직접 class 나 structure 를 만들 때, 두개가 같은 것으로 취급될 조건에 대해 정해주어야합니다. 이 과정은 추후 다시 포스팅 하도록 하겠습니다. (Advanced Operators, 포스팅하기)
Pointers
만약 C, C++, Objective-C 에 대해 해보셨다면 이 언어들이 memory 에 있는 addresses 를 refer 할 때 pointers 를 사용한다는 것을 알고있으실 거에요. Swift 에서 reference type 의 instance 를 가리키는 constant 나 variable 는 C 에서의 Pointer 와 유사하지만 memory 내 address 를 직접적으로 가리키는 direct pointer 가 아니며, reference 를 만들고 있다는 표시인 * 을 쓰지 않아도 됩니다. 대신 이 references 는 Swift 에서는 다른 constant, variable 처럼 정의됩니다. pointers 를 직접적으로 사용하는게 필요할 때 쓸 수 있도록 Standard library 에서 pointer 와 buffer types 를 제공합니다. ( Manual Memory Management )
출처: https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html
Structures and Classes — The Swift Programming Language (Swift 5.5)
Structures and Classes Structures and classes are general-purpose, flexible constructs that become the building blocks of your program’s code. You define properties and methods to add functionality to your structures and classes using the same syntax you
docs.swift.org
'Swift > Swift Language' 카테고리의 다른 글
Swift Language ) Error Handling (0) 2021.11.23 Swift Language ) Advanced Operators (0) 2021.11.11 Swift Language ) Closure (0) 2021.10.06 Swift Language) ARC ( Automatic Reference Counting) (0) 2021.10.04 Swift Language ) Generics (0) 2021.09.23