클래스와 구조체

Written by Tejay
on 

Class VS Struct

1. Class(클래스)와 Struct(구조체)란

  • 클래스와 구조체는 일반적으로 프로그램 코드의 블럭 구조이다.

  • 프로퍼티(상수, 변수), 메소드(함수)를 추가할 수 있다.

  • 다일 파일에 적용되며 다른 코드에서 사용할 수 있다. (단, 접근 제한자로 인해 사용을 하지 못할 수도 있다.)

  • 초기 상태를 설정하기 위해 Initializer가 만들어 지고 사용자가 따로 설정할 수 도 있다.

  • 사용시에는 인스턴스로서 사용됨

  • 기본 구현된 내용에 Extension을 사용하여 확장시킬 수 있다.

  • 프로토콜을 상속받아 사용할 수 있다.

2. 기본 구조

class SpecificClass {
    var name: String = ""
    var phone: String = ""

    func addName() {
        //content
    }
}

struct SpecificStruct {
    var address: String = ""
    var counter: Int = 0

    func addCounter() {
        //content
    }
}
  • 기본 구조는 클래스와 구조체 둘다 같다.

  • 클래스와 구조체 둘다 프로퍼티와 메소드로 구성되어 있다.

let someClass = SpecificClass()
let someStruct = SpecificStruct()

someClass.name = "태준"

someStruct.addCounter()
  • 클래스와 구조체 둘다 사용시에는 인스턴스로 사용이 된다.
  • 클래스와 구조체 내부의 프로퍼티나 메소드에 접근하기 위해선 (.)을 사용하여 접근한다.

3. 초기화

  • 인스턴스에 설정된 속성의 초기값 설정과 초기화하는데 목적이 있다.

  • 클래스 및 구조체는 인스턴스로 만들어 질 때 프로퍼티는 적절한 초기값으로 설정이 되어 있어야 한다.

  • 구조체는 자동으로 Memberwise Initializers가 만들어진다.

    • Memberwise Initializers란

      struct Subject {
          var name: String
      }
      
      class Student {
          var subject: [Subject] = []
      
          func addSubject(name: String){
              let subject = Subject(name: String)
              subject.append(subject)
          }
      }
      
      • 위에 코드를 보면 구조체의 초기화를 쓰진 않았지만 밑에 Subject를 초기화할 때 Subject(name: String)란 함수를 쓸 수 있다. 이것은 구조체의 특징으로 프로퍼티의 초기값을 가지게 하는 초기화 메소드가 자동으로 만들어진다. (클래스는 불가능) 물론 커스텀하게 만들 수도 있다.
    • Custom Initializers란

      struct Subject {
          var name: String?
          var score: Int
      
          init(score: Int) {
              self.score = score
          }
      }
      
      class Student {
          var subject: [Subject] = []
          var score: Int = 0
      
          func addScore(score: Int){
              let score = Subject(score: Int)
          }
      }
      
      • 위에 코드를 보면 구조체에 초기화 함수를 사용자가 직접 지정을 할 수가 있다. 이런 경우 Custom Initializers라고 한다.
  • 상속과 Initializers

    • 부모의 클래스로부터 상속받은 모든 저장 프로퍼티는 초기화할 때 초기 값을 할당받아야 한다.

    • 스위프트는 클래스 타입에 모든 저장 프로퍼티에 초기값을 받도록 도와주는 방법이 두가지가 있는데, 하나는 Designated Initializers와 Convenience Initializers이다.

      • Designated Initializers
        • 모든 프로퍼티는 초기화되어야 한다.
        • 상속을 받았다면 부모클래스의 Designated Initializers를 호출해야 한다.
      • Convenience Initializers
        • 다른 Convenience Initializers를 호출할 수 있다.
        • 하지만 궁극적으로는 Designated Initializers를 호출해야만 한다.

  • Required Initializers

    class SomeClass {
        required init() {
        // initializer implementation goes here
        }
    }
    
    • 해당 초기화는 필수적으로 구현해야만 한다.
    • 상속받은 모든 클래스와 구조체는 필수로 구현해야 한다.
    • Required Initializers를 구현할 때에는 override 수식어를 사용할 필요 없다.
  • Setting a Default Property Value with a Closure or Function

    class SomeClass {
        let someProperty: SomeType = {
        // 해당 클로져 안에 프로퍼티의 기본값을 지정한다.
        // someValue는 반드시 SomeType과 타입이 같아야 한다.
        return someValue
        }()
    }
    
    • 클래스의 init시 해당 프로퍼티의 값이 할당되며, 값 대신 클로저나 전역 함수를 사용할 수 있다.
    • 클로저 사용시 마지막에 ()를 붙여 클로저를 바로 실행시킨다.

4. Class vs Structures

  • Class는 참조 타입이며 Structure는 값 타입이다.

    • 값타입 vs 참조타입

      • Memory구조

        • 값타입은 복사의 개념으로 복사된 객체가 변경이 되면 복사된 객체에는 영향을 끼치지 않지만 참조타입은 참조의 개념으로 하나가 변경이 되면 그것을 참조하는 모든 객체에 변화가 생기게 된다.
  • Class는 상속을 통해 부모 클래스의 특성을 상속받을 수 있다.

  • Class 는 Type Casting을 사용할 수 있다. 하지만 Structure는 불가능 하다.

  • Structure의 프로퍼티는 instance가 var를 통해서 만들어야 수정 가능하다.

  • Class는 Reference Counting을 통해 instance의 해제를 계산한다.

  • Class는 Deinitializer를 사용할 수 있다.

5. Value Type 프로퍼티 수정

  • 기본적으로 구조체와 열거형의 값타입 프로퍼티는 인스터스 메소드 내에서 수정이 불가능하다.

  • 그러나 특정 메소드에서 수정을 해야하는 경우에는 mutating 키워드를 사용하여 변경이 가능하다.

    struct Point {
        var x = 0.0, y = 0.0
        mutating func moveBy(x deltaX: Double, y deltaY: Double) {
            x += deltaX
            y += deltaY
        }
    }
    

6. Deinit

class Student {
    init() {
        //인스턴스 생성시 필요한 내용 구현
    }
    deinit {
        //종료직전 필요한 내용 구현
    }
}