Swift 클래스

  1. 클래스를 이해하기 전에 먼저 객체 지향 프로그램에 대해서 이해가 필요하다.
    1. 해당 내용은 아래 링크에 자세하게 다루었다.
      1. 참고 링크 : https://klausbreaktime.blogspot.com/2017/07/blog-post.html
    2. 정리하자면 객체 지향 프로그래밍의 특징은 아래와 같다.
      • 모든 것을 객체로 취급한다.
      • 객체는 실 세계에 존재하거나 생각할 수 있는 것들을 통틀어서 이야기한다.
      • 클래스로 정의되고 클래스의 속성(변수, 데이터, 프로퍼티)와 클래스의 메소드 형태로 구성된다.
      • 클래스의 메소드는 행위를 나타낸다.
  2. 클래스 정의와 객체 생성 방법
    1. 클래스 정의 : class [클래스 명] { 클래스의 속성 및 메소드 }
      클래스 정의
      class Rectangle {
         // 사각형의 가로, 세로 길이에 대한 속성을 정의
         // 사각형의 넓이에 대한 메소드를 정의
      }
    2. 객체 생성 : [클래스 명]()
      객체 생성
      var rect = Rectangle() // 새로운 객체 대입 가능
      rect = Rectangle()

      let rect1 = Rectangle() // 새로운 객체 대입 불가능
    3. 소스코드 파일과 클래스의 관계
      1. 소스 파일 단위와 클래스 정의 단위는 서로 다르다.
      2. 하나의 소스 코드 파일 내에 다수의 클래스 정의가 가능하다.
      3. 하나의 클래스를 개별 소스 코드 파일로 생성한다.
      4. 하나의 클래스를 다수의 소스 코드 파일에 작성 가능하다.
      5. 소스코드 파일에서 탑 레벨에 실행 코드는 작성할 수 없다.
  3. 클래스와 프로퍼티
    1. 프로퍼티는 객체의 데이터를 나타내며 값을 저장하고 읽는 역할을 한다.
    2. 프로퍼티 종류 (저장 프로퍼티, )
      1. 저장 프로퍼티
        1. 데이터를 저장하는 용도로 쓰인다.
        2. 데이터를 읽고 쓰는 역할을 한다.
        3. 객체 생성 시 초기화하며, 초기화하는 방법이 필요하다.
        4. 저장 프로퍼티 정의 및 사용 예시는 아래와 같다.
          저장 프로퍼티 예시
          // 저장 프로퍼티 정의
          class MyClass{
             // 초기값을 설정한 프로퍼티
             var intProperty = 0
             // 초기값을 설정하지 않은 프로퍼티
             var floatProperty : Float?
             // 초기값 설정이 반드시 필요한 프로퍼티
             var strProperty : String = "Test"
          }

          // 저장 프로퍼티 사용
          var obj = MyClass() // 객체 생성
          // 저장 프로퍼티에 값을 저장
          obj.intProperty = 10
          obj.floatProperty = 3.1
          // 저장 프로퍼티에 값을 사용
          let val = obj.floatProperty
          print("val = \(val)") // val = 3.1 출력
      2. 계산 프로퍼티
        1. 데이터를 저장하지 않는다.
        2. 프로퍼티 읽기/쓰기 코드를 작성한다.(set/get)
        3. 읽기전용은 가능하고 쓰기 전용은 사용할 수 없다.(get만 존재)
        4. 계산 프로퍼티 쓰기에서 설정 값은 반드시 한개만 가능하다.(set에 파라미터는 한개만 가능하다.)
        5. set에 들어가는 기본 파라미터 명은 newValue 이며, 그대로 사용해도 되고, 변경도 가능하다.
        6. 계산 프로퍼티 정의 및 사용 예는 아래와 같다.
          계산 프로퍼티 예시
          // 계산 프로퍼티 정의
          class Rectangle {
              var width = 0
              var height = 0
             // 계산 프로퍼티 정의 (읽기 전용)
             var area : Int {
                get {
                    return (width * height)
                }
             }
          }

          // 계산 프로퍼티 사용
          var rect = Rectangle()
          rect.width = 10
          rect.height = 20
          print(rect.area) // 200 출력
      3. 프로퍼티 변경 감시 : 프로퍼티가 객체 생성 후에 변경이 될 경우 변경 전의 값과 변경 후의 값을 확인할 수 있다.
        1. 프로퍼티 변경 전 : willSet
        2. 프로퍼티 변경 후 : didSet
        3. 프로퍼티 변경 감시 사용 예시는 아래와 같다.
          프로퍼티 감시 예시
          class Rectangle {
             var height : Int = 0 {
                willSet {
                     print("사각형 높이 변경 예정 : \(newValue)")
                 }
                 didSet {
                     print("사각형 높이 변경 완료. 이전 값 : \(oldValue)")
                 }
             }
          }
      4. 프로퍼티의 늦은 초기화 : 보통은 객체 생성과 동시에 프로퍼티를 초기화를 하지만 프로퍼티를 사용할 때 초기화하는 방법이 있다.
        1. 프로퍼티의 늦은 초기화하는 lazy 키워드를 앞에 붙여서 정의한다.
        2. 사용 예시는 아래와 같다.
          프로퍼티의 늦은 초기화
          class Person {
             lazy var phone = Phone()
          }

          let john = Person()
          john.phone // 이 때 초기화가 된다.
  4. 클래스와 메소드
    1. 클래스 내에서 메소드(함수)는 어떤 동작을 할지 정의한다.
    2. 메소드의 종류
      1. 인스턴스 메소드
        1. 객체 생성 후 사용해야한다. (객체를 생성하지 않고는 사용할 수 없다.)
        2. 객체의 데이터(프로퍼티) 접근이 가능하다.
      2. 타입 메소드
        1. 객체를 생성하지 않고 사용 가능하다.
        2. 객체의 데이터(프로퍼티) 접근을 할 수 없다.
        3. 키워드는 static으로 한다.(자세한 내용은 5번에서 다룬다.)
    3. 이번에 다루는 메소드는 인스턴스 메소드이다.
    4. 클래스 내에서 메소드 정의 및 사용 예시는 아래와 같다.
      클래스 내에서 메소드 정의 및 사용
      // 클래스 내에 메소드 정의
      class Counter {
         var count = 0
         // 파라미터가 없는 메소드 정의
         func increment() {
             count += 1
         }
         // 파라미터가 1개 있는 메소드 정의
         func increment(amount : Int) {
            count += amount
         }
         // 파라미터가 2개 있는 메소드 정의
         func increment(amount : Int, times : Int) {
            count += (amount * times)
         }
      }

      // 정의된 메소드 사용
      let counter = Counter()
      counter.increment() // count가 1로 증가
      counter.increment(amount : 5) // counter가 6으로 증가
      counter.increment(amount : 5, times : 3)
      // counter가 21로 증가
    5. self 포인터
      1. 클래스 내에서 객체 자신을 참조하는 포인터로 프로퍼티 이름과 메소드의 파라미터 이름이 겹칠 때 프로퍼티 이름과 파라미터 이름을 구분하기 위해서 사용한다.
        self 포인터 사용
        class Counter {
           var count = 0 // 프로퍼티
            // 메소드
            func setCount(count : Int) { // 메소드의 파라미터
                self.count = count
            }
        }
  5. 클래스의 타입 메소드와 타입 프로퍼티
    1. 타입 메소드와 타입 프로퍼티는 모두 객체 생성 없이 사용이 가능하다.
    2. 타입 메소드는 클래스 내에 정의된 프로퍼티에는 접근할 수가 없다.
    3. 타입 메소드와 타입 프로퍼티는 static을 앞에 붙여서 정의한다.
    4. 타입 메소드, 타입 프로퍼티 사용 예시는 아래와 같다.
      타입 메소드, 타입 프로퍼티 정의 및 사용
      // 클래스 내에 타입 메소드, 타입 프로퍼티 정의
      class Rectangle {
         var width = 0
         var height = 0
         // 사각형에 대한 정보를 타입 프로퍼티로 정의
         static var edge = 4
       
         var area {
             get {
                return (width * height)
             }
         }
         // 이름에 대한 정보를 타입 메소드로 정의
         static func name()  -> String {
              return "사각형"
         }
      }

      // 정의된 타입 메소드, 타입 프로퍼티 사용
      var rect = Rectangle()
      rect.width = 10
      rect.height = 20

      // 타입 프로퍼티 접근
      Rectangle.edge // 4
      // 타입 메소드 접근
      Rectangle.name() // 사각형
  6. 클래스와 연산자
    1. 연산자 : 클래스 내에 메소드를 정의하는 것과 동일하게 연산자를 이용하여 해당 클래스 내에서 전용으로 사용되는 연산자를 정의하여 사용할 수 있다. 예) + 연산자에 추가 기능을 더할 수 있다.
    2. 연산자 정의 시 필요 내용
      1. 피 연산자의 개수는 파라미터의 개수와 동일하다.
        1. 단항 연산자는 파라미터 개수가 1개
        2. 이항 연산자는 파라미터 개수가 2개
      2. 연산자의 위치
        1. 앞에 위치 : 전위 연산자 - prefix
        2. 중간에 위치(기본값) : 중위 연산자 - infix
        3. 뒤에 위치 : 후위 연산자 - postfix
      3. 연산자 함수 정의
        1. 연산자 함수는 타입 메소드로 작성
        2. 연산자 함수의 이름은 연산자 예) +, -
        3. 단항 연산자는 연산자 위치 정보가 필요 (prefix, infix, postfix)
    3. 사용 방법
      연산자 선언 및 사용
      // 클래스 내에 연산자 선언
      class Point {
         var x : Int
         var y : Int
         // Initializer
         init(x : Int, y : Int) {
             self.x = x
             self.y = y
         }
         // 단항 연산자 선언
         static prefix func -(point : Point) -> Point {
             var another = Point()
             another.x = -point.x
             another.y = -point.y
             return another
         }
         // 이항 연산자 선언
         static func +(left : Point, right : Point) -> Point {
             return Point(x : (left.x + right.x), y : (left.y + right.y))
         }
      }

      var point1 = Point(x : 10, y : 20)
      point2 = -point1 // Point(x : -10, y : -20)
      let result = point1 + point2 // Point(x : 0, y : 0)