티스토리 뷰

1. Structures and Classes

Swift 가 제공하는 형식 외에 직접 형식을 지정할 수 있는데 이런 형식을 Custom Data Type 이라고 합니다.

Custom Data Type 은 Enumeration, Structure, Class 가 있습니다.

 

Custom Data Type 에 대해 알아보기 전 간단하게 Programming Paradigm 에 대해 살펴보겠습니다.

Swift 의 Programming Paradigm
- Object-Oriented Programming (객체지향)
- Protocol-Oriented Programming
- Functional Programming

객체 지향 프로그래밍은 프로그래밍에서 처리하는 모든 데이터를 객체로 만들고, 객체의 상태와 동작을 조작해서 원하는 기능을 구현하는 것을 말합니다.

 

객체가 가진 여러가지 요소 중에서 프로그램에서 처리할 요소들을 도출하는 과정을 추상화라고 하며 추상화의 결과를 코드로 표현한 것을 Class 라고 합니다. Class 는 객체의 특징과 상태는 속성으로 구현하고 객체의 동작은 메소드로 구현한 것입니다. 클래스를 통해 여러 개의 객체 즉, 인스턴스를 생성할 수 있습니다.

객체들은 다른 객체의 속성을 바꾸거나 메소드를 호출하는 등의 상호작용을 하는데 이를 메시지를 보낸다고 합니다. Apple 이 제공하는 개발 환경인 cocoa 에서는 메시지를 보내는 객체를 sender 받는 객체를 receiver 라고 합니다.

객체지향에서는 새로운 형식을 만들 때 대부분 클래스로 구현하고 비교적 작은 데이터를 저장하거나 값 형식이 필요한 경우에만 구조체로 구현합니다.
Swift 에서는 클래스가 가진 대부분의 기능을 구조체에서도 제공합니다. 프로토콜 지향 프로그래밍이나, 함수형 프로그래밍에서는 새로운 형식을 구현할 때 보통 구조체로 구현합니다.

 

간단하게 클래스와 구조체를 코드로 살펴보겠습니다.

import UIKit

/*
 # Structure
 */

// 문법
// struct StructName {
//     property
//     method
//     initializer
//     subscript
// }

// 형식 내부에 구현하는 요소를 멤버라고 함
// property, method, initializer, subscript

struct Person {
    var name: String
    var age: Int
    
    func speak() {
        print("Hello")
    }
}

let p = Person(name: "Steve", age: 50)
p.name     // 결과: "Steve"
p.age      // 결과: 50

// 함수는 이름만으로 호출이 가능하지만, 메소드는 인스턴스 이름으로 접근해 호출
p.speak()  // 결과: "Hello"

/*
 # Class
 */

// 문법
// class ClassName {
//     property
//     method
//     initializer
//     deinitializer (소멸자)
//     subscript
// }

class PersonClass {
    var name = "John Doe"
    var age = 30
    
    func speak() {
        print("Hello")
    }
}

let pc = PersonClass()
pc.name     // 결과: "John Doe"
pc.age      // 결과: 30
pc.speak()  // 결과: "Hello"

 

 

구조체 역시 클래스와 마찬가지로 설계도 역할을 하는데 클래스와 달리 객체라고 부르지 않고 값이라고 부릅니다.
그리고 다른 언어에서는 클래스로 구현한 객체를 인스턴스라고 부르지만 스위프트에서는 형식에 관계 없이 모두 인스턴스라고 부릅니다.

정리해보면, 
- Structure 와 Class 는 새로운 형식을 만들 때 사용하며 인스턴스는 생성자 문법으로 생성합니다.
- 형식에는 속성, 메소드, 생성자, subscript 를 추가합니다.
- extension 을 통해 형식을 확장하거나 Protocol 을 채용하는 것도 가능합니다.

- 구조체와 클래스는 저장 공간을 처리하는 방식에 차이가 있습니다.


구조체는 stack 이라고 부르는 메모리 공간에 값을 저장합니다. 그리고 값을 전달할 때마다 복사본을 생성합니다. 이런 형식을 값 형식(Value Type)이라고 부르는데 기본 자료형과 열거형 모두 값 형식에 속합니다.


반대로 클래스는 heap 이라고 부르는 공간에 값을 저장합니다. stack 에는 heap 에 저장되어 있는 값의 주소를 저장합니다. 값을 전달하면 복사본을 생성하지 않고 주소만 전달합니다. 이런 형식은 참조 형식(Reference Type)이라고 합니다. Swift 에서는 클래스와 클로저가 참조 형식에 포함됩니다.

- 소멸자(deinitializer), 상속(Inheritance), (Reference Counting) 은 클래스 전용입니다.

- 마지막으로 메모리 관리 방식에도 차이가 있습니다.
값 형식의 구조체는 인스턴스가 속한 scope 가 종료되면 메모리에서 자동으로 제거되지만, 참조 형식인 클래스는 scope 에 관계 없이 reference counting 을 통해 메모리를 관리합니다.

 

2. Initializer Syntax

생성자는 인스턴스를 만들 때 사용하는 특별한 메소드를 말합니다. 생성자는 모든 속성의 초기값을 저장하는데 이 과정을 인스턴스 초기화라고 합니다. 생성자의 목적은 속성을 초기화하는 것입니다. 따라서 생성자 실행이 종료되는 시점에는 모든 속성의 초기값이 저장되어 있어야 합니다.

// 문법
// init(parameters) {
//     statements
// }

class Position {
    var x: Double
    var y: Double
    
    init() {
        x = 0.0
        y = 0.0
    }
    
    init(value: Double) {
        x = value
        y = value
    }
}

let a = Position()
a.x  // 결과: 0
a.y  // 결과: 0

let b = Position(value: 100)
b.x  // 결과: 100
b.y  // 결과: 100

 

3. Value Types and Reference Types

Value Types(값 형식)은 stack 이라는 메모리 공간에 데이터를 저장하며, 값을 전달할 때마다 복사본을 생성합니다. 값 형식에 해당하는 타입은 Structure, Enumeration, Tuple 등이 있습니다.

Reference Types(참조 형식)은 heap 이라는 메모리 공간에 데이터를 저장하고, stack 에는 메모리의 주소를 저장하게 됩니다. 값을 전달할 때는 복사본을 생성하지 않고 주소만 전달합니다. 참조 형식에 해당하는 타입은 Class, Closure 가 있습니다.

// Value Type
struct PositionValue {
    var x = 0.0
    var y = 0.0
}

// Reference Type
class PositionObject {
    var x = 0.0
    var y = 0.0
}

var v = PositionValue()
var o = PositionObject()

var v2 = v
var o2 = o

v2.x = 12
v2.y = 34

v   // x = 0, y = 0
v2  // x = 12, y = 34

o2.x = 12
o2.y = 34

o   // x = 12, y = 34
o2  // x = 12, y = 34

 

새로운 형식을 생성할 때 일반적인 규칙을 살펴보면 다음과 같습니다.

 

- 객체 지향 프로그래밍에서는 대부분 참조 형식인 클래스로 구현하고 상대적으로 적은 데이터를 처리하고 상속이 필요하지 않다면 값 형식으로 구현합니다.

- 값이 전달되는 시점마다 복사본이 생성되어야 하는 경우에도 마찬가지로 값 형식으로 구현합니다.

- 연관된 상수 그룹을 표현할 때는 열거형으로 구현하고 코드 내에서 한번만 사용되는 형식은 튜플로 구현합니다.

- 나머지 값 형식은 모두 구조체로 구현합니다.

- 프로토콜 지향 프로그래밍과 함수형 프로그래밍에서는 주로 구조체로 구현하고 상속을 구현해야 하거나 참조를 전달해야 하는 경우에만 클래스로 구현합니다.

 

4. Identity Operators

Value Type 과 Reference Type 은 동일성 비교 방식에 차이가 있습니다.

Value Type(값 형식)이 저장되는 메모리 공간은 stack 입니다. 하나의 공간에 저장되기 때문에 이 값을 비교하기 위해서는 비교 연산자 하나로 충분합니다.

Reference Type(참조 형식)은 값을 heap 에 저장하고 메모리 주소를 stack 에 저장합니다. 두 개의 공간에 저장되기 때문에 비교하는 방법도 2가지가 필요합니다. 값을 비교할 때는 값 형식과 마찬가지로 비교 연산자를 사용합니다. 반면 메모리 공간을 비교할 때는 항등 연산자가 필요합니다.

// 문법
// classInstance === classInstance
// classInstance !== classInstance

// === : Identical to Operator 인스턴스의 주소가 같으면 true
// !== : Not Identical to Operator 인스턴스의 주소가 다르면 true

class A {
    
}

let a = A()
let b = a
let c = A()

a === b  // true
a !== b  // false

a === c  // false
a !== c  // true

 

5. Nested Types

포함된 형식, 내포된 형식으로 형식 내부에 선언된 형식을 말합니다.

class One {
    struct Two {
        enum Three {
            case a
            
            class Four {
                
            }
        }
    }
    
    var a = Two()
}

let two: One.Two = One.Two()

let four: One.Two.Three.Four = One.Two.Three.Four()

let a = One.Two.Three.a
a
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함