大器晩成

클래스와 구조체의 차이 본문

iOS/Swift 문법

클래스와 구조체의 차이

zerobugpark 2024. 11. 21. 18:03

 

*구조체와 클래스의 가장 큰 차이는 메모리 저장 방식의 차이입니다.*

 

구조체 클래스
  • 값형식(Value Type)
  • 인스턴스 데이터를 모두 스택(Stack)에 저장
  • (복사 시) 값을 전달할 때마다 복사본을 생성 (다른 메모리 공간 생성)
  •  스택(Stack)의 공간에 저장, 스택 프레임 종료 시, 메모리에서 자동 제거
  • 스위프트에서 제공하는 정수, 문자열, 배열, 또는 딕셔너리 등 기본 자료형들은 모두 복사를 통해 값이 전달되는데, 이는 이들 자료형이 모두 구조체로 구현되었기 때문이다.
  • 참조형식(Reference Type)
  • 인스턴스 데이터는 힙(Heap)에 저장되고, 변수 자체는 스택에 저장
  •  (스택에 저장된) 변수 안에 메모리 주소값이 힙(Heap)의 인스턴스를 가리킴
  •  (복사시) 값을 전달하는 것이 아니고, 저장된 주소를 전달
  •  힙(Heap)의 공간에 저장, ARC시스템을 통해 메모리 관리(메모리 관리 주의 필요)

 

 

클래스의 메모리 

class Person {
    var name = "태연"
}

var p = Person()    // 가상의주소: 0x9001
p.name  // "태연"

var p2 = p       // (클래스)     // 가상의주소: 0x9001
p.name = "카리나"

print(p2.name) //"카리나"

p2.name = "윈터"

print(p.name) //"윈터"
  • 클래스는 참조타입으로 복사 시 저장된 주소를 전달합니다.
  • 즉, "var p2 = p" 코드는 p가 가리키는 주소값을 복사해서 p2에 전달하는 것입니다.
  • 참조란 객체가 저장된 메모리 주소 정보가 전달된다는 뜻입니다.
  • p에서 값이 변경되면, 주소값을 동일한 주소값을 가리키는 p2도 값이 변경됩니다.
    - 실제로는 힙에 있는 값이 변경되는 것입니다. (스택에서는 힙의 인스턴스를 가리키고 있습니다.)
  • 즉, p와 p2는 같은 객체입니다.

구조체의 메모리

struct Person {
    var name = "태연"
}

var p = Person()
p.name  // "태연"

var p2 = p       // (구조체)
p.name = "카리나"

print(p2.name) //"태연"

p2.name = "윈터"

print(p.name) //"카리나"
  • 구조체는 값 타입으로 현재의 데이터를 복사합니다.. 만약 p.name의 이름을 변경하고 복사를 하면 변경된 값이 복사됩니다.
  • 변수에 대입된 인스턴스와 기존의 인스턴스는 서로 독립적입니다. (즉, a와 a2는 서로 다른 인스턴스이다.

 

클래스의 let과 var 키워드

   - var와 let을 사용하여 객체를 생성할 때의 차이는 객체 자체를 수정할 수 있는지 여부에 달려 있습니다.

[let]

class Person {
    var name: String
    init(name: String) {
        self.name = name
    }
}

let person = Person(name: "John")

// Error: Cannot assign to value: 'person' is a 'let' constant
// person = Person(name: "Alice")  // 다른 객체로 변경할 수 없다.

person.name = "Alice"  // 객체 내부의 속성은 변경 가능
print(person.name) // Alice


--------------------------------------------------------
[var]

var person2 = Person(name: "John")
person2.name  // "John"
person2 = Person(name: "Alice")  // 객체 자체를 변경할 수 있음
person2.name  // "Alice"
person2.name = "Bob"  // 객체의 속성도 변경 가능
person2.name "Bob" // Bob


--------------------------------------------------------

class PersonClass {
  var name = "사람"
  var age = 0
}

let pclass = PersonClass()
pclass.name = "사람1"
pclass.name

PersonClass().name     // 왜 "사람1"이 나오지 않을까요?
//pclass와 PersonClass().name는 완전히 다른 인스턴스이다.
* 클래스는 객체의 틀이며, 같은 클래스 타입으로 생성된 인스턴스여도 서로 독립적인 관계이다.

 

let을 사용할 때:

  • 불변 객체: let으로 선언한 객체는 변수 자체는 변경할 수 없지만, 객체 내부의 속성이나 메서드는 수정이 가능할 수 있습니다.
  • 중요한 점은, 객체 자체를 다른 객체로 변경할 수 없다는 것입니다. 즉, let을 사용하여 객체를 생성한 후, 해당 객체를 다른 객체로 대체할 수 없다.

var를 사용할 때:

  • 가변 객체: var로 선언한 객체는 객체 자체와 객체의 속성을 모두 변경할 수 있습니다.
  • 객체를 새로운 객체로 바꾸거나, 객체의 속성을 수정하는 것이 가능합니다.
let var
  • let을 사용하면 객체를 재할당(객체 자체를 변경)할 수 없지만, 객체의 속성은 변경할 수 있습니다.
  • var는 객체 자체와 객체의 속성 모두 자유롭게 수정할 수 있다.

 

구조체의 let과 var 키워드

- 스위프트에서 구조체를 사용할 때 let과 var의 차이는 클래스와 비슷하지만, 값 타입인 구조체는 참조타입인 클래스와 다르게 동작합니다. 구조체는 값을 복사하는 특성이 있기 때문입니다.

#1. 예시1
struct AnimalStruct {
    var name = "동물"
    var age = 0
}

let astruct = AnimalStruct()

//astruct.name = "동물1" // let으로 선언해서 수정 불가능
astruct.name // "동물"

#2. 예시2
struct Person {
    var name: String
    let age: Int
}

let person = Person(name: "John", age: 30)
// person = Person(name: "Alice", age: 25)  // Error: Cannot assign to value: 'person' is a 'let' constant
//person.name = "Alice"  // Error: Cannot assign to property: 'person' is a 'let' constant
// person.age = 31  // Error: Cannot assign to property: 'age' is a 'let' constant

var person = Person(name: "John", age: 30)
person = Person(name: "Alice", age: 25)  // 구조체 자체를 다른 값으로 변경 가능
person.name = "Bob"  //  name 속성 변경 가능
// person.age = 31  // age는 구조체에서 let으로 선언되었기 때문에 변경 불가

 

 let으로 선언한 구조체 인스턴스

  • let으로 선언된 구조체 인스턴스는 구조체 자체속성 모두 수정할 수 없습니다.
  • 구조체 내부에 var로 선언된 속성이라도, 구조체 자체가 불변이기 때문에 해당 속성을 변경하려고 하면 에러가 발생합니다.

var로 선언한 구조체 인스턴스

  • var로 선언된 구조체 인스턴스는 구조체 자체와 속성 모두 수정할 수 있습니다.
  • 구조체 내의 var로 선언된 속성도 변경할 수 있습니다.
let var
  • let으로 선언한 구조체 인스턴스는 구조체 자체와 속성 모두 수정할 수 없다. 
  • 구조체는 값 타입이기 때문에, let으로 선언된 구조체 인스턴스는 값 자체를 수정할 수 없는 불변 객체가 된다.
  • let으로 선언한 구조체 인스턴스는 구조체 자체와 속성 모두 수정할 수 없다
  • var로 선언한 구조체 인스턴스는 구조체 자체와 속성 모두 수정할 수 있다. 
  • 구조체는 값 타입이기 때문에, let으로 선언된 구조체 인스턴스는 값 자체를 수정할 수 없는 불변 객체가 된다.

 

접문법/ 명시적 멤버 표현식(Explicit Member Expression)의 정확한 의미

// 내부의 요소. 즉, 클래스, 구조체의 인스턴스의 멤버에 접근한다.
// 멤버는 속성, 메서드를 포함

struct Bird {
    var name = "새"
    var weight = 0.0
    
    func fly() {
        print("날아갑니다.")
    }
}

var bBird = Bird()
bBird.fly()


Int.random(in: 1...10)
  • 점문법은 하위의 프로퍼티(속성) 또는 메서드(함수)를 가리킵니다.
  • 프로퍼티의 하위 프로퍼티에 값을 할당 또는 접근할 때도 점문법을 연속으로 연결하여 값을 할당 또는 접근할 수 있다.

관습적인 부분들에 대한 이해 

 - 일반적으로 클래스, 구조체 선언할때 모두
 - 1) 속성 2) 메서드 순서대로 작성
 - 클래스 내부에는 직접 메서드(함수) 실행문이 올 수 없다.
 - 메서드 실행문은 메서드 정의문 내에 존재해야 함.
 
 
 // 속성, 메서드 순서대로 작성
struct Bird {
    var name = "새"
    var weight = 0.0
    
    func fly() {
        run() // 메서드 실행문은 메서드 정의문 내에 존재
        print("날아갑니다.")
    }
    func run() {
        print("달려갑니다.")
    }
    
    //run() // 에러 발생
}

var bBird = Bird()
bBird.fly() // 출력: 달려갑니다. 날아갑니다.

 

식별연산자(Identity Operators)

// 식별연산자 - 두개의 참조가 같은 인스턴스를 가리키고 있는지를 비교하는 방법
// 동일 인스턴스인지 비교할 때: ===
// 동일 인스턴스가 아닌지 비교할 때 : !==

class Person {
    var name = "카리나"
    let age = 25
}

var person = Person()
var person2 = Person()


if (person === person2) {
    print("동일한 인스턴스를 참조하고 있다.")
} else {
    print("서로 다른 인스턴스를 참조하고 있다..")
}
// 출력: 서로 다른 인스턴스를 참조하고 있다..

var person3 = person

if (person === person3) {
    print("동일한 인스턴스를 참조하고 있다.")
} else {
    print("서로 다른 인스턴스를 참조하고 있다..")
}
// 출력: 동일한 인스턴스를 참조하고 있다.

 

  • **식별 연산자 (===, !==)**는 클래스 타입의 객체에만 사용 가능합니다.
  • 구조체열거형값 타입이므로, 식별 연산자를 사용할 수 없습니다.
  • 값 타입에서는 == 연산자를 사용하여 값이 같은지 비교할 수 있습니다.

 

 

728x90

'iOS > Swift 문법' 카테고리의 다른 글

저장속성(Stored Properties)  (0) 2024.11.21
초기화(initializer)  (0) 2024.11.21
구조체(Struct)와 클래스(Class)  (1) 2024.11.21
옵셔널 체이닝  (4) 2024.11.12
inout 파라미터  (0) 2024.11.08