iOS 앱개발 6주차

2024. 10. 10. 16:48iOS앱개발

클래스 vs 객체 vs 인스턴스

 

 

스위프트에서 클래스를 정의하는 방법

class 새로운 클래스 이름 : 부모 클래스 {
// 프로퍼티
// 인스턴스 메서드
// 타입(type) 메서드(클래스 메서드)
}

 

var Kim = Man() //Swift

스위프트에서 클래스로부터 객체를 만드는 방법

class Man{
    var age : Int = 0
    var weight : Double //error , stored property 는 반드시 초기값이 필요하다
    
}

또는 stored property를  옵셔널 변수로 선언하는 방법도 있다.

class Man{
    var age : Int?
    var weight : Double!//error , stored property 는 반드시 초기값이 필요하다
}

 

인스턴스 메소드 display 지정

class Man{
    var age : Int = 1
    var weight : Double = 3.5
    func display() {
        print("나이 = \(age), 몸무게 = \(weight)")
    }
}

클래스를 통해서 인스턴스를 만들고 사용하는 방법이다.

class Man{
    var age : Int = 1
    var weight : Double = 3.5
    func display() {
        print("나이 = \(age), 몸무게 = \(weight)")
    }
}

var kim : Man = Man()
print(kim.age)
kim.display()

각 언어에서 클래스를 생성하고 객체를 만드는 방법을 간단히 설명하겠습니다.

C#

// 클래스 정의
public class MyClass
{
    public int MyProperty { get; set; }

    public MyClass(int value)
    {
        MyProperty = value;
    }
}

// 객체 생성
MyClass myObject = new MyClass(10);

Java

// 클래스 정의
public class MyClass {
    private int myProperty;

    public MyClass(int value) {
        myProperty = value;
    }
}

// 객체 생성
MyClass myObject = new MyClass(10);

C++

#include <iostream>
using namespace std;

// 클래스 정의
class MyClass {
public:
    int myProperty;

    MyClass(int value) {
        myProperty = value;
    }
};

// 객체 생성
MyClass myObject(10);

JavaScript

// 클래스 정의
class MyClass {
    constructor(value) {
        this.myProperty = value;
    }
}

// 객체 생성
const myObject = new MyClass(10);

Python

# 클래스 정의
class MyClass:
    def __init__(self, value):
        self.my_property = value

# 객체 생성
my_object = MyClass(10)

Swift

// 클래스 정의
class MyClass {
    var myProperty: Int

    init(value: Int) {
        myProperty = value
    }
}

// 객체 생성
let myObject = MyClass(value: 10)

class method

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)")
    }
}

클래스가 사용하는 메소드로 인스턴스 레벨이 아닌 클래스 레벨에서 사용된다

Man.scM()
Man.cM()

 

Man 의 인스턴스인 kim은 class method를 사용할 수 없다.

kim.scM()//Static member 'scM' cannot be used on instance of type 'Man'

class 키워드로 만든 클래스 메서드는 자식 클래스에서 override할 수 있다.

initializer

class Man{
    var age : Int = 1
    var weight : Double = 3.5
    init(yourAge : Int,yourWeight : Double){
        age = yourAge
        weight = yourWeight
    }
    func display(){
        print("나이 \(age) 몸무게 \(weight)")
    }
}

다른 언어에서 생성자에 해당하는 부분이다 프로퍼티를 초기화시킬때 사용하며 init 키워드를 사용한다 이는 자동으로 객체가 만들어질때 호출되는 함수이며 만약 initalizer가 없다면 자동으로 기본 initalizer가 호출된다 

* 위와같이 모든 프로퍼티 age, weight 를 모두 초기화하는 생성자를 designated initializer 라고 한다

self and this

self를 사용하는 언어

  • Python: 메서드 내에서 인스턴스를 참조할 때 self를 사용합니다.
  • Swift: 메서드 내에서 인스턴스를 참조할 때 self를 사용합니다.

this를 사용하는 언어

  • C#: 메서드 내에서 인스턴스를 참조할 때 this를 사용합니다.
  • Java: 메서드 내에서 인스턴스를 참조할 때 this를 사용합니다.
  • C++: 메서드 내에서 인스턴스를 참조할 때 this를 사용합니다.
  • JavaScript: 메서드 내에서 인스턴스를 참조할 때 this를 사용합니다.
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)")
    }
}

생성자함수를 위와같이 수정할 수 있다.

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)")
    }
}

매개변수의 종류나 개수가 다른 생성자 여러개

애플에서 제공하는 이미지 클래스이다 위와같이 여러 생성자를 오버로딩해서 제공하는 모습을 볼 수 있다.

상속

 

부모클래스와 자식클래스의 관계를 나타낸 클래스 다이어그램이다.

각 언어에서 상속을 사용하는 예제

C#

// 부모 클래스 정의
public class Animal
{
    public void Speak()
    {
        Console.WriteLine("Animal speaks");
    }
}

// 자식 클래스 정의
public class Dog : Animal
{
    public void Bark()
    {
        Console.WriteLine("Dog barks");
    }
}

// 사용 예제
Dog myDog = new Dog();
myDog.Speak(); // "Animal speaks"
myDog.Bark();  // "Dog barks"

Java

// 부모 클래스 정의
class Animal {
    void speak() {
        System.out.println("Animal speaks");
    }
}

// 자식 클래스 정의
class Dog extends Animal {
    void bark() {
        System.out.println("Dog barks");
    }
}

// 사용 예제
public class Main {
    public static void main(String[] args) {
        Dog myDog = new Dog();
        myDog.speak(); // "Animal speaks"
        myDog.bark();  // "Dog barks"
    }
}

C++

#include <iostream>
using namespace std;

// 부모 클래스 정의
class Animal {
public:
    void speak() {
        cout << "Animal speaks" << endl;
    }
};

// 자식 클래스 정의
class Dog : public Animal {
public:
    void bark() {
        cout << "Dog barks" << endl;
    }
};

// 사용 예제
int main() {
    Dog myDog;
    myDog.speak(); // "Animal speaks"
    myDog.bark();  // "Dog barks"
    return 0;
}

JavaScript

// 부모 클래스 정의
class Animal {
    speak() {
        console.log("Animal speaks");
    }
}

// 자식 클래스 정의
class Dog extends Animal {
    bark() {
        console.log("Dog barks");
    }
}

// 사용 예제
const myDog = new Dog();
myDog.speak(); // "Animal speaks"
myDog.bark();  // "Dog barks"

Python

# 부모 클래스 정의
class Animal:
    def speak(self):
        print("Animal speaks")

# 자식 클래스 정의
class Dog(Animal):
    def bark(self):
        print("Dog barks")

# 사용 예제
my_dog = Dog()
my_dog.speak()  # "Animal speaks"
my_dog.bark()   # "Dog barks"

Swift

// 부모 클래스 정의
class Animal {
    func speak() {
        print("Animal speaks")
    }
}

// 자식 클래스 정의
class Dog: Animal {
    func bark() {
        print("Dog barks")
    }
}

// 사용 예제
let myDog = Dog()
myDog.speak() // "Animal speaks"
myDog.bark()  // "Dog barks"
 class 자식:부모 {
}

의 형태로 상속을 받으며 상속은 클래스만 가능하다 (구조체는 상속불가능) 상속하는 부모 클래스는 하나씩만 올 수 있고 없다면 프로토콜이 올 수 있다.

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 {
    
}
var lee : Student = Student(age: 21, weight: 21312)
lee.display()
var kim : Man = Man.init(age : 10, weight : 187.12)
kim.display()

super()는 부모 생성자를 호출하는 메서드이다.

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 {
    var name : String
    init (age : Int , weight : Double , name : String){
        self.name = name
        super.init(age: age, weight: weight)
    }
    func displayS(){
        print("이름\(name) 나이\(age) 몸무게\(weight)")
    }
}
var lee : Student = Student(age : 123,weight: 21, name: "foo")
lee.displayS()
var kim : Man = Man.init(age : 10, weight : 187.12)
kim.display()

오버라이딩

override 키워드를 func 앞에 붙이면 된다.

    override func display(){
        print("이름\(name) 나이\(age) 몸무게\(weight)")
    }

자식 클래스에서 오버라이드된 메소드는 우선적으로 호출된다.

// Man 클래스 정의
class Man {
    // 속성: 나이와 몸무게를 저장하는 변수
    var age: Int = 1      // 기본 나이는 1
    var weight: Double = 3.5 // 기본 몸무게는 3.5
    
    // 초기화 메서드: 객체 생성 시 호출됨
    init(age: Int, weight: Double) {
        self.age = age          // 전달받은 나이로 초기화
        self.weight = weight    // 전달받은 몸무게로 초기화
    }
    
    // 메서드: 나이와 몸무게를 출력
    func display() {
        print("나이 \(age) 몸무게 \(weight)")
    }
}

// Student 클래스 정의 (Man 클래스를 상속)
class Student: Man {
    // 속성: 학생의 이름을 저장하는 변수
    var name: String
    
    // 초기화 메서드: Student 객체를 생성할 때 호출됨
    init(age: Int, weight: Double, name: String) {
        self.name = name                      // 전달받은 이름으로 초기화
        super.init(age: age, weight: weight) // 부모 클래스의 초기화 메서드 호출
    }
    
    // 메서드 오버라이딩: 부모 클래스의 display() 메서드 수정
    override func display() {
        print("이름 \(name) 나이 \(age) 몸무게 \(weight)") // 학생 정보 출력
    }
}

// Student 클래스의 인스턴스 생성
var lee: Student = Student(age: 123, weight: 21, name: "foo")
lee.display() // "이름 foo 나이 123 몸무게 21" 출력

// Man 클래스의 인스턴스 생성
var kim: Man = Man.init(age: 10, weight: 187.12)
kim.display() // "나이 10 몸무게 187.12" 출력

전체 코드

failable initializers

init?(named name: String)

이는 옵셔널 인스턴스가 만들어지므로 언래핑을 해야한다 이는 오류 상황에 nil을 리턴한다

class Man{
    var age : Int
    var weight : Double
    func display(){
        print("나이=\(age), 몸무게=\(weight)")
    }
    init?(age: Int, weight : Double){
        if age <= 0 {
            return nil
        }
        self.age = age
        self.weight = weight
    } // failable initializer
}
var kim : Man = Man(age:10, weight:20.5)!
kim.display()
var lee : Man = Man(age:0, weight:3.5)! 
lee.display()

하지만 여기서 lee 의 생성자로 age:0  이 전달되는데 nil을 강제 언래핑하면 에러가 나게 된다

옵셔널을 푸는 4가지 방법 예시

var kim : Man? = Man(age:1, weight:3.5)
//1-1.옵셔널 형으로 선언
if let kim1 = kim { //1-2.옵셔널 바인딩
kim1.display()
}
//2.인스턴스 생성과 동시에 옵셔널 바인딩
if let kim2 = Man(age:2, weight:5.5) {
kim2.display()
}
//3.인스턴스 생성하면서 바로 강제 언래핑
var kim3 : Man = Man(age:3, weight:7.5)!
kim3.display()
//4.옵셔널 인스턴스를 사용시 강제 언래핑
var kim4 : Man? = Man(age:4, weight:10.5)
kim4!.display()
var lee : Man? = Man(age:0, weight:3.5)
if let lee {
    lee.display()
}

실제 예시를 보면 !를 사용해 강제 언래핑을 하는것보다 훨씬 안전하게 옵셔널 언래핑을 할 수 있다.

if let lee = Man(age:0, weight:3.5){
    lee.display()
}

보다 더 단축해서 사용할 수 있는 방법이다.

// Man 클래스 정의
class Man {
    var age: Int     // 나이를 저장하는 속성
    var weight: Double // 몸무게를 저장하는 속성
    
    // 객체의 나이와 몸무게를 출력하는 메서드
    func display() {
        print("나이=\(age), 몸무게=\(weight)")
    }
    
    // 실패 가능 생성자 (Failable Initializer)
    // 나이와 몸무게가 0 이하일 경우 객체 생성을 실패하여 nil을 반환함
    init?(age: Int, weight: Double) {
        if age <= 0 || weight <= 0.0 { // 나이나 몸무게가 0 이하라면
            return nil // 객체 생성 실패 (nil 반환)
        }
        self.age = age // 정상적인 경우, 속성 초기화
        self.weight = weight
    }
}

// 강제 언래핑(Forced Unwrapping)을 사용한 인스턴스 생성
// Man 객체를 생성할 때 age가 10, weight가 20.5인 경우 생성 성공
var kim: Man = Man(age: 10, weight: 20.5)!
// 옵셔널 타입에서 강제 언래핑(!)을 사용했기 때문에, nil이 아닌 경우에만 동작
// 생성된 객체가 nil이 아니므로 kim.display() 호출 가능
kim.display()

// 옵셔널 바인딩을 사용한 인스턴스 생성
// Man 객체를 생성할 때 age가 20, weight가 -2.2인 경우 생성 실패 (weight가 0 이하이므로 nil 반환)
if let lee = Man(age: 20, weight: -2.2) {
    // lee가 nil이 아닐 경우, 객체가 정상적으로 생성되었으므로 display() 호출 가능
    lee.display()
} else {
    // 객체 생성 실패 시 실행되는 블록 (생성 실패, lee는 nil)
    // 이 부분에서는 아무런 처리를 하지 않음
}

출저: 스마일한의 스위프트 기초

'iOS앱개발' 카테고리의 다른 글

iOS앱개발 8주차  (3) 2024.10.31
iOS 앱개발 7주차  (1) 2024.10.17
iOS 앱개발 5주차  (0) 2024.10.06
iOS 앱개발 4주차  (1) 2024.09.26
iOS 앱개발 3주차  (1) 2024.09.19