iOS Development/Swift

[Swift] #6 - Class

se0m 2021. 9. 3. 12:34

** 객체지향 프로그래밍

  • 객체로 프로그램을 구성
  • 객체: 정보(변수) + 동작(함수)
  • 객체를 만들 때는 클래스라는 설계도를 이용해서 만듬

 

 

** 객체지향의 용어

  • 객체: 데이터, 행위, 아이덴티티를 가지고 있는 것
  • 클래스: 객체를 생성하는 틀
  • 캡슐화: 행위와 상태를 포장하고 외부에 노출할 것과 감출 것을 결정하는 것
  • 상속: 코드의 재사용성과 계층구조의 표현
  • 다형성: 캡슐화, 상속과 함께 동작함으로써 객체-지향 프로그램의 흐름 제어를 단순화하는 것

 

 

** 클래스 정의

  • 프로퍼티 = 멤버 변수 = 속성
// Class
// '사용자 정의 타입'
// 클래스 정의
class SimpleClass {
    var name = "SimpleClass"
    var count = 0
}

// 객체 생성
var simpleClass = SimpleClass()
var simpleClass1 = SimpleClass()

// 객체 내부 접근
simpleClass.count = 1
simpleClass1.count = 2

var count = simpleClass.count

print(simpleClass.count)
print(simpleClass1.count)

 

 

 

** 클래스 정의 - 메소드

// 클래스 정의 - 메소드
class Vehicle {
    var speed = 0.0
    
    var mile:Double {
        // return Double(speed) * 0.6213
        
        // 속성값을 읽을 때는 get이 동작
        get {
            return Double(speed) * 0.6213
        }
        // 속성값을 사용할 때는 set이 동작
        set(newValue) {
            if newValue > 0 { // 제한두기 가능
                speed = newValue * 1.6
            } else {
                speed = 0
            }
        }
    }
    
    func speedUp() {
        speed += 10
    }
    
    func speedDn() {
        speed -= 10
    }
    
    func speed2Mile() -> Double {
        return Double(speed) * 0.6213
    }
}

var someVehicle = Vehicle()

someVehicle.speedUp()
print("changed speed = \(someVehicle.speed)")

print(someVehicle.speed2Mile())
print(someVehicle.mile)

someVehicle.mile = 94
print(someVehicle.speed)

 

 

 

** 연산 프로퍼티

  • 메소드와 하는 일은 같지만, 데이터가 중심일 때 사용하고 메소드에 비해 액션이 많지 않음
  • 연산 후 값을 저장하는 프로퍼티

 

 

** getter / setter

  • read-only 인 경우, setter 생략 가능
  • 올바른 값만 저장할 수 있도록 함 -> 캡슐화 (속성에 직접 접근 불가)

 

 

** 예제

// 클래스 정의 실습
// 정사각형 클래스
class Rectangle {
    var width = 0.0; var height = 0.0 // 초기화하지 않으면 ERROR -> 선언만 하고 할당되지 않은 상태: nil(= null)
    
    var area:Double {
        get { width * height }
        set(newVal) {
            width = sqrt(newVal)
            height = width
        }
    }
}

var rec = Rectangle() // 생성자가 정의되어 있지 않을 경우 자동으로 생성해줌
rec.width = 2
rec.height = 3

print("사이즈 변경 후 넓이: \(rec.area)")
rec.area = 100

print("넓이 변경 후 너비: \(rec.width)")

 

 

 

 

**  클래스 정의 -  생성자

  • 생성자: 멤버 변수를 초기화하고 메모리 공간을 할당(인스턴스화)
  • init이 하나도 없을 경우, 내부적으로 자동으로 생성하여 실행함
// 클래스 정의 - 생성자
class Square1 {
    var width:Double; var height:Double // 생성자에서 초기화해주므로 값을 할당하지 않았어도 ERROR가 나지 않음
    var area:Double {
        get {
            return width * height
        }
        set(newVal) { // area 값이 수정되면
            width = sqrt(newVal) // width, height 값도 변경
            height = width
        }
    }
    
    func duplicate() -> (Double, Double) {
        width *= 2
        height *= 2
        
        return (width, height)
    }
    
    // 생성자
    init(w:Double, h:Double) {
        width = w
        height = h
    }
}

var square1 = Square1(w:10, h:10)
print(square1.area)

square1.area = 25
print("width = \(square1.width) / height = \(square1.height)")

square1.duplicate()
print(square1.area)

 

 

 

** 클래스 정의 - self

  • self: 클래스 변수
// 클래스 정의 - self
class Square2 {
    var width:Double; var height:Double
    var area:Double {
        get { return width * height }
        set(newVal) { width = sqrt(newVal); height = width }
    }
    
    func duplicate() -> (Double, Double) {
        width *= 2
        height *= 2
        
        return (width, height)
    }
    
    init(width:Double, height:Double) {
        self.width = width
        self.height = height
        
        self.duplicate()
    }
}

 

 

 

** 클래스의 상속

  • Super class: 부모 클래스 / 공통 기능 재사용 가능
  • Sub class: 자식 클래스 

 

 

 

 

** 상속의 구현

  • 클래스 정의시 상속 받을 클래스를 명시함
  • 해당 클래스에 메소드가 없을 경우, 부모 클래스에서 찾아 실행함
// 클래스 상속
class Car:Vehicle {
    var wheelCount:Int; var seatCount:Int
    
    func shiftGear() {
        print("변속")
    }
    
    init(wheelCount:Int, seatCount:Int) {
        self.wheelCount = wheelCount
        self.seatCount = seatCount
    }
}

var car = Car(wheelCount: 4, seatCount: 2)
car.speedUp() // 부모 클래스의 메소드 실행
print(car.speed) // 부모 클래스의 멤버 변수 접근

 

 

 

** 예제

  • var truck = Truck(): ERROR
// 클래스 상속 실습
class Truck:Car {
    var loadage:Int = 0
    
    func load() {
        print("load")
    }
    
    func unLoad() {
        print("unLoad")
    }
}

var truck = Truck(wheelCount: 6, seatCount: 2) // Truck에 생성자가 없지만 그 부모 클래스에 존재하므로
truck.load()
truck.unLoad()

 

 

 

** 메소드 재정의

  • 오버라이딩: 부모 메소드 재정의
// 부모 메소드 재정의
class Truck1:Car {
    var loadage:Int = 0
    
    func load() {
        print("load")
    }
    
    func unLoad() {
        print("unLoad")
    }
    
    // 오버라이딩
    override func speedUp() {
        speed += 5
    }
}

class SportsCar:Car {
    override func speedUp() {
        speed += 20
    }
}

var testCar = Car(wheelCount: 4, seatCount: 4)
testCar.speedUp()
print(testCar.speed)

var testTruck = Truck1(wheelCount: 6, seatCount: 2)
testTruck.speedUp()
print(testTruck.speed)

var testSportsCar = SportsCar(wheelCount: 4, seatCount: 2)
testSportsCar.speedUp()
print(testSportsCar.speed)

 

 

 

** 생성자 재정의

// 생성자 재정의
class Truck2:Car {
    var loadage:Int
    
    func load() { print("load") }
    func unLoad() { print("unLoad") }
    
    init(loadage:Int, wheelCount:Int, seatCount:Int) {
        self.loadage = loadage // 자신
        
        super.init(wheelCount: wheelCount, seatCount: seatCount) // 부모의 생성자
    }
    
    override func speedUp() {
        speed += 5
    }
}

var truck2 = Truck2(loadage: 1000, wheelCount: 6, seatCount: 2)
print(truck2.loadage)


// 다형성: 같은 부모 다른 자식
class Sedan:Car {
    func loadPassenger() {
        print("Load Passanger")
    }
    
    override func shiftGear() {
        print("자동 변속")
    }
}

class Bus:Car {
    func loadCargo() {
        print("Load Cargo")
    }
    
    override func shiftGear() {
        print("수동 변속")
    }
}

var sedan = Sedan(wheelCount: 4, seatCount: 5)
sedan.shiftGear()

var bus = Bus(wheelCount: 4, seatCount: 50)
bus.shiftGear()