iOS 프로그래밍 6주차

2024. 10. 16. 16:47📱 모바일 프로그래밍/iOS 프로그래밍 기초

클래스(class)

 

클래스 vs. 객체 vs. 인스턴스

 

객체지향 용어 비교

 

 

클래스 vs. 인스턴스(객체)

각 언어별 클래스 생성 및 객체 생성

1. Swift

// 클래스 정의
class Car {
    var brand: String
    var year: Int
    
    // 생성자 (Initializer)
    init(brand: String, year: Int) {
        self.brand = brand
        self.year = year
    }
    
    // 메서드
    func drive() {
        print("\(brand) 자동차가 운전 중입니다.")
    }
}

// 객체 생성
let myCar = Car(brand: "Tesla", year: 2020)
myCar.drive() // 출력: Tesla 자동차가 운전 중입니다.

2. Java

// 클래스 정의
public class Car {
    private String brand;
    private int year;
    
    // 생성자
    public Car(String brand, int year) {
        this.brand = brand;
        this.year = year;
    }
    
    // 메서드
    public void drive() {
        System.out.println(brand + " 자동차가 운전 중입니다.");
    }
    
    // Getter와 Setter (옵션)
    public String getBrand() {
        return brand;
    }
    
    public int getYear() {
        return year;
    }
}

// 객체 생성
public class Main {
    public static void main(String[] args) {
        Car myCar = new Car("Hyundai", 2021);
        myCar.drive(); // 출력: Hyundai 자동차가 운전 중입니다.
    }
}

3. C#

// 클래스 정의
public class Car {
    public string Brand { get; set; }
    public int Year { get; set; }
    
    // 생성자
    public Car(string brand, int year) {
        Brand = brand;
        Year = year;
    }
    
    // 메서드
    public void Drive() {
        Console.WriteLine($"{Brand} 자동차가 운전 중입니다.");
    }
}

// 객체 생성
class Program {
    static void Main(string[] args) {
        Car myCar = new Car("BMW", 2019);
        myCar.Drive(); // 출력: BMW 자동차가 운전 중입니다.
    }
}

4. JavaScript

// 클래스 정의
class Car {
    constructor(brand, year) {
        this.brand = brand;
        this.year = year;
    }
    
    // 메서드
    drive() {
        console.log(`${this.brand} 자동차가 운전 중입니다.`);
    }
}

// 객체 생성
const myCar = new Car("Audi", 2022);
myCar.drive(); // 출력: Audi 자동차가 운전 중입니다.

5. Python

# 클래스 정의
class Car:
    def __init__(self, brand, year):
        self.brand = brand
        self.year = year
    
    # 메서드
    def drive(self):
        print(f"{self.brand} 자동차가 운전 중입니다.")

# 객체 생성
my_car = Car("Toyota", 2023)
my_car.drive() # 출력: Toyota 자동차가 운전 중입니다.

 

각 언어별 상속을 구현하는 방법

1. Swift

// 기본 클래스
class Car {
    var brand: String
    var year: Int
    
    init(brand: String, year: Int) {
        self.brand = brand
        self.year = year
    }
    
    func drive() {
        print("\(brand) 자동차가 운전 중입니다.")
    }
}

// 서브 클래스
class ElectricCar: Car {
    var batteryLife: Int
    
    init(brand: String, year: Int, batteryLife: Int) {
        self.batteryLife = batteryLife
        super.init(brand: brand, year: year) // 부모 클래스의 생성자 호출
    }
    
    func charge() {
        print("\(brand) 전기차가 충전 중입니다. 배터리 수명: \(batteryLife)%")
    }
}

// 객체 생성 및 사용
let myElectricCar = ElectricCar(brand: "Tesla", year: 2023, batteryLife: 90)
myElectricCar.drive()  // 출력: Tesla 자동차가 운전 중입니다.
myElectricCar.charge() // 출력: Tesla 전기차가 충전 중입니다. 배터리 수명: 90%

2. Java

// 기본 클래스
public class Car {
    protected String brand;
    protected int year;
    
    public Car(String brand, int year) {
        this.brand = brand;
        this.year = year;
    }
    
    public void drive() {
        System.out.println(brand + " 자동차가 운전 중입니다.");
    }
}

// 서브 클래스
public class ElectricCar extends Car {
    private int batteryLife;
    
    public ElectricCar(String brand, int year, int batteryLife) {
        super(brand, year); // 부모 클래스의 생성자 호출
        this.batteryLife = batteryLife;
    }
    
    public void charge() {
        System.out.println(brand + " 전기차가 충전 중입니다. 배터리 수명: " + batteryLife + "%");
    }
}

// 객체 생성 및 사용
public class Main {
    public static void main(String[] args) {
        ElectricCar myElectricCar = new ElectricCar("Hyundai", 2024, 80);
        myElectricCar.drive();  // 출력: Hyundai 자동차가 운전 중입니다.
        myElectricCar.charge(); // 출력: Hyundai 전기차가 충전 중입니다. 배터리 수명: 80%
    }
}

3. C#

// 기본 클래스
public class Car {
    public string Brand { get; set; }
    public int Year { get; set; }
    
    public Car(string brand, int year) {
        Brand = brand;
        Year = year;
    }
    
    public void Drive() {
        Console.WriteLine($"{Brand} 자동차가 운전 중입니다.");
    }
}

// 서브 클래스
public class ElectricCar : Car {
    public int BatteryLife { get; set; }
    
    public ElectricCar(string brand, int year, int batteryLife) : base(brand, year) { // 부모 클래스 생성자 호출
        BatteryLife = batteryLife;
    }
    
    public void Charge() {
        Console.WriteLine($"{Brand} 전기차가 충전 중입니다. 배터리 수명: {BatteryLife}%");
    }
}

// 객체 생성 및 사용
class Program {
    static void Main(string[] args) {
        ElectricCar myElectricCar = new ElectricCar("BMW", 2023, 70);
        myElectricCar.Drive();  // 출력: BMW 자동차가 운전 중입니다.
        myElectricCar.Charge(); // 출력: BMW 전기차가 충전 중입니다. 배터리 수명: 70%
    }
}

4. JavaScript

// 기본 클래스
class Car {
    constructor(brand, year) {
        this.brand = brand;
        this.year = year;
    }
    
    drive() {
        console.log(`${this.brand} 자동차가 운전 중입니다.`);
    }
}

// 서브 클래스
class ElectricCar extends Car {
    constructor(brand, year, batteryLife) {
        super(brand, year); // 부모 클래스 생성자 호출
        this.batteryLife = batteryLife;
    }
    
    charge() {
        console.log(`${this.brand} 전기차가 충전 중입니다. 배터리 수명: ${this.batteryLife}%`);
    }
}

// 객체 생성 및 사용
const myElectricCar = new ElectricCar("Audi", 2025, 85);
myElectricCar.drive();  // 출력: Audi 자동차가 운전 중입니다.
myElectricCar.charge(); // 출력: Audi 전기차가 충전 중입니다. 배터리 수명: 85%

5. Python

# 기본 클래스
class Car:
    def __init__(self, brand, year):
        self.brand = brand
        self.year = year
    
    def drive(self):
        print(f"{self.brand} 자동차가 운전 중입니다.")

# 서브 클래스
class ElectricCar(Car):
    def __init__(self, brand, year, battery_life):
        super().__init__(brand, year)  # 부모 클래스의 생성자 호출
        self.battery_life = battery_life
    
    def charge(self):
        print(f"{self.brand} 전기차가 충전 중입니다. 배터리 수명: {self.battery_life}%")

# 객체 생성 및 사용
my_electric_car = ElectricCar("Tesla", 2026, 95)
my_electric_car.drive()  # 출력: Tesla 자동차가 운전 중입니다.
my_electric_car.charge() # 출력: Tesla 전기차가 충전 중입니다. 배터리 수명: 95%

 

Swift 클래스 선언하기

 

클래스에 저장 프로퍼티(stored property) 추가하기

클래스 안에 있는 저장 프로퍼티는 반드시 초기값이 있어야 한다.

 

class Man {
    var age : Int = 0
    var weight : Double = 0.0
}

1. 초기값 직접 주기

class Man {
    var age : Int?
    var weight : Double?
}

2. optional 변수로 선언하기, 자동으로 nil로 초기화 함

 

프로퍼티는 초기값이 있거나 옵셔널 변수(상수)로 선언

 

인스턴스 만들고 메서드와 프로퍼티 접근

class Man {
    var age : Int = 0
    var weight : Double = 0.0
    func display() {
        print(age, weight)
    }
}

var x : Int
// 클래스명 다음의 괄호는 눈에 보이지 않는 default initializer를 나타낸다
var sung : Man = Man()  // :Man 생략 가능 
sung.age = 10
class Man {
    var age : Int = 0
    var weight : Double = 0.0
    func display() {
        print("나이: \(age), 몸무게: \(weight)")
    }
}

var x : Int
var sung : Man = Man()
print(sung.age) // 0
sung.age = 10
sung.weight = 20.5
print(sung.age, sung.weight)    // 10 20.5
sung.display()  // 나이: 10, 몸무게: 20.5

 

 

클래스(class or type) 메서드

class Man {
    var age : Int = 0
    var weight : Double = 0.0
    func display() {
        print("나이: \(age), 몸무게: \(weight)")
    }
    class func cM(){
        print("cM은 클래스 메서드입니다.")
    }
    static func scM(){
        print("scM은 클래스 메서드(static)")
    }
}

var x : Int
var sung : Man = Man()
Man.cM()    // 클래스 메서드는 클래스가 호출
// cM은 클래스 메서드입니다.
Man.scM()   // 클래스 메서드는 클래스가 호출
// scM은 클래스 메서드(static)

class 키워드로 만든 클래스 메서드는 자식 클래스에서 override 가능하다

 

인스턴스 초기화하기: Init()

class Man {
    var age : Int = 0
    var weight : Double = 0.0
    
    init(yourAge: Int, yourWeight : Double){
        age = yourAge
        weight = yourWeight
    } //designated initializer
    
    func display() {
        print("나이: \(age), 몸무게: \(weight)")
    }
}

// var sung : Man = Man()   // 오류
// init()을 하나라도 직접 만들면 default initializer는 사라짐
var sung : Man = Man(yourAge: 5, yourWeight: 10.3)
sung.display()

designated initializer:

   모든 프로퍼티(age, weight)를 다 초기화시키는 생성자

 

인스턴스 만들 때 클래스명 다음 괄호의 의미: init() 호출

class Man {
    var age : Int = 0
    var weight : Double = 0.0
    
    init(yourAge: Int, yourWeight : Double){
        age = yourAge
        weight = yourWeight
    } //designated initializer
    
    func display() {
        print("나이: \(age), 몸무게: \(weight)")
    }
}

var sung : Man = Man(yourAge: 5, yourWeight: 10.3) 
// init(yourAge: 5, yourWeight: 10.3) 호출
sung.display()
sung.age = 10
sung.weight = 20.5
sung.display()

 

self

class Man {
    var age : Int = 0
    var weight : Double = 0.0
    
    init(age: Int, weight : Double){
        self.age = age   //프로퍼티 = 매개변수
        self.weight = weight
    } //designated initializer
    
    func display() {
        print("나이: \(age), 몸무게: \(weight)")   
    }
}

var sung : Man = Man(age:10, weight:20.5)
sung.display()

 

this와 self

언어 키워드 사용 예 설명
JavaScript this this.brand 객체 메서드에서 현재 객체의 속성이나 메서드를 참조합니다.
Python self self.brand 메서드의 첫 번째 매개변수로 사용되며, 현재 인스턴스의 속성이나 메서드를 참조합니다.
Java this this.brand 생성자나 메서드 내부에서 현재 객체의 속성을 가리키고, 매개변수와 속성 간의 혼동을 피합니다.
C# this this.brand 클래스 내에서 현재 객체의 속성을 명확히 지정하고, 메서드 내부에서 해당 인스턴스를 참조합니다.
Swift self self.brand 메서드 내에서 현재 인스턴스를 참조하며, 주로 인스턴스 변수와 메서드를 명확하게 지정할 때 사용됩니다.

 

method overloading: 생성자 중첩

class Man {
    var age : Int = 0
    var weight : Double = 0.0
    
    init(age: Int, weight : Double){
        self.age = age
        self.weight = weight
    } //designated initializer
    
    init(age: Int){ // 2
        self.age = age
    }
    
    func display() {
        print("나이: \(age), 몸무게: \(weight)")
    }
}

var sung : Man = Man.init(age: 5, weight: 10.3)   // 1
var kim : Man = Man(age: 33)   // 2
sung.display()
kim.display()

매개변수의 개수와 자료형이 다른 같은 이름의 함수를 여러 개 정의

 

UIImage클래스의 init()함수 overloading

UIImage

1. UIImage(named:)

  • 용도: 앱 번들에 포함된 이미지를 로드할 때 가장 자주 사용됩니다.
  • 예시:
let image = UIImage(named: "exampleImageName")
  • 설명: 앱에 포함된 정적 이미지를 로드하는 데 매우 빈번하게 사용됩니다.

2. UIImageView(image:)

  • 용도: 이미지 뷰에 이미지를 표시할 때 사용됩니다.
  • 예시:
let imageView = UIImageView(image: UIImage(named: "exampleImageName"))
  • 설명: UIImageView를 초기화할 때 사용되며, 이미지를 화면에 표시하기 위해 많이 사용됩니다.

3. UIImage(contentsOfFile:)

  • 용도: 앱 번들 외부의 이미지 파일을 로드할 때 사용됩니다.
  • 예시:
if let filePath = Bundle.main.path(forResource: "exampleImage", ofType: "png") {
    let image = UIImage(contentsOfFile: filePath)
}
  • 설명: 파일 경로를 통해 이미지를 불러올 때 사용되며, 일반적으로 로컬 저장소에서 이미지를 로드할 때 사용됩니다.

4. UIImage(systemName:)

  • 용도: iOS 13 이상에서 제공하는 SF Symbols 아이콘을 로드할 때 사용됩니다.
  • 예시:
let icon = UIImage(systemName: "heart.fill")
  • 설명: 시스템 제공 아이콘을 사용할 때 사용되며, 최근 iOS에서 자주 사용됩니다.

5. UIImage(data:)

  • 용도: 이미지 데이터로부터 이미지를 생성할 때 사용됩니다. 예를 들어, 네트워크에서 이미지를 다운로드한 후 사용됩니다.
  • 예시:
if let imageData = try? Data(contentsOf: url) {
    let image = UIImage(data: imageData)
}
  • 설명: 원격 서버에서 이미지를 받아올 때나 데이터를 이미지로 변환할 때 사용됩니다.

6. UIImage.resizableImage(withCapInsets:)

  • 용도: 이미지가 늘어나도 품질이 유지되도록 일부 영역만 늘어나게 설정할 때 사용됩니다.
  • 예시:
let resizableImage = image.resizableImage(withCapInsets: UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10))
  • 설명: 특히 버튼 배경 등에 자주 사용되며, 이미지의 특정 영역이 반복되어도 깨지지 않도록 조정할 수 있습니다.

7. UIImageRenderingMode

  • 용도: 이미지를 템플릿 또는 원본 모드로 렌더링할 때 사용됩니다.
  • 예시:
let templateImage = image.withRenderingMode(.alwaysTemplate)
  • 설명: 템플릿 모드를 사용하여 아이콘에 다양한 색상을 적용할 수 있습니다.

8. UIImage(cgImage:)

  • 용도: CGImage 객체를 사용하여 이미지를 생성할 때 사용됩니다.
  • 예시:
let cgImage = image.cgImage
let newImage = UIImage(cgImage: cgImage!)
  • 설명: Core Graphics 이미지 객체를 UIImage로 변환할 때 사용되며, 이미지 처리 시 유용합니다.

9. UIImage.scaleAspectFit / scaleAspectFill

  • 용도: 이미지 뷰의 콘텐츠 모드를 설정하여 이미지의 비율을 유지하며 화면에 맞게 조정할 때 사용됩니다.
  • 예시:
imageView.contentMode = .scaleAspectFit
  • 설명: 이미지가 비율을 유지하면서 화면에 맞게 표시되도록 조정할 때 사용됩니다.

 

 

클래스(class) 상속

 

superclass와 subclass

 

스위프트 상속

 

suepr: 부모 메서드 호출 시 사용

class Man {
    var age : Int = 0
    var weight : Double = 0.0
    
    init(age: Int, weight : Double){
        self.age = age
        self.weight = weight
    } //designated initializer
    
    func display() {
        print("나이: \(age), 몸무게: \(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) //과제: 이 줄을 안쓰면?
      }//error:'super.init' isn't called on all paths before returning from initializer
}

var lee : Student = Student(age: 25, weight: 77.7, name: "soft")
lee.display()
lee.displayS()

 

override: 부모와 자식에 같은 메서드가 있으면 자식 우선

class Man {
    var age : Int = 0
    var weight : Double = 0.0
    
    init(age: Int, weight : Double){
        self.age = age
        self.weight = weight
    } //designated initializer
    
    func display() {
        print("나이: \(age), 몸무게: \(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) //과제: 이 줄을 안쓰면?
      }//error:'super.init' isn't called on all paths before returning from initializer
}

var lee : Student = Student(age: 25, weight: 77.7, name: "soft")
lee.display()
  • 부모와 자식에 display()라는 메서드가 있어서 Student클래스는 display() 메서드가 두 개임 
  • Student클래스의 인스턴스 lee가 display()를 호출할 때, 자식클래스가 새로 만든 display() 메서드가 우선적으로 호출되려면 func 앞에 override키워드 씀

 

failable initializers(실패 가능한 생성자: init?)

 

failable initializer(실패 가능한 생성자: init? init!)

init다음에 “?”나 “!” 하며 옵셔널 값이 리턴됨

오류 상황에 nil을 리턴하는 조건문이 있음

  •    return nil

init?

init!

 

failable initializer 만드는 방법

1. ? 붙이기

class Man {
    var age : Int = 0
    var weight : Double = 0.0
    
    init?(age: Int, weight : Double){
        self.age = age
        self.weight = weight
    } //designated initializer
    
    func display() {
        print("나이: \(age), 몸무게: \(weight)")
    }
}

 if문 추가

class Man {
    var age : Int = 0
    var weight : Double = 0.0
    
    init?(age: Int, weight : Double){
        if age <= 0 || weight <= 0.0 {
            return nil
        } else {
            self.age = age
            self.weight = weight
        }
    } //designated initializer
    
    func display() {
        print("나이: \(age), 몸무게: \(weight)")
    }
}

 

2. 선언할 때 optional 형으로 선언해야 한다

var sung : Man? = Man(age: 5, weight: 10.3)

 

failable initialize가 있는 클래스의 인스턴스 생성

var kim : Man? = Man(age:1, weight:3.5)
// 1-1. 옵셔널 형식으로 Man 객체 생성: 'Man?' 타입으로 옵셔널 선언. 객체가 있을 수도, 없을 수도 있다.

if let kim1 = kim { //1-2. 옵셔널 바인딩
    kim1.display()
}
// 1-2. 옵셔널 바인딩: 'if let' 구문을 사용하여 옵셔널이 nil이 아닌 경우 안전하게 unwrapping 함.
// 'kim' 객체가 nil이 아닌 경우 'kim1'에 할당되고, 'display()' 메서드 호출 가능.

if let kim2 = Man(age:2, weight:5.5) {
    kim2.display()
}
// 2. 인스턴스 생성과 동시에 옵셔널 바인딩: 객체를 생성하며 바로 옵셔널 바인딩.
// 'if let'을 통해 객체 생성과 동시에 unwrapping, nil이 아니면 'display()' 메서드 호출.

var kim3 : Man = Man(age:3, weight:7.5)!
// 3. 인스턴스 생성하면서 바로 강제 언래핑: 객체 생성 시 '!'로 강제 언래핑을 통해 바로 unwrapping.
// 옵셔널 형식이 아닌 'Man' 타입으로 선언했기 때문에 nil이 아님을 확신하는 경우에 사용.

kim3.display()
// 'kim3'는 강제 언래핑으로 옵셔널이 아니므로 바로 'display()' 메서드 호출 가능.

var kim4 : Man? = Man(age:4, weight:10.5)
// 4. 옵셔널 인스턴스 생성: 'Man?' 타입으로 옵셔널 객체 생성, nil이 될 수 있는 경우에 사용.

kim4!.display()
// 4. 옵셔널 인스턴스를 사용시 강제 언래핑: 'kim4!'로 강제 언래핑 후 'display()' 메서드 호출.
// 옵셔널 값이 nil이 아닐 것을 확신할 때만 사용해야 안전하다. 그렇지 않으면 런타임 에러 발생.

 

class Man {
    var age : Int = 0
    var weight : Double = 0.0
    
    init?(age: Int, weight : Double){
        if age <= 0 || weight <= 0.0 {
            return nil
        } else {
            self.age = age
            self.weight = weight
        }
    } //designated initializer
    
    func display() {
        print("나이: \(age), 몸무게: \(weight)")
    }
}

var sung : Man? = Man(age: 0, weight: 10.3)   
if let sung = sung {
    sung.display()
}

가장 좋은 방법

 

정리

// 기본 클래스 Person 정의
class Person {
    var name: String
    var age: Int
    
    // 기본 생성자
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    
    // 메서드: 기본 정보 출력
    func displayInfo() {
        print("Name: \(name), Age: \(age)")
    }
}

// Person을 상속받은 Employee 클래스 정의
class Employee: Person {
    var employeeID: String
    
    // failable initializer: 조건에 맞지 않으면 nil 반환
    init?(name: String, age: Int, employeeID: String) {
        // 나이가 18세 이상이어야만 Employee 객체 생성 가능
        if age < 18 {
            return nil // 조건에 맞지 않으면 nil 반환
        }
        self.employeeID = employeeID
        super.init(name: name, age: age) // 상위 클래스의 init 호출
    }
    
    // 메서드 오버라이딩: Employee 정보 출력
    override func displayInfo() {
        super.displayInfo() // 상위 클래스의 메서드 호출
        print("Employee ID: \(employeeID)")
    }
}

// Person 인스턴스 생성 및 사용
let person = Person(name: "Alice", age: 30)
person.displayInfo()
// 출력:
// Name: Alice, Age: 30

// 조건을 만족하는 Employee 인스턴스 생성
if let employee = Employee(name: "Bob", age: 25, employeeID: "E123") {
    employee.displayInfo()
    // 출력:
    // Name: Bob, Age: 25
    // Employee ID: E123
} else {
    print("Failed to create employee.")
}

// 조건을 만족하지 않는 경우(nil 반환)
if let employee = Employee(name: "Charlie", age: 16, employeeID: "E124") {
    employee.displayInfo()
} else {
    print("Failed to create employee.")
    // 출력: Failed to create employee.
}

 

출처: iOS 프로그래밍 기초 강의 자료

'📱 모바일 프로그래밍 > iOS 프로그래밍 기초' 카테고리의 다른 글

iOS 프로그래밍 10주차  (1) 2024.11.06
iOS 프로그래밍 9주차  (0) 2024.10.30
iOS 프로그래밍 5주차  (0) 2024.10.13
iOS 프로그래밍 4주차  (0) 2024.10.07
iOS 프로그래밍 3주차  (0) 2024.09.25