class
키워드 뒤에 클래스 이름을 붙여 새로운 클래스를 생성할 수 있다. 클래스에 속성을 정의하는 방법은 상수, 변수 정의에 사용된 방법과 동일하나, 클래스 컨텍스트 안에 존재한다는 점만 다르다. 마찬가지로, 메소드와 함수 정의도 같은 방법을 따른다.
class Shape {
var numberOfSides = 0
func simpleDescription() -> String {
return "A shape with \(numberOfSides) sides."
}
}
클래스 이름 뒤에 괄호를 붙여 클래스 인스턴스를 만들 수 있다. .
점을 통해 클래스 인스턴스의 변수, 메소드에 접근할 수 있다.
var shape = Shape()
shape.numberOfSides = 7
var shapeDescription = shape.simpleDescription()
위 Shape
클래스는 클래스의 중요한 부분인 initializer, 생성자가 없다. 생성자는 클래스 인스턴스가 생성될 때 변수를 설정한다. 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."
}
}
name
속성과 name
인자를 구분하는 데 self
가 어떻게 쓰였는지 주목하자. 클래스 인스턴스를 생성할 때, 인자는 함수 호출과 같이 넘어온다. 모든 속성은 값이 할당되어야 한다. 선언과 동시에 (numberOfSides
의 경우) 혹은 생성자에서 (name
과 같은 경우)
deinit
을 사용하여 오브젝트가 할당 해제되기 전에 메모리 정리를 수행하는 소멸자를 생성한다.
subclass는 superclass 이름을 자신의 클래스 이름: 뒤에 포함한다. 서브클래스가 어떠한 표준 root class도 반드시 상속할 필요는 없다.
수퍼 클래스의 구현 사항을 override한 서브 클래스의 메소드는 메소드 이름 앞에 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()
저장되는 속성을 단순하게 만들기 위해 속성은 getter와 setter를 가질 수 있다.
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)
// Prints "9.3"
triangle.perimeter = 9.9
print(triangle.sideLength)
// Prints "3.3000000000003"
perimeter
setter에서 새로운 값은 암시적으로 newValue
라는 이름의 변수가 된다. set
뒤에 괄호로 명시적인 이름을 표기할 수도 있다.
EquilateralTriangle
클래스가 생성자가 세 가지 다른 단계를 가지는 것에 주목하자:
- 서브 클래스가 정의한 속성의 값을 설정
- 수퍼 클래스의 생성자를 호출
- 수퍼 클래스에서 설정된 속성값을 변경. 메소드, getter, setter를 사용하는 추가 작업도 수행될 수 있다
속성을 계산할 필요가 없지만 새로운 값을 설정하기 전과 후에도 코드를 제공해야 한다면, willSet
과 didSet
을 사용하라. 제공된 코드는 생성자 밖에서도, 값이 변하는 어느 시점에서든 실행된다. 예를 들어, 아래 클래스는 삼각형의 side length가 항상 사각형의 side length와 같다.
class TriangleAndSquare {
var triangle: EquilateralTriangle {
willSet {
square.sideLength = newValue.sideLength
}
}
var square: Square {
willSet {
triangle.sideLength = newValue.sideLength
}
}
init(size: 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
이 된다. 다시 말해, 옵셔널 을 unwrap 되면 ?
이후 값은 모두 옵셔널 자료형이 된다. 두 경우 모두, 전체 표현식의 값은 옵셔널 값이다.
let optionalSquare: Square? = Square(sideLength: 2.5, name: "optional square")
let sideLength = optionalSquare?.sideLength // optionalSquare가 nil이면 nil, 아니면 sideLength 값을 반환. 두 경우 모두를 포함하는 자료형은 Int?
'Swift' 카테고리의 다른 글
mac OS #Framework 생성, Cannot find #FUNCTION in scope error, Swift #접근제어자 와 @testable (0) | 2021.01.21 |
---|---|
#Postman 이용하여 #대부분의 데이터를 받아오는 방법! (0) | 2021.01.20 |
Functions and Closures - A Swift Tour 2일차 (0) | 2020.12.19 |
Control Flow - A Swift Tour 1일차 (0) | 2020.12.19 |
Simple Values - A Swift Tour 1일차 (0) | 2020.12.19 |