* 내가 읽으려고 내 맘대로 번역한 글.
* 원문 : https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html
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 use to define constants, variables, and functions.
구조체와 클래스는 프로그램의 코드를 이루는 범용의 유연한 구조다.
상수, 변수, 함수를 정의할때와 동일한 문법으로 속성과 메소드를 정의해서 너의 구조체와 클래스에 기능을 추가한다.
Unlike other programming languages, Swift doesn’t require you to create separate interface and implementation files for custom structures and classes. In Swift, you define a structure or class in a single file, and the external interface to that class or structure is automatically made available for other code to use.
다른 프로그래밍 언어와 다르게, swift 에서는 structure와 class를 만들때 interface와 implementation 파일을 따로 만들 필요가 없다.
그냥 하나의 파일에 정의하면 된다.
그러면 다른 코드에서 너가 만든 structure 나 class 사용할수 있도록 외부 interface가 자동으로 만들어진다.
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.
클래스의 인스턴스는 전통적으로 객체로 알려져 있다. 다른 언어들에서보다 swift의 구조체와 클래스는 더 기능적으로 비슷하다.
이 장의 많은 부분은 클래스나 구조체 타입의 인스턴스에 적용할수 있는 기능을 설명한다.
이런 이유로 더 일반적인 용어인 인스턴스가 사용된다.
Comparing Structures and Classes
Structures and classes in Swift have many things in common. Both can:
swift에서 구조체와 클래스는 많은 공통점이 있다.
- Define properties to store values
- Define methods to provide functionality
- Define subscripts to provide access to their values using subscript syntax
- Define initializers to set up their initial state
- Be extended to expand their functionality beyond a default implementation
- Conform to protocols to provide standard functionality of a certain kind
- 값을 저장하기 위해서 속성을 정의한다.
- 기능을 제공하기 위해서 메소드를 정의한다.
- 첨자구문을 사용해서 값에 접근할수 있도록 첨자를 정의한다.
- 초기상태를 설정하기 위한 초기화를 정의한다.
- 기본 구현을 확장하기 위해서 확장되기.
- 특정종류의 표준 기능을 제공하기 위하여 프로토콜을 준수한다.
For more information, see Properties, Methods, Subscripts, Initialization, Extensions, and Protocols.
Classes have additional capabilities that structures don’t have:
클래스에는 구조체가 가지지 않은 능력이 더 있다.
- Inheritance enables one class to inherit the characteristics of another.
- Type casting enables you to check and interpret the type of a class instance at runtime.
- Deinitializers enable an instance of a class to free up any resources it has assigned.
- Reference counting allows more than one reference to a class instance.
- 상속은 한 클래스가 다른 클래스의 특성을 상속할수 있게 한다.
- 타입캐스팅은 실행시에 클래스의 인스턴스 타입을 검사하고 해석할수 있게 한다.
- Deinitializer는 클래스의 인스턴스가 할당한 자원들을 해제할수 있게 한다.
- Reference counting은 클래스 인스턴스에 대한 하나 이상의 참조를 허용한다.
For more information, see Inheritance, Type Casting, Deinitialization, and Automatic Reference Counting.
The additional capabilities that classes support come at the cost of increased complexity. As a general guideline, prefer structures because they’re easier to reason about, and use classes when they’re appropriate or necessary. In practice, this means most of the custom data types you define will be structures and enumerations. For a more detailed comparison, see Choosing Between Structures and Classes.
클래스가 지원하는 추가적인 능력은 복잡도가 증가한다는 비용을 치른다.
일반적인 지침에 따라 간단한건 구조체를 쓰고, 적적히 필요한 경우에 클래스를 써라.
실제로 너가 정의하는 대부분의 데이타 타입은 구조체거나 열거형일 것이다.
Definition Syntax
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 키워드, 클래스는 class 키워드. 둘다 중괄호 안에 전체 정의를 넣는다.
struct SomeStructure {
// structure definition goes here
}
class SomeClass {
// class definition goes here
}
NOTE
Whenever you define a new structure or class, you define a new Swift type. Give types UpperCamelCase names (such as SomeStructure and SomeClass here) to match the capitalization of standard Swift types (such as String, Int, and Bool). Give properties and methods lowerCamelCase names (such as frameRate and incrementCount) to differentiate them from type names.
너가 새로운 구조체나 클래스를 정의할때마다, 그것은 새로운 swift의 타입이 된다.
구조체와 클래스 이름에는 UpperCamelCase 형식을 사용하고, 속성이나 메소드 이름음 lowerCamelCase 형식을 사용해라.
Here’s an example of a structure definition and a 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?
}
The example above defines a new structure called Resolution, to describe a pixel-based display resolution. This structure has two stored properties called width and height. Stored properties are constants or variables that are bundled up and stored as part of the structure or class. These two properties are inferred to be of type Int by setting them to an initial integer value of 0.
The example above also defines a new class called VideoMode, to describe a specific video mode for video display. This class has four variable stored properties. The first, resolution, is initialized with a new Resolution structure instance, which infers a property type of Resolution. For the other three properties, new VideoMode instances will be initialized with an interlaced setting of false (meaning “noninterlaced video”), a playback frame rate of 0.0, and an optional String value called name. The name property is automatically given a default value of nil, or “no name value”, because it’s of an optional type.
Structure and Class Instances
The Resolution structure definition and the VideoMode class definition only describe what a Resolution or VideoMode will look like. They themselves don’t describe a specific resolution or video mode. To do that, you need to create an instance of the structure or class.
The syntax for creating instances is very similar for both structures and classes:
- let someResolution = Resolution()
- let someVideoMode = VideoMode()
Structures and classes both use initializer syntax for new instances. The simplest form of initializer syntax uses the type name of the class or structure followed by empty parentheses, such as Resolution() or VideoMode(). This creates a new instance of the class or structure, with any properties initialized to their default values. Class and structure initialization is described in more detail in Initialization.
Accessing Properties
You can access the properties of an instance using dot syntax. In dot syntax, you write the property name immediately after the instance name, separated by a period (.), without any spaces:
print("The width of someResolution is \(someResolution.width)")
// Prints "The width of someResolution is 0"
In this example, someResolution.width refers to the width property of someResolution, and returns its default initial value of 0.
You can drill down into subproperties, such as the width property in the resolution property of a VideoMode:
print("The width of someVideoMode is \(someVideoMode.resolution.width)")
// Prints "The width of someVideoMode is 0"
You can also use dot syntax to assign a new value to a 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
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:
모든 구조체는 자동으로 생성되는 memberwise 생성자가 있어서, 새로운 구조체 인스턴스의 속성들을 초기화하는데 사용할수 있다.
새로운 인스턴스의 속성에 대한 초기값은 memberwisze 생성자에 전달된다.
let vga = Resolution(width: 640, height: 480)
Unlike structures, class instances don’t receive a default memberwise initializer. Initializers are described in more detail in Initialization.
구조체와 다르게, 클래스 인스턴스는 기본 memberwise 생성자가 없다.
Structures and Enumerations Are Value Types
A value type is a type whose value is copied when it’s assigned to a variable or constant, or when it’s passed to a function.
You’ve actually been using value types extensively throughout the previous chapters. In fact, all of the basic types in Swift—integers, floating-point numbers, Booleans, strings, arrays and dictionaries—are value types, and are implemented as structures behind the scenes.
All structures and enumerations are value types in Swift. This means that any structure and enumeration instances you create—and any value types they have as properties—are always copied when they are passed around in your code.
값타입은 상수나 변수나 함수에 전달될때 그 값이 복사되는 타입이다.
실제로 이전 장에서 값타입을 광범위하게 사용했었다.
사실 swift의 기본타입 모두는 (정수, 부동소수숫자, Booleans, 문자열, 배열, dictionary 들) 값 타입이고, 내부에서 구조체로 구현되어 있다.
swift에서 모든 구조체와 열거형은 값타입이다. 이말은 너가 만든 모든 구조체의 인스턴스와 열거형의 인스턴스, 그리고 그 안에 있는 속성들은 항상 다른곳에 전달될때 복사된 값이 전달된다.
NOTE
Collections defined by the standard library like arrays, dictionaries, and strings use an optimization to reduce the performance cost of copying. Instead of making a copy immediately, these collections share the memory where the elements are stored between the original instance and any copies. If one of the copies of the collection is modified, the elements are copied just before the modification. The behavior you see in your code is always as if a copy took place immediately.
배열, dictionary, 문자열등과 같이 표준 라이브러리를 이용하여 정의된 collection 들은 복사할때 필요한 성능 비용을 줄이기 위해 최적화를 사용한다. 즉시 복사하는 대신, 이 collection들은 원본 인스턴스와 복사본들 사이에 저장되는 요소들의 메모리를 공유한다.
만약 collection의 복사본중 하나가 변경되면, 그 요소는 수정되기 바로 전에 복사된다.
코드에서 너가 보는 동작은 즉시 복사본이 생기는 것처럼 보인다.
Consider this example, which uses the Resolution structure from the previous example:
이전 예제에서 사용해떤 Resolution 구조체를 보자.
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
This example declares a constant called hd and sets it to a Resolution instance initialized with the width and height of full HD video (1920 pixels wide by 1080 pixels high).
It then declares a variable called cinema and sets it to the current value of hd. Because Resolution is a structure, a copy of the existing instance is made, and this new copy is assigned to cinema. Even though hd and cinema now have the same width and height, they are two completely different instances behind the scenes.
Next, the width property of cinema is amended to be the width of the slightly wider 2K standard used for digital cinema projection (2048 pixels wide and 1080 pixels high):
이 예제는 hd 라는 상수를 만들고, 넓이와 높이가 full HD video (1920 * 1080)로 초기화된 Resolution 인스턴스가 설정되었다.
그리고 cinema 라는 변수를 만들고 hd 의 현재값을 넣었다.
Resolution은 구조체니까 기존 인스턴스의 복사본이 만들어지고, cinema 에 그 복사본이 할당된다.
지금은 hd와 cinema가 같은 넓이와 높이를 가지고 있지만, 내부에서는 완전히 서로 다른 인스턴스다.
다음은 cinema의 넓이 속성이 디지털씨네마프로젝션에서 사용된 2K 표준 넓이로 약간 수정된다.
cinema.width = 2048
Checking the width property of cinema shows that it has indeed changed to be 2048:
cinema의 넓이 속성은 확실히 2048로 변경되었음을 보여준다.
print("cinema is now \(cinema.width) pixels wide")
// Prints "cinema is now 2048 pixels wide"
However, the width property of the original hd instance still has the old value of 1920:
하지만 원본 hd 인스턴스의 넓이 속성은 아직도 1920 이다.
print("hd is still \(hd.width) pixels wide")
// Prints "hd is still 1920 pixels wide"
When cinema was given the current value of hd, the values stored in hd were copied into the new cinema instance. The end result was two completely separate instances that contained the same numeric values. However, because they are separate instances, setting the width of cinema to 2048 doesn’t affect the width stored in hd, as shown in the figure below:
cinema에 hd의 현재값을 넣었을때, hd 안에 저장된 값들이 복사되어서 cinema 인스턴스에 들어갔다.
그 결과 같은 숫자값을 가지고 있더라도, 2개는 완전히 별도의 Resolution 인스턴스가 되었다.
Resolution의 분리된 인스턴스기 때문에 cinema의 넓이에 2048을 넣어도, hd에 저장된 값에는 영향을 미치지 않는다. 아래그림 처럼.
The same behavior applies to 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)")
// Prints "The current direction is north"
// Prints "The remembered direction is west"
When rememberedDirection is assigned the value of currentDirection, it’s actually set to a copy of that value. Changing the value of currentDirection thereafter doesn’t affect the copy of the original value that was stored in rememberedDirection.
rememberDirection이 currentDirection의 값으로 할당되었을때, 사실은 그 값의 복사본이 할당된것이다.
currentDirection의 값을 변경하는것은 rememberDirection에 저장된 복사본의 값에는 영향이 없다.
Classes Are Reference Types
Unlike value types, reference types are not copied when they are assigned to a variable or constant, or when they are passed to a function. Rather than a copy, a reference to the same existing instance is used.
Here’s an example, using the VideoMode class defined above:
값타입과 다르게, 참조타입은 변수나 상수에 할당되거나 함수에 넘길때 복사되지 않는다.
복사 대신에, 동일한 원본 인스턴스의 참조가 사용된다.
위에서 선언한 VideoMode 클래스의 사용법이 있다.
let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
This example declares a new constant called tenEighty and sets it to refer to a new instance of the VideoMode class. The video mode is assigned a copy of the HD resolution of 1920 by 1080 from before. It’s set to be interlaced, its name is set to "1080i", and its frame rate is set to 25.0 frames per second.
Next, tenEighty is assigned to a new constant, called alsoTenEighty, and the frame rate of alsoTenEighty is modified:
이 예제는 tenEighty라는 새로운 상수를 선언하고, VideoMode 클래스의 새로운 인스턴스를 참조하도록 설정하였다.
video mode는 1920 * 1080 HD 해상도의 복사본이 할당되었다. interlaced 는 true로 설정하고, 이름은 1080i 라고 설정하고,
frame rate는 초당 25.0 프레임으로 설정하였다.
다음 tenEighty은 새로운 상수 alsoTenEighty에 할당되었고, alsoTenEighty의 frame rate를 수정하였다.
let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
Because classes are reference types, tenEighty and alsoTenEighty actually both refer to the same VideoMode instance. Effectively, they are just two different names for the same single instance, as shown in the figure below:
클래스는 참조타입이라서, tenEighty과 alsoTenEighty은 실제로 같은 VideoMode의 인스턴스를 참조한다.
사실상 동일한 하나의 인스턴스에 대해서 이름만 다르게 2개를 가지고 있는것이다. 아래 그림처럼.
Checking the frameRate property of tenEighty shows that it correctly reports the new frame rate of 30.0 from the underlying VideoMode instance:
tenEighty의 frameRate 속성을 조사해보면, VideoMode 인스턴스에 내재된 새로운 frame rate 30.0이 올바르게 보고된다.
print("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
// Prints "The frameRate property of tenEighty is now 30.0"
This example also shows how reference types can be harder to reason about. If tenEighty and alsoTenEighty were far apart in your program’s code, it could be difficult to find all the ways that the video mode is changed. Wherever you use tenEighty, you also have to think about the code that uses alsoTenEighty, and vice versa. In contrast, value types are easier to reason about because all of the code that interacts with the same value is close together in your source files.
이 예제는 참조타입이 추론하기 어려울수 있다는걸 보여준다.
tenEighty와 alsoTenEighty가 너의 코드에서 완전히 떨어져 있다면, video mode가 변경되었는지 찾아내는 방법이 어려울것이다.
tenEighty를 사용할때마다 alsoTenEighty를 사용하는 코드에 대해서 생각해야만 하고 반대의 경우도 마찬가지다.
반면 값타입은 소스파일안에서 같은값이 상호작용하는 코드들이 모두 가깝게 모여있기 때문에 추론하기 쉽다.
Note that tenEighty and alsoTenEighty are declared as constants, rather than variables. However, you can still change tenEighty.frameRate and alsoTenEighty.frameRate because the values of the tenEighty and alsoTenEighty constants themselves don’t actually change. tenEighty and alsoTenEighty themselves don’t “store” the VideoMode instance—instead, they both refer to a VideoMode instance behind the scenes. It’s the frameRate property of the underlying VideoMode that is changed, not the values of the constant references to that VideoMode.
tenEighty와 alsoTenEighty가 변수가 아니고 상수로 선언되었음에 주목해라.
그럼에도 불구하고 tenEighty.frameRate 와 alsoTenEighty.frameRate가 수정될수 있다.
왜냐면 tenEighty와 alsoTenEighty의 상수값 자체는 실제로 변하기 않기 때문이다.
tenEighty와 alsoTenEighty 자체는 VideoMode 인스턴스를 저장하지 않는다. 대신 내부에서 VideoMode 인스턴스를 참조한다.
변하는 것은 VideoMode가 내포하는 frameRate 속성이지, VideoMode를 참조하는 상수의 값이 변하는건 아니다.
Identity Operators
Because classes are reference types, it’s possible for multiple constants and variables to refer to the same single instance of a class behind the scenes. (The same isn’t true for structures and enumerations, because they are always copied when they are assigned to a constant or variable, or passed to a function.)
It can sometimes be useful to find out whether two constants or variables refer to exactly the same instance of a class. To enable this, Swift provides two identity operators:
클래스는 참조타입이기 때문에, 여러개의 상수나 변수가 동일한 하나의 클래스 인스턴스를 참조하는게 가능하다.
(구조체나 열거형에는 적용되지 않는다. 왜냐면 그것들은 상수나 변수에 할당되거나, 함수에 전달될때 항상 복사되기 때문이다)
때로 2개의 상수나 변수가 정확히 같은 클래스의 인스턴스를 참조하는지 알아내는것은 유용하다.
이걸 위해서 swift는 2개의 id(신원확인) 연산자를 제공한다.
Identical to (===)
Not identical to (!==)
Use these operators to check whether two constants or variables refer to the same single instance:
2개의 상수나 변수가 동일한 하나의 인스턴스를 참조하는 확인하기 위해서 이 연산자들을 사용해라.
if tenEighty === alsoTenEighty {
print("tenEighty and alsoTenEighty refer to the same VideoMode instance.")
}
// Prints "tenEighty and alsoTenEighty refer to the same VideoMode instance."
Note that identical to (represented by three equals signs, or ===) doesn’t mean the same thing as equal to (represented by two equals signs, or ==). Identical to means that two constants or variables of class type refer to exactly the same class instance. Equal to means that two instances are considered equal or equivalent in value, for some appropriate meaning of equal, as defined by the type’s designer.
=== 와 == 는 같지 않다는걸 주목해라.
클래스 타입의 상수나 변수가 === 하다는건 정확히 같은 클래스 인스턴스를 참조한다는 뜻이다.
== 는 2개의 인스턴스가 그 타입을 만든사람이 정의한대로 값을 봤을때 동일하다고 여겨지는 것이다.
When you define your own custom structures and classes, it’s your responsibility to decide what qualifies as two instances being equal. The process of defining your own implementations of the == and != operators is described in Equivalence Operators.
너가 구조체나 클래스를 정의할때, 2개의 인스턴스가 동일한지를 결정하는것은 너의 책임이다.
너 자신만의 ==, != 연산자를 정의하는 방법은 여기에 적혀있다.
Pointers
If you have experience with C, C++, or Objective-C, you may know that these languages use pointers to refer to addresses in memory. A Swift constant or variable that refers to an instance of some reference type is similar to a pointer in C, but isn’t a direct pointer to an address in memory, and doesn’t require you to write an asterisk (*) to indicate that you are creating a reference. Instead, these references are defined like any other constant or variable in Swift. The standard library provides pointer and buffer types that you can use if you need to interact with pointers directly—see Manual Memory Management.
너가 c, c++, objective-c에 경험이 있다면, 메모리에서 주소를 참조하는 포인터를 알것이다.
swift에서 참조타입의 인스턴스를 참조하는 상수나 변수는 c의 포인터와 비슷하지만
메모리의 주소에 대한 직접 포인터가 아니고, 너가 만든 참조를 가르키기 위해서 별표(*)를 쓸 필요가 없다.
대신 이러한 참조들은 swift의 다른 상수나 변수처럼 정의된다.
직접 포인터가 필요한 경우를 위해 표준 라이브러리는 pointer와 버퍼타입을 제공한다.
'iOS 초보' 카테고리의 다른 글
[swift5.1번역] 11.Methods (0) | 2019.08.19 |
---|---|
[swift5.1번역] 10.Properties (0) | 2019.08.14 |
[swift5.1번역] 8.Enumeration (0) | 2019.08.01 |
[swift5.1번역] 7.Closures (0) | 2019.07.25 |
[swift5.1번역] 6.Functions (0) | 2019.07.09 |