ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [6주차] Swift 문법 5(클래스 failable initialize 상속)
    iOS프로그래밍기초 2024. 10. 10. 16:35

    1. class , object , instance

     

     

    - 스위프트에서는 프로퍼티와 메소드로 말함

     

    - 스위프트에서는 인스턴스만들때 new 안씀

     

     

     

     

     

    2. property

    - 인스턴스 메서드와 타입 메서드 2가지가 있다.

     

    class Man{
        //var age : Int // error , stored property는 초기값 없이 선언안됨
        var age : Int = 0  // 1번 초기값을 주기
        var weight : Double = 0.0
    }

    - 프로퍼티는 2종류가 있다.

    - 스토어드 프로퍼티는 초기값이 있어야 한다 

    - 또는 옵셔널을 주워야함

     

    class Man{
        var age1 : Int?  // 2번 옵셔널 변수로 만들어서 초기값을 자동으로 nil을 주기
        var age2 : Int!  // 
        var weight : Double = 0.0
    }

    - 옵셔널 변수를 선언해 자동으로 nil값을 주기

     

     

     

    3. 클래스 선언 , 인스턴스 정의

    class Man{
        var age : Int = 1
        var weight : Double = 3.5
        
        func display() {
            print("나이=\(age), 몸무게=\(weight)")
        }
    }
    
    //var kim : Man
    //kim.age  //Variable 'kim' used before being initialized
    
    var kim : Man = Man()
    print(kim.age)
    kim.display()

    - kim 은 Man 클래스 타입으로 함 //    kim : Man

    - 주석에서는 kim이 age에 접근할려고 하면 에러가뜸 - 이니셜라이즈를 사용해라

     

    - 눈에 보이지 않는 생성자  디폴트 이니셜라이즈가 있음

    - 이니셜라이즈를 통해서 kim을 만듬

     

     

     

    4. 언어들 마다 클래스를 만드는 형태

    #include <iostream>
    
    class MyClass {
    public:
        int x;
        MyClass(int val) { x = val; }
    };
    
    int main() {
        MyClass obj(10);
        std::cout << "Value of x: " << obj.x << std::endl;
        return 0;
    }

     

    class MyClass {
        int x;
        MyClass(int val) {
            x = val;
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            MyClass obj = new MyClass(10);
            System.out.println("Value of x: " + obj.x);
        }
    }

     

    using System;
    
    class MyClass {
        public int x;
        public MyClass(int val) {
            x = val;
        }
    }
    
    class Program {
        static void Main(string[] args) {
            MyClass obj = new MyClass(10);
            Console.WriteLine("Value of x: " + obj.x);
        }
    }

     

    class MyClass {
        constructor(val) {
            this.x = val;
        }
    }
    
    const obj = new MyClass(10);
    console.log("Value of x: " + obj.x);

     

    class MyClass:
        def __init__(self, val):
            self.x = val
    
    obj = MyClass(10)
    print("Value of x:", obj.x)

     

    class MyClass {
        var x: Int
        init(val: Int) {
            x = val
        }
    }
    
    let obj = MyClass(val: 10)
    print("Value of x: \(obj.x)")

     

     

     

     

    5. 인스턴스 메소드 , 클래스 메소드

    class Man{
      var age : Int = 1
      var weight : Double = 3.5
        
      func display(){. // 인스턴스 메소드
       print("나이=\(age), 몸무게=\(weight)")
      }
        
      class func cM(){ // 클래스 메소드
        print("cM은 클래스 메서드입니다.")
      }
        
      static func scM(){
        print("scM은 클래스 메서드(static)")
      }
    }
    
    
    var kim : Man = Man()
    
    // kim.cM      //error
    // kim.scM()   //error
    // Static member 'scM' cannot be used on instance of type 'Man'
    // 클래스 메소드는 인스턴스가 아니라 클래스가 사용하는 메소드
    
    kim.display() //인스턴스 메서드는 인스턴스가 호출
    Man.cM()      //클래스 메서드는 클래스가 호출
    Man.scM()     //클래스 메서드는 클래스가 호출

    - 메소드의 종류 2가지,  인스턴스 메소드 , 클래스 메소드

    - 클래스 메소드는 클래스에서 호출

    - 인스턴스 메소드는 인스턴스가 호출

     

     

    - 클래스 메소드는 2종류로   class 를 붙인것 , static을 붙인것 2개다

    - class 키워드를 사용한 메소드는 자식클래스에서 오버라이드가 가능하다.

    - class를 쓰면 오버라이드 가능 , static을 사용하면 오버라이드 불가능

     

     

     

     

    6. initalizer

    class Man{
        var age : Int = 1
        var weight : Double = 3.5
        
        init(yourAge: Int, yourWeight : Double){
            age = yourAge
            weight = yourWeight
        } //designated initializer
        
        func display(){ // 인스턴스 메소드
            print("나이=\(age), 몸무게=\(weight)")
        }
    }
    
    
    // var kim : Man = Man().  //error
    // Missing arguments for parameters 'yourAge', 'yourWeight' in call
    
    var kim : Man = Man(yourAge: 10, yourWeight: 30.5)
    kim.display()

     

    - 이니셜라이즈 , 생성자는 함수이다.

    - 이니셜라이즈를 직접 작성하고 , 파라미터를 만들면 , 인스턴스 정의시 () 빈값을 넣으면 에러. 

     

    - 아규먼트 레이블등 과 같이 쓰면서 아규먼트를 넣어서 인스턴스를 만들어야함

     

     

     

     

    - 모든 프로퍼티를 다 초기화하는 생성자를  designated initializer.  데지그나이트 이니셜라이저 라고함

    - 프로퍼티 하나만 초기화 하면  designated initializer 라고 안함

     

    var kim = Man.init(yourAge: 10, yourWeight: 30.5)
    kim.display()

     

    - init 함수를 기본으로 사용하고 있는거임  // 평소에 뺄 수 있음

     

     

     

     

    7. self

    class Man{
        var age : Int = 1
        var weight : Double = 3.5
        
        init(age: Int, weight : Double){
            self.age = age
            self.weight = weight
        }
        
        func display(){
            print("나이=\(age), 몸무게=\(weight)")
        }
    }
    
    
    var kim = Man(age: 10, weight: 30.5)
    // Cannot assign to value: 'age' is a 'let' constant
    // Cannot assign to value: 'weight' is a 'let' constant
    // self 없이 하면 지역변수를 가리키는게 당연
    
    kim.display()

     

    - 스위프트에서 인스턴스를 가리키는 건 self , 다른언어의 this

     

    8. 

    이런것도 있는데 일단 지나감

     

     

    9. 메소드 오버라이딩 method overloading

    class Man{
        var age : Int = 1
        var weight : Double = 3.5
        
        init(age: Int, weight : Double){  // 첫번째 생성자
            self.age = age
            self.weight = weight
        }
        
        init(age: Int){. // 두번째 생성자
            self.age = age
        }
        
        func display(){
            print("나이=\(age), 몸무게=\(weight)")
        }
    }
    
    
    var kim = Man(age: 10, weight: 30.5)
    var lee = Man(age: 3)
    
    lee.display()
    kim.display()

    - 생성자가 여러개 있는 코드예제

    - 매개변수 종류나, 개수가 다른 init 함수가 여러개 있음

     

     

     

     

    UIImage 

    https://developer.apple.com/documentation/uikit/uiimage

     

    UIImage | Apple Developer Documentation

    An object that manages image data in your app.

    developer.apple.com

     

     

    - 애플에서 만든 UIImage 는 사용자를 위해 수많은 init() 을 overriding  해놨다.

     

     

     

     

    10. failable initializers(실패 가능한 생성자: init? )    // 아주 중요함 , 어려움

     

     

    - init?()  ,  init!()    !는 잘안씀

    - 생성자가 실행되지않는 오류상황에 nil을 리턴   

     

     

     

    class Man{
        var age : Int
        var weight : Double
        func display(){
            print("나이=\(age), 몸무게=\(weight)")
        }
        init?(age: Int, weight : Double){  // failable initializer
            if age <= 0 {
                return nil
            }
            else {
                self.age = age
            }
            self.weight = weight
        } 
    }
    var kim : Man = Man(age:10, weight:20.5)  //error 
    //Value of optional type 'Man?' must be unwrapped to a value of type 'Man'
    kim.display()
    var lee : Man = Man(age:0, weight:3.5)    //error
    lee.display()

     

    - ex) Student() 생성시 age가 0보다 낮을때 등을 조건으로 nil 을 리턴

    - 일반 인스턴스가 안만들어짐 , 옵셔널로 감싸진 인스턴스가 생성됨

    - 옵셔널을 풀어주는 게 필요함

     

     

    var kim : Man = Man(age:10, weight:20.5)!   //!
    kim.display()
    var lee : Man = Man(age:0, weight:3.5)!     //!
    lee.display()

    - 강제로 풀기. 좋은 방법은 아님

     

     

    var kim : Man = Man(age:10, weight:20.5)!   //!을 붙이기.
    kim.display()
    var lee : Man = Man(age:0, weight:3.5)!     //age가 0임 nil을 출력
    // 크레시가 나며 앱이 다운됨
    lee.display()

    - 제대로 사용해라.

     

     

    - 옵셔널을 푸는 4가지 방법

    - 2번 형태가 1번의 간소화 형태를 띄우며 가장 많이 사용함

    - 3,4는 언젠가 크래시가 나게됨

     

     

    1번)

    var lee : Man? = Man(age:0, weight:3.5) // Man? 
    if let lee {   // if let 형
        lee.display()    // lee가 nil이 아닐때만 실행해라.
    }

     

    2번)

    if let lee = Man(age:0, weight:3.5){   // Man에서 어차피 옵셔널이 나오니 바로 if let으로 보냄
        lee.display()
    }

     

     

    <전체코드 주석설명>

    // Man 클래스 정의
    class Man {
        var age: Int        // 나이를 저장하는 속성
        var weight: Double  // 몸무게를 저장하는 속성
        
        // 객체의 속성(나이, 몸무게)을 출력하는 메서드
        func display() {
            print("나이=\(age), 몸무게=\(weight)")
        }
        
        // failable initializer (실패 가능한 생성자)
        // 나이와 몸무게 값을 받아서 초기화하며, 값이 적절하지 않으면 nil을 반환
        init?(age: Int, weight: Double) {
            // 나이와 몸무게가 0 이하이면 객체 생성을 실패로 처리하고 nil을 반환
            if age <= 0 || weight <= 0.0 {
                return nil  // 객체 생성 실패
            } else {
                // 나이와 몸무게가 정상적이면 속성을 초기화
                self.age = age
                self.weight = weight
            }
        }
    }
    
    // 객체 생성 및 조건에 따른 처리
    // if let 구문을 사용해 Man 객체를 생성하고 성공 여부를 확인
    if let lee = Man(age: 1, weight: 0.0) {
        // 만약 객체가 정상적으로 생성되면 display 메서드를 호출하여 속성 출력
        lee.display()
    } else {
        // 객체 생성 실패 시 아무것도 출력되지 않음 (예: 나이가 1이지만 몸무게가 0.0이므로 객체 생성 실패)
        // 이 경우에는 else 블록이 없어 출력하지 않음
    }

     

     

     

     

     

     

    11. 클래스 상속

    - 객체 지향 언어에서 가장 많이 사용하는것은 상속이다.

    - 스위프트의 상속은   부모 : 자식   형태를 가짐

    - 상속은 클래스만 가능한다.

    - 부모하나만 상속가능 하다. 

    - , 후 여러개 더 있으면 부모클래스가아닌 프로토콜이다.

    - 프로토콜은 여러개가 상속 가능하다.

     

    class Man{
        var age : Int = 1
        var weight : Double = 3.5
        
        init(age: Int, weight : Double){  // 첫번째 생성자
            self.age = age
            self.weight = weight
        }
        
        func display(){
            print("나이=\(age), 몸무게=\(weight)")
        }
    }
    
    class Student : Man { // Man은 super or 부모클래스
        
    }
    
    var lee : Student = Student(age: 20, weight: 70.5)
    lee.display()
    
    var kim = Man(age: 10, weight: 30.5)
    kim.display()

    - Student 클래스는 아무것도 없는 빈 클래스지만  상속을 통해 부모의 모든 요소를 받아왔다 - 실제로 못받는 값들도 있음

     

     

     

     
    12. super
     
    class Man{
        var age : Int
        var weight : Double
        
        func display(){
            print("나이=\(age), 몸무게=\(weight)")
        }
        init(age: Int, weight : Double){
            self.age = age
            self.weight = weight
        }
    }
    
    class Student : Man {
        var name : String
        
        func displayS() {
            print("이름=\(name), 나이=\(age), 몸무게=\(weight)")
        }
        init(age: Int, weight : Double, name : String){
            self.name = name
            super.init(age:age, weight:weight) // 부모age에 자식age값넣기
        }//error:'super.init' isn't called on all paths before returning from initializer
    }
    var lee : Student = Student(age:20,weight:65.2,name:"홍길동")
    lee.displayS()

     

     

    - Student 자식클래스가 부모클래스와 다르게 name을 사용하고 싶음

     

     

     

    13. 오버라이딩 overriding.   ,  override 키워드

    - 부모의display() 를 자식클래스 에서 똑같이 쓸려고 했더니 나온 에러

     

    class Man{
        var age : Int
        var weight : Double
        
        func display(){
            print("나이=\(age), 몸무게=\(weight)")
        }
        init(age: Int, weight : Double){
            self.age = age
            self.weight = weight
        }
    }
    
    class Student : Man {
        var name : String
        
        override func display() {   //오버라이드
            print("이름=\(name), 나이=\(age), 몸무게=\(weight)")
        }
        init(age: Int, weight : Double, name : String){
            self.name = name
            super.init(age:age, weight:weight) 
        }
    }
    var lee : Student = Student(age:20,weight:65.2,name:"홍길동")
    lee.display()

     

    - 스위프트에서는 자식클래스안 에서   override 키워드를 사용해서 오버라이딩을 구현한다.

    - 오버라이드는 객체지향 언어에서 반드시 필요

     

     

     

    <전체설명>

    // 부모 클래스 Man 정의
    class Man {
        var age: Int        // 나이를 저장하는 속성
        var weight: Double  // 몸무게를 저장하는 속성
        
        // 부모 클래스의 메서드. 나이와 몸무게를 출력함.
        func display() {
            print("나이=\(age), 몸무게=\(weight)")
        }
        
        // 부모 클래스의 생성자. 나이와 몸무게 값을 초기화함.
        // designated initializer: 모든 프로퍼티를 초기화하는 생성자
        init(age: Int, weight: Double) {
            self.age = age              // 전달받은 나이 값을 속성에 저장
            self.weight = weight        // 전달받은 몸무게 값을 속성에 저장
        }
    }
    
    // 자식 클래스 Student는 Man 클래스를 상속받음
    class Student: Man {
        var name: String    // 이름을 저장하는 속성
        
        // 부모 클래스의 display 메서드를 오버라이드 (재정의)하여 이름까지 출력함.
        override func display() {
            // 오버라이드된 메서드에서는 부모 클래스의 메서드를 덮어써서 자식 클래스에 맞게 수정할 수 있음
            print("이름=\(name), 나이=\(age), 몸무게=\(weight)")
        }
        
        // 자식 클래스의 생성자. 이름, 나이, 몸무게를 모두 초기화함.
        // 이니셜라이저에서 부모 클래스의 초기화 메서드(super.init)를 호출하여 상속받은 속성들을 초기화해야 함.
        init(age: Int, weight: Double, name: String) {
            self.name = name  // 전달받은 이름 값을 저장
            super.init(age: age, weight: weight) // 부모 클래스의 초기화 메서드 호출
            // 부모 클래스의 속성(age, weight)을 초기화하기 위해 반드시 super.init을 호출해야 함
            // 'super.init'을 호출하지 않으면 에러 발생 (부모 클래스 속성이 초기화되지 않기 때문)
        }
    }
    
    // Student 객체 생성
    var lee: Student = Student(age: 20, weight: 65.2, name: "홍길동")
    // lee.display() 호출 시 오버라이드된 메서드가 실행됨
    lee.display()  // 출력: 이름=홍길동, 나이=20, 몸무게=65.2
    
    // 추가 설명:
    
    // 1. 인스턴스 생성 시 new 키워드가 필요 없음
    // Swift는 다른 언어들과 달리 객체를 생성할 때 new를 사용하지 않음.
    // 예: var lee: Student = Student() // new 키워드를 쓰지 않음
    
    // 2. self
    // self는 현재 인스턴스를 가리킴. 다른 언어의 this와 동일한 역할을 함.
    // self.age = age // 생성자에서 전달받은 매개변수 age를 인스턴스의 age에 할당
    
    // 3. 오버라이드 (override)
    // 자식 클래스에서 부모 클래스의 메서드를 재정의하기 위해 override 키워드를 사용함.
    // 부모의 메서드를 오버라이드하는 경우, 반드시 override 키워드를 사용해야 함.
    // Swift는 이 키워드를 통해 의도적인 재정의를 명시적으로 요구함.
    
    // 4. 클래스 메서드와 인스턴스 메서드
    // display()는 인스턴스 메서드로, 인스턴스를 통해 호출됨.
    // 클래스 메서드는 static이나 class 키워드를 사용하여 정의되며, 인스턴스가 아닌 클래스 자체에서 호출 가능.
    // 예: class func classMethod() { ... }
    // 클래스 메서드는 클래스에서 직접 호출, 인스턴스 메서드는 인스턴스를 통해 호출됨.

     

Designed by Tistory.