공부/SWIFT

[SWIFT] 구조체와 클래스 기본개념정리

알로하리미 2021. 3. 11. 11:42
728x90

1. 개요

클래스와 구조체 공통점

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

- 기능을 제공하기 위한 메소드 정의

- subscript 문법을 이용해 특정 값을 접근할 수 있는 subscript 정의

- 초기 상태를 설정할 수 있는 initializer 정의

- 기본 구현에서 기능 확장

- 특정한 종류의 표준 기능을 제공하기 위한 프로토콜 순응(conform)

- 둘 모두 중첩 구조가 가능하다.

- 소스파일에 여러개의 구조체와 클래스를 정의하고 구현해도 문제 없다.

 

 

 

클래스와 구조체 차이점

구조체
인스턴스는 값타입


클래스
인스턴스는 참조타입

  • 상속 (Inheritance) : 클래스의 여러 속성을 다른 클래스에 물려 줌

  • 타입 캐스팅 (Type casting) : 런타임에 클래스 인스턴스의 타입을 확인

  • 소멸자 (Deinitializers) : 할당된 자원을 해제(free up) 시킴

  • 참조 카운트 (Reference counting) : 클래스 인스턴스에 하나 이상의 참조가 가능

 

 

 

 

클래스와 구조체중 뭘 쓸까?

음의 조건 중 1개 이상을 만족하면 구조체를 사용하는 것을 고려

  • 구조체의 주 목적이 관계된 간단한 값을 캡슐화(encapsulate) 하기 위한 것인 경우

  • 구조체의 인스턴스가 참조되기 보다 복사되기를 기대하는 경우

  • 구조체에 의해 저장된 어떠한 프로퍼티가 참조되기 보다 복사되기를 기대하는 경우

  • 구조체가 프로퍼티나 메소드 등을 상속할 필요가 없는 경우

 

 

1. 선언

구조체 선언 키워드 struct

클래스 선언 키워드 class

클래스를 정의한다는 것또한 타입을 정의함과 같다. 대문자 카멜케이스를 사용한다.

구조체를 정의한다는 것은 타입을 정의함과 같다. 대문자 카멜케이스를 사용한다.

struct SomeStructure {
    // 구조체 내용은 여기에
}

class SomeClass {
    // 클래스 내용은 여기에
}



struct Resolution {   
    var width = 0
    var height = 0
}

// 구조체
// 상수(let)으로 선언된 구조체인스턴스의 내부는 변경 불가 
// 내부 프로퍼티가 var여도 변경 불가
// 왜냐면 구조체는 값 타입 이기 때문이다.
// 내부 프로퍼티 이름으로 생성자가 자동 생성된다.
let letResolution: Resolution(widht:100, height:100) 
letResolution.width = 200 //오류


// 클래스
// 구조체와는 다르게 클래스의 인스턴스는 참조타입이므로
// 클래스의 인스턴스를 상수 let으로 선언해도 
// 내부 프로퍼티가 let, var 선언에 따라 값을 변경 할 수 있다.
// 기본 생성자 외의 사용자 정의 이니셜라이저를 만들 수 있다.
class VideoMode {
    let code: String?  //let 으로 선언시 변경 불가
    var resolution = Resolution()  // 위 Resolution 구조체를 값으로 사용
    var interlaced = false
    var frameRate = 0.0
    var name: String?
    
    deinit {
       // 클래스 인스턴스가 소멸되기 직전에 호출 되는 deinit
       // 인스턴스 소멸전에 데이터를 저장하거나 , 
       // 다른 객체에 소멸을 알려야할때 사용
    }
}








 

 

클래스와 구조체 이름 뒤에 빈 괄호를 적으면 각각의 인스턴스를 생성

let someResolution = Resolution()    // 구조체 인스턴스 생성
let someVideoMode = VideoMode()    // 클래스 인스턴스 생성


 

 

프로퍼티 접근

//점문법으로 프로퍼티 접근 가능
print("The width of someResolution is \(someResolution.width)")
print("The width of someVideoMode is \(someVideoMode.resolution.width)")

//점문법으로 값 할당 가능
someVideoMode.resolution.width = 1280

 

 

구조체형의 맴버 초기화

모든 구조체는 초기화시 프로퍼티를 선언할 수 있는 초기자를 자동으로 생성해 제공

let vga = Resolution(width: 640, height: 480)

 

 

구조체는 값 타입

let hd = Resolution(width: 1920, height: 1080) //구조체의 인스턴스를 생성하여 hd 할당
var cinema = hd // 새로운 변수 cinema에 할당

// 구조체는 값타입이므로 
// cinema라는 새로운 위치에 값만 들어간것이라고 볼수있다.
// 그러므로 hd의 프로퍼티를 변경해도
// cinema의 프로퍼티는 변경 되지 않는다.
// 반대도 마찬가지이다.

cinema.width = 2048
print("cinema is now \(cinema.width) pixels wide")
// "cinema is now 2048 pixels wide" 출력

print("hd is still \(hd.width) pixels wide")
// "hd is still 1920 pixels wide" 출력 변하지 않았다.

 

 

클래스는 참조 타입

참조타입이란 것은 메모리의 주소 라고 보면된다.

// 참조 타입이라는것은 메모리의 주소를 바라 보고 있다 보면된다.

// 클래스 인스턴스 생성
let tenEighty = VideoMode()

// 인스턴스의 각 프로퍼티에 값 할당
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0

// 새로운 변수에 tenEighty가 바라보는 메모리 주소를 할당
// alsoTenEighty와 tenEighty는 같은 집을 보고 있는 것과 같다.
// 그러므로 둘중의 하나라도 프로퍼티를 변경시에
// 둘 모두 변경된 값을 보게 된다.
let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0



print("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
// "The frameRate property of tenEighty is now 30.0" 출력


// 참조타입 식별 연산자
// === : 두 상수나 변수가 같은 인스턴스를 참조하고 있는 경우 참
// !== : 두 상수나 변수가 다른 인스턴스를 참조하고 있는 경우 참
if tenEighty === alsoTenEighty {
    print("tenEighty and alsoTenEighty refer to the same VideoMode instance.")
}
// "tenEighty and alsoTenEighty refer to the same VideoMode instance." 출력

 

 

* 참고

스위프트의 기본 데이터 타입은 모두 구조체이다.

String, Array, Dictionary 같은 기본 데이터 타입이 구조체로 구현 돼 있습니다. 그렇다는 의미는 이 값을 다른 상수나 변수에 할당하거나 함수나 메소드에 인자로 넘길 때 이 값이 복사 된다는 것입니다. 반면 FoundationNSString, NSArray, NSDictionary는 클래스로 구현 돼 있습니다. 그래서 이 데이터들은 항상 할당 되거나 전달될 때 복사 되지 않고 참조가 사용 ( String, Array, Dictionary 는 할당되거나 전달될 때 복사된다고 설명했습니다. 하지만 실제로 Swift에서는 최적의 성능을 위해 실제 필요할 때만 데이터가 복사됩니다 )