728x90
반응형

구조체와 클래스는 비슷한 점도 있지만 다른 점도 분명하게 있다고 생각한다.
그래서 구조체와 클래스를 비교해서 정리하기로 했다.

구조체와 클래스의 공통점

- 값을 저장하기 위한 프로퍼티를 정의한다.

- 기능성을 제공하기 위한 메소드를 정의한다.

// 구조체 정의
struct People {
    // 값을 저장하기 위한 프로퍼티 정의
    var name: String = "jaynam"
    var age: Int = 28
    var gender: String = "male"
    
    // 기능성 제공을 위한 메서드 정의
    func getPeopleInfo() {
        print("Name : \(name) , Age : \(age) , Gender : \(gender)")
    }
}


// 클래스 정의
class Computer {
    // 값을 저장하기 위한 프로퍼티 정의
    var cpu: String = "AMD"
    var mem: Int = 16
    var disk: String = "1TB"
    
    // 기능성 제공을 위한 메서드 정의
    func getComputerInfo() {
        print("CPU : \(cpu) , MEMORY : \(mem) , DISK : \(disk)")
    }
}

- subscript 문법을 사용하는 값에 접근하기 위한 subscript 문법을 정의한다.

struct Weight {
    let book: Int
    
    // 서브스크립트 선언
    subscript(cnt: Int) -> Int {
    	// set 인자가 따로 없기 때문에 get으로 동작
        return book * cnt
    }
}

let myBagWeight = Weight(book: 3)
print("my bag weight is \(myBagWeight[3])")

========== 출력 결과 ==========
my bag weight is 9

간단하게 서브 스크립트를 생성해서 출력해보았다.
프로퍼티와 메서드와 같이 선언을 할 수 있고 다만 서브스크립트는 read-write 와 read only 만 가능하다고 한다.
지금은 간단하게 사용만 해봤지만 서브 스크립트에 대한 옵션 등과 같이 자세한 내용은 아래의 참고사이트에 자세히 설명되어 있다.

- 초기화 상태를 설정하기 위한 initializer 를 정의한다.
초기화는 init() 이라는 함수를 통해서 초기화를 설정해줄 수 있다.

class Temperature {
    var temp: Double
    
    init() {
        temp = 36.5
    }
}

var t = Temperature()
print("Now temperature is \(t.temp)")

만약 프로퍼티가 초기값을 가져야 한다면 초기화에서 설정하는 것보다 기본 값을 정해주는 것이 좋다.
이 외에도 인자 레이블을 통해서 초기화 하는 방법도 있다.

class Temperatures {
    let temp: Double
    
    init(temp: Double) {
        self.temp = temp
    }
    
    func getTemp() {
        print("Now temperature is \(temp)")
    }
}

let tt = Temperatures(temp: 30.5)
tt.getTemp()

========== 출력 결과 ==========
Now temperature is 30.5

인자 레이블을 통해서 초기화를 하는 등 다양한 방법으로 초기화를 시킬 수 있다는 점을 알아두자.
이 부분에 대한 내용도 아래의 참고 사이트에서 자세하게 공부할 수 있다.

- 기본적인 구현을 넘어서 기능성을 확장한다.

- 특정한 종류의 표준 기능성을 제공하기 위한 프로토콜을 정한다.

- 초기 구현과 더불어 새로운 기능 추가를 위해 익스텐션을 통해 확장할 수 있다.


구조체와 클래스의 차이점

가장 큰 차이로는 구조체는 값 타입이고 클래스는 참조 타입이라는 점이다.
C 언어의 포인터와 유사한 개념이라고 한다.

구조체

구조체를 정의하고 인스턴스를 생성하고 초기화 하고자 할 때에는 기본적으로 생성되는 멤버와이즈 이니셜라이저를 사용한다.
구조체에 기본 생성된 이니셜 라이저의 매개변수는 구조체의 프로퍼티 이름으로 자동 지정된다.
인스턴스가 생성되고 초기화한 후에 프로퍼티 값에 접근해서 수정할 수 있다.
프로퍼티가 상수 let 이면 변경할 수 없고, 변수 var 이면 변경할 수 있다.
그리고 클래스와 달리 상속할 수 없다.

// 구조체 정의
struct People {
    // 값을 저장하기 위한 프로퍼티 정의
    var name: String = "jaynam"
    var age: Int = 28
    var gender: String = "male"
    let country: String = "Korea"
    
    // 기능성 제공을 위한 메서드 정의
    func getPeopleInfo() {
        print("Name : \(name) , Age : \(age) , Gender : \(gender) , Country : \(country)")
    }
}

// 자동으로 이니셜라이저를 사용해서 구조체를 생성할 수 있다.
var me: People = People(name: "nam", age: 27, gender: "male")
me.getPeopleInfo()

me.age = 30
// 에러 발생
//me.country = "ENG"

me.getPeopleInfo()

========== 출력 결과 ==========
Name : nam , Age : 27 , Gender : male , Country : Korea
Name : nam , Age : 30 , Gender : male , Country : Korea

클래스

클래스를 정의하는 방법은 구조체와 비슷하다.
다만, 클래스는 상속받을 수 있기 때문에 상속받을 때에는 클래스 이름 뒤에 콜론을 써주고 부모 클래스 이름을 명시한다.

class [클래스 이름] : [부모 클래스 이름] {
	[프로퍼티, 메서드 생성]
}

클래스의 인스턴스를 생성하고 초기화 할 때는 기본적인 이니셜라이저를 사용한다.
구조체와 다르게 자동으로 이니셜라이저를 사용할 수 없다.

// 클래스 정의
class Computer {
    // 값을 저장하기 위한 프로퍼티 정의
    var cpu: String = "AMD"
    var mem: Int = 16
    var disk: String = "1TB"
    
    // 기능성 제공을 위한 메서드 정의
    func getComputerInfo() {
        print("CPU : \(cpu) , MEMORY : \(mem) , DISK : \(disk)")
    }
}

// 에러 발생
//var cominfo: Computer = Computer(cpu: "intel", mem: 32, disk: "500GB")

간단한 예제를 한번 작성해봤다.

class Person {
    // 값을 저장하기 위한 프로퍼티 정의
    var name: String = "jaynam"
    var height:Float = 0.0
    var weight:Float = 0.0
    
    // 기능성 제공을 위한 메서드 정의
    func getPersonInfo() {
        print("Name : \(name) , Height : \(height) , Weight : \(weight)")
    }
}

var jay: Person = Person()
jay.height = 174.4
jay.weight = 65.0

let su: Person = Person()
su.height = 164.3
su.weight = 49.8

프로퍼티의 값을 온점(.) 을 통해서 프로퍼티의 값을 변경할 수 있고
상수 let 으로 인스턴스를 생성해도 내부 프로퍼티의 값을 변경할 수 있었다.
구조체는 상수로 선언할 경우 변경할 수 없다.

클래스는 참조 타입이므로 참조할 필요가 없을 때 메모리에서 해제된다.
이 과정으로 소멸이라고 칭하고 소멸되지 직전 deinit 이라는 메서드가 호출된다.
클래스 내부에서 deinit 메서드를 구현해주면 소멸되기 직전에 deinit 메서드가 호출된다.
deinit 메서드를 소멸자(deinitializer) 라고 부른다.
deinit 메서드는 클래스당 하나만 구현할 수 있다. 매개변수와 반환 값을 가질 수 없고 매개변수를 위한 소괄호도 적지 않는다.
프로그래머가 직접 deinit 을 호출할 수도 없다.

class Person {
    // 값을 저장하기 위한 프로퍼티 정의
    var name: String = "jaynam"
    var height:Float = 0.0
    var weight:Float = 0.0
    
    // 기능성 제공을 위한 메서드 정의
    func getPersonInfo() {
        print("Name : \(name) , Height : \(height) , Weight : \(weight)")
    }
    
    deinit {
        print("소멸자 확인~~~")
    }
}

var jaynam: Person? = Person()

jaynam = nil

========== 출력 결과 ==========
소멸자 확인~~~

옵셔널 타입으로 정해주고 nil 로 값을 바꿔주었을 때 deinit 메서드가 호출된 것을 확인할 수 있었다.

추가로 구조체와 다르게 클래스에서만 사용 가능한 추가적인 기능을 확인할 수 있다.

- 상속(inheritance) : 한 클래스가 다른 클래스를 상속할 수 있다.
- 타입 캐스팅(type casting) : 런타임 시에 클래스 인스턴스의 타입을 확인하고 이해하기 위한 타입 캐스팅이 가능하다.
타입 캐스팅이란 인스턴스의 타입을 확인하는 용도나 클래스의 타입으로 사용할 수 있는지 확인하는 용도로 사용한다.
is 를 통해 타입을 확인할 수 있다. 자세한 내용은 야곰님의 블로그를 통해 자세하게 공부할 수 있었다.

var jay: Person = Person()

var typeCheck: Bool

typeCheck = jay is Person // true
typeCheck = jay is People // false

- 소멸자(deinitializer) : 할당된 자원을 해제시킬 수 있다. deinit 메서드 호출
- 참조 카운팅(reference counting) : 클래스 인스턴스에 하나 이상의 참조를 가능케 한다.

아무래도 가장 큰 차이점은 타입이 다르다는 점 같다.

구조체는 값(value) 타입 , 클래스는 참조(reference) 타입


클래스와 구조체 중에 어떤 것을 선택해야할까?

구조체와 클래스는 서로 타입이 다르기 때문에 용도 또한 다르다고 할 수 있다.

애플의 가이드 라인에서 나와있듯이,
다음과 같은 경우에는 구조체를 사용하기를 권하고 있다고 한다.

- 연관된 간단한 값의 집합을 캡슐화 하는 것만이 목적일 때
- 캡슐화한 값이 참조되는 것보다 복사되는 것이 합당할 때
- 구조체에 저장된 프로퍼티가 값 타입이면 참조되는 것보다 복사되는 것이 합당할 때
- 다른 타입으로부터 상속받거나 자신이 상속될 필요가 없을 때

솔직히 이렇게 글만 봐서는 어떤 때에 효율적으로 사용할 수 있는지 알 수 없다.
직접 사용해보고 겪어봐야 더 와닿을 것 같다고 생각한다.

마지막으로,
스위프트에서의 사용

- 스위프트의 기본 데이터 타입은 모두 구조체로 되어있다.
- 스위프트는 구조체와 열거형 사용을 선호한다
- Apple 프레임워크는 대부분 클래스를 사용한다.
- 구조체/클래스 선택과 사용은 개발자의 몫이다.

정리하기

구조체와 클래스에 대해서 비교해가면 공부했다.
솔직하게 참고한 사이트들에 적혀 있는 것들을 그대로 따라 해본 것들을 정리해서 적은 것이라고 해도 무방하다.
아래에 참고해놓은 사이트에서 더 자세하게 설명되어 있고 따라 했기 때문에 정확히 이해하고 정리했다고 보기는 어렵지만
더 공부한 후 나중에 다시 봤을 때 더 자세하고 쉽게 이해할 수 있게 수정해야겠다.

 

- 참고 사이트 -

velog.io/@co-in/공식-문서로-공부하는-Swift-8-구조체와-클래스

 

공식 문서로 공부하는 Swift (8) - 구조체와 클래스

Structures and Classes 구조체(Structure)와 클래스(Class)는 보통 프로그램 코드 블록을 유연성 있게 구축하기 위해 사용합니다. 상수, 변수, 함수를 정의하는 것과 같은 문법을 사용해 구조체와 클래스에

velog.io

medium.com/@jgj455/오늘의-swift-상식-subscript-2288551588f9

 

오늘의 Swift 상식 (Subscript)

서브스크립트란?

medium.com

beankhan.tistory.com/165

 

[Swift 3] 초기화 (Initialzer)

출처 http://kka7.tistory.com/19 초기화 클래스, 구조체, 열거형의 인스턴스를 사용하기 전에 준비하는 단계이다. Swift 초기화는 Objective-C 와 다르게 값을 반환하지 않는다. 이 규칙은 타입의 새로운 인�

beankhan.tistory.com

blog.yagom.net/530/

 

Swift - 구조체 클래스 - yagom's blog

yagom's blog Swift - 구조체 클래스

blog.yagom.net

edu.goorm.io/learn/lecture/1141/야곰의-스위프트-프로그래밍/lesson/43403/타입캐스팅

 

구름EDU - 모두를 위한 맞춤형 IT교육

구름EDU는 모두를 위한 맞춤형 IT교육 플랫폼입니다. 개인/학교/기업 및 기관 별 최적화된 IT교육 솔루션을 경험해보세요. 기초부터 실무 프로그래밍 교육, 전국 초중고/대학교 온라인 강의, 기업/

edu.goorm.io

 

728x90
반응형
복사했습니다!