스위프트 투어 - 객체와 클래스 Swift


객체와 클래스

속성 정의는 상수나 변수 생성과 같은 방식으로 지정하는데 클래스 컨텍스트 내에 있다는 것만 다르다. 이런식으로, 메소드와 함수가 같은 방식으로 쓰여진다.

class Shape {
  var numberOfSides = 0
  func simpleDescription() ->String {
    return "A shape with \(numberOfSides) sides."
  }
}

클래스 이름뒤에 괄호를 붙임으로서 인스턴스를 생성한다. .을 사용해 속성과 메서드에 접근한다.

var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()

쉐이프 클래스의 이 버전은 중요한 부분이 빠져 잇다. 인스턴스가 생성될 때의 생성자이다. init 를 사용해 하나를 생성한다.

class NamedShape {
  var numberOfSides: Int = 0
  var name: String

  init(name: String) {
    self.name = name
  }

  func simpleDescription() -> String {
    return "A shape with \(numberOfSides) sides."
  }
}

어떻게 self가 사용되어 name 속성과 name 매개변수를 구별하는지 확인한다. 생성자로의 매개변수는 클래스의 인스턴스를 생성할 때 함수처럼 전달된다. 모든 속성은 값을 할당받아야 한다. 이 정의 (nameOfSides) 나 생성자 (name) 에서

deinit 는 객체 소멸자를 정의하는데 쓰인다

이들 클래스 이름 뒤의 슈퍼클래스 이름을 포함하는 서브클래스는 콜론으로 구별된다. 서브클래스할 표준 루트 클래스 요구사항은없으므로 필요하다면 포함하고 아니면 생략할 수 있다.

서브클래스 상의 메소드는 슈퍼클래스의 구현을 오버라이드하는 것은 override 로 마킹한다. override 가 없는 실수에 의한 오버라이딩은 컴파일러에의해 에러로 다뤄진다. 또한 컴파일러는 실제로 오버라이드 하지 않는 메소드를 감지한다.

class Square : NamedShape {
  var sideLength: Double
  
  init(sideLength: Double, name: String) {
    self.sideLength = sideLength
    super.init(name: name)
    numberOfSides = 4
  }

  func area() -> Double {
    return sideLength * sideLength
  }

  override func simpleDescription() -> String {
    return "A square with sides of length \(sideLength)."
  }
}

let test = Square(sideLength: 5.2, name: "my test square")
test.area()
test.simpleDescription()

저장되는 단순 프로퍼티에 추가적으로 게터와 세터를 가질 수 있다.

class EquilateralTriangle: NamedShape {
  var sideLength: Double = 0.0

  init(sideLength: Double, name: String) {
    self.sideLength = sideLength
    super.init(name: name)
    numberOfSides = 3
  }

  var perimeter: Double {
    get {
      return 3.0 * sideLength
    }
    set {
      sideLength = newValue / 3.0
    }
  }

  override func simpleDescription() -> String {
    return "An equilateral triangle with sides of length \(sideLength)."
  }
}

var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
print(triangle.perimeter)
// 9.3
triangle.perimeter = 9.9
print(triangle.perimeter)
// 3.3

perimeter 를 위한 세터에서 새로운 값은 newValue 이다. set뒤의 괄호 내에 명시적이름을 지정할 수 있다.

EquilateralTriangle 클래스를 위한 생성자는 3가지의 다른 단계를 갖는다.

1. 서브클래스가 정의하는 속성의 값에 할당
2. 슈퍼클래스의 생성자 호출
3. 슈퍼클래스에 의해 정의된 속성 값 변경. 메소드, 게터, 세터를 사용하는 작업이 이 단계에서 수행된다.

새로운 값에대한 설정 직전과 설정 후에 실행하고 싶은 코드가 있다면 willSet, didSet 를 사용한다. 코드는 생성자 바깥의 값 변화에 대해 실행된다. 예를 들어, 아래 클래스에서 삼각형의 사이드 길이는 사각형의 사이드길이와 항상 같다.

class TriangleAndSquare {
  var triangle: EquilateralTriangle {
    willSet {
      square.sideLength = newValue.sideLength
    }
  }

  var square: Square {
    willSet {
      triangle.sideLength = newValue.sideLength
    }
  }

  init(side: Double, name: String) {
    square = Square(sideLength: size, name: name)
    triangle = EquilateralTriangle(sideLength: size, name: name)
  }
}
var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
print(triangleAndSquare.square.sideLength)
// 10.0
print(triangleAndSquare.triangle.sideLength)
// 10.0
triangleAndSquare.square = Square(sideLength: 50, name: "larger square")
print(triangleAndSquare.triangle.sideLength)
// 50.0

옵셔널 값과 작업할 때는 ?를 메소드, 속성 그리고 서브스크립팅과 같은 연산 앞에 쓸 수 있다. 만약 ? 앞의 값이 nil이면 ?뒤의 모든 것은 무시되고 전체 표현의 값은 nil이다. 그렇지 않으면 옵셔널 값이 언랩되며 언랩값으로 처리된다. 양상황에서 전체 표현의 값은 옵셔널 값이다.

let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength


덧글

댓글 입력 영역