스위프트 기초 시리즈

클래스

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

 

인스턴스 생성

new 키워드를 입력하지 않습니다.

var shape = Shape() // new 키워드가 필요없음
shape.numberOfSides = 7 // 클래스 변수에 직접 접근 가능
var shapeDesc = shape.simpleDescription()
print(shapeDesc)

A shape with 7 sides.

 

초기화자 (Initializer)

초기화자는 다른 객체지향 언어의 생성자(Constructor)와 비슷한 개념입니다.

class NamedShape {
    var numberOfSides: Int = 0
    var name: String
    
    init(name:String) {
        self.name = name
    }
    func simpleDescription() -> String {
        return "A shape with \(numberOfSides) sides."
    }
}
ar namedShape = NamedShape(name: "11각형")
namedShape.numberOfSides = 11
print(namedShape.simpleDescription())

A shape with 11 sides.

 

상속

상속의 특징은 다음과 같습니다.

  • class: 내클래스이름: 부모클래스이름 { ..... } 의 형태로 작성한다.
  • 부모클래스 키워드는 super를 사용한다.
  • 오버라이딩시에는 override 키워드를 반드시 기입해야 한다.

 

class Square: NamedShape {
    var sideLength: Double
    
    // 상속받은 클래스는 상속한 클래스를 따라 초기화자가 반드시 있어야 함
    init(sideLength: Double, name: String){
        self.sideLength = sideLength // self 키워드 (나 자신) -> Square
        super.init(name: name) // super 키워드 (부모 클래스) -> NamedShape
        numberOfSides = 4
    }
    
    // 정사각형의 넓이 = 한 변의 길이의 제곱
    func area() -> Double {
        return sideLength * sideLength
    }
    
    // 오버라이딩 시에 override 키워드 반드시 필요
    override func simpleDescription() -> String {
        return "A square with sides of length \(sideLength)."
    }
}
let test = Square(sideLength: 5, name: "test square")
print(test.area())
print(test.simpleDescription())

25.0
A square with sides of length 5.0.

 

퀴즈 1. NamedShape클래스의 또 다른 하위 클래스인 Circle을 작성하시오. 이 클래스는 이니셜라이저를 통해 radiusname을 인자로 받는다. Circle 클래스 안에 area, simpleDescription 함수를 구현하시오.

class Circle: NamedShape {
    var radius: Double
    init(radius: Double, name: String){
        self.radius = radius
        super.init(name: name)
    }
    
    func area() -> Double {
        return pow(radius, 2) * Double.pi
    }
    
    override func simpleDescription() -> String {
        return "A circle with area \(area())."
    }
}
let test2 = Circle(radius: 10, name: "test circle")
print(test2.area())
print(test2.simpleDescription())

314.1592653589793
A circle with area 314.1592653589793.

 

프로퍼티 – getter/setter

getter/setter를 비롯한 프로퍼티의 설정은 변수 선언 시 변수 이름 옆에 괄호 {} 로 묶은 다음  그 안에서 작성합니다. get, set 키워드를 사용합니다. 또한 특이점으로 setter를 통해 들어오는 값은 newValue라는 예약된 이름의 변수를 통해 다루게 됩니다.

아래 예제는 정삼각형 클래스입니다.

class EquilateralTriangle: NamedShape{
    var sideLength: Double = 0.0
    
    init(sideLength: Double, name: String){
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 3
    }
    
    // getter/setter
    // newValue: setter에서 사용하는 예약된 키워드
    var perimeter: Double { // perimeter: 둘레
        get {
            return 3.0 * sideLength
        }
        set {
            sideLength = newValue / 3.0
        }
    }
    
    override func simpleDescription() -> String {
        return "An equilateral triagle with sides of length \(sideLength)."
    }
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")

// getter 사용
print(triangle.perimeter)

// setter 사용
triangle.perimeter = 9.9
print(triangle.sideLength)

9.3
3.3000000000000003

 

프로퍼티 – willSet/didSet

willSetdidSet은 프로퍼티의 변경 후(willset), 또는 변경 직전(didSet)에 실행되는 setter입니다. 공통적으로 변경되는 값을 감지하는 기능이 있으며 두 기능의 차이는 실행 시점만 차이가 있습니다. 또한 초기화시에는 실행되지 않고, 초기화 이후에 값을 변경할 때에만 실행된다는 특징이 있습니다.

class TriangleAndSquare{
    var triangle: EquilateralTriangle{
        willSet{
            square.sideLength = newValue.sideLength
            print("triangle이 willSet되었습니다.")
        }
    }
    var square: Square{
        willSet{
            triangle.sideLength = newValue.sideLength
            print("square가 willSet되었습니다.")
        }
    }
    init(size: Double, name: String){
        square = Square(sideLength: size, name: name)
        triangle = EquilateralTriangle(sideLength: size, name: name)
    }
}

초기화시에는 willSet이 동작하지 않습니다.

var triangleAndSquare = TriangleAndSquare(size: 10, name: "another test shape")
print(triangleAndSquare.square.sideLength)
print(triangleAndSquare.triangle.sideLength)

10.0
10.0

 

초기화 이후 square를 변경시에는 willSet이 동작합니다.

triangleAndSquare.square = Square(sideLength: 50, name: "a larger square")
print(triangleAndSquare.triangle.sideLength)

square가 willSet되었습니다.
50.0

 

클래스 예제: 카운터
class Counter {
    var count: Int = 0
    
    func incrementBy(_ amount: Int, numberofTimes times: Int) {
        count += amount * times
    }
    
    func outCount() -> Int {
        return count
    }
}
var counter = Counter()
counter.incrementBy(2, numberofTimes: 4)
print(counter.outCount())

8

 

옵셔널(optional)과 nil

변수의 타입 뒤에 물음표를 쓰면 이 변수는 옵셔널 값이라는 것을 나타냅니다. 옵셔널 변수란 nil을 가질 수 있으면 옵셔널 변수, 가질 수 없다면 비 옵셔널 변수(non-optional) 입니다. 스위프트의 변수는 기본적으로 non-optional입니다.

그렇다면 nil은 무엇일까요? nil이란 변수에 어떤 값도 들어있지 않은 상태로 비슷한 것으로 null이 있습니다.

옵셔널 변수를 선언하면 기본적으로 안에는 nil 상태입니다.

var optionalString: String?
print(optionalString == nil)

true

옵셔널 변수에 값을 넣으면 nil 상태가 아닙니다.

optionalString = "Hell"
print(optionalString == nil)

false

 

옵셔널 값은 if문으로 다룰 수 있습니다. 이것을 언래핑(unwrapping)이라 합니다. 옵셔널 값은 nil의 가능성 때문에 논옵셔널 값과 같이 다뤄질 수 없으며, 언래핑을 통해 옵셔널 값을 언옵셔널로 바꾸는 과정을 거칩니다.

var optionalName: String? = "John Appleseed"
var greeting = "Hell!"

// optionalName에 값이 있다면 name 상수에 집어넣고
// "Hell, \(name)"을 greeting 에 할당하라.
if let name = optionalName {
    greeting = "Hell, \(name)"
}

print (greeting)

Hell, John Appleseed

 

옵셔널 참고: http://monibu1548.github.io/2018/05/12/swift-optional/

퀴즈 1. optionalName에 nil을 할당하고, 할당된 값이 nil일 때 “Hell, Anonymous”을 greeting에 할당하도록 else 절을 추가하시오.

optionalName = nil
if let name = optionalName {
    greeting = "Hell, \(name)"
} else {
    greeting = "Hell, Anonymous"
}
print(greeting)

 

클래스에서 옵셔널 값 사용
let optionalSquare: Square? = Square(sideLength: 2.5, name: "Optional square")
let sideLength = optionalSquare?.sideLength
print(sideLength ?? "nil")

2.5

 

let optionalSquare2: Square? = nil
let sideLength2 = optionalSquare2?.sideLength
print(sideLength2 ?? "nil")

nil

?? 연산자는 삼항 연산자가 더욱 간략화된 형태로. sideLengthnil이 아니면 ?? 앞에 있는 변수를 그대로 쓰고, 만약 nil이라면 ?? 뒤에 있는 변수를 사용하라는 의미입니다.

 

as – 형 변환 (Type Casting)
  • as? : 형 변환이 될 것이 불확실할 때
  • as! : 형 변환이 될 것이 확실할 때, 주로 다운캐스팅에 사용
class Animal {
    let name: String?
    init(name: String) {
        self.name = name
    }
    
    func move() -> (){
        print("오른쪽으로 이동")
    }
}

class Dog: Animal {
    // Dog 전용 함수
    func bark() -> () {
        print ("멍멍")
    }
}

class Frog: Animal {
    // Frog 용으로 오버라이딩
    override func move() -> (){
        print("오른쪽으로 점프")
    }
}

let someDogAsAnimal: Animal = Dog(name: "Dog Bird") // Dog
someDogAsAnimal.name ?? "nil" // Dog Bird
(someDogAsAnimal as! Dog).bark() // 멍멍
(someDogAsAnimal as? Dog) // Dog

let someFrogAsAnimal: Animal = Frog(name: "ggr")
someFrogAsAnimal.move() // 오른쪽으로 점프
스위프트 기초 시리즈

문의 | 코멘트 또는 yoonbumtae@gmail.com


카테고리: Swift


0개의 댓글

답글 남기기

Avatar placeholder

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다