iOS실무 4주차

CDH·2025년 3월 26일

Xcode 실습

처음 project를 만들면 나오는 swift의 세 가지 파일 + ai 질문

ai 질문 : 위 소스를 주석으로 설명해줘

AppDelegate

import UIKit  // UIKit 프레임워크를 가져옴. iOS 앱 개발에 필요한 UI 구성 요소와 도구를 제공.

// @main 속성은 이 클래스가 앱의 진입점(entry point)임을 나타냄.
@main
class AppDelegate: UIResponder, UIApplicationDelegate {  // AppDelegate 클래스 정의. UIResponder를 상속받아 사용자 입력에 응답하고, UIApplicationDelegate 프로토콜을 준수해 앱 생명주기를 관리.

    // 앱이 실행을 완료한 후 호출되는 메서드. 앱 초기화 후 사용자 정의 작업을 추가할 수 있는 지점.
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // launchOptions: 앱이 실행된 이유(예: 알림, URL 등)에 대한 정보가 포함될 수 있음.
        // 여기서 앱 실행 후 초기 설정(예: 데이터 로드, UI 설정 등)을 커스터마이징 가능.
        return true  // 초기화가 성공했음을 나타냄.
    }

    // MARK: UISceneSession Lifecycle - 코드 가독성을 위해 섹션을 구분하는 주석.

    // 새로운 장면(scene)이 생성될 때 호출됨. iOS 13 이상에서 멀티 윈도우 지원을 위해 사용.
    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // connectingSceneSession: 연결하려는 장면 세션에 대한 정보.
        // options: 장면이 생성되는 상황에 대한 추가 정보.
        // 이 메서드는 새 장면의 설정을 정의하며, 기본 설정을 반환.
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)  // "Default Configuration"이라는 이름의 설정을 반환.
    }

    // 사용자가 장면 세션을 삭제했을 때 호출됨. 더 이상 필요 없는 리소스를 정리하는 데 사용.
    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // sceneSessions: 삭제된 장면 세션들의 집합.
        // 앱이 실행 중이 아닌 상태에서 세션이 삭제되었다면, 앱 시작 직후 이 메서드가 호출됨.
        // 삭제된 장면과 관련된 리소스를 해제하거나 정리하는 코드를 여기에 추가 가능.
    }
}

SceneDelegate

import UIKit  // UIKit 프레임워크를 가져옴. UI 관련 기능과 장면 관리에 필요.

class SceneDelegate: UIResponder, UIWindowSceneDelegate {  // SceneDelegate 클래스 정의. UIResponder를 상속받고, UIWindowSceneDelegate 프로토콜을 준수해 장면 생명주기를 관리.

    var window: UIWindow?  // 앱의 주요 창(window)을 나타내는 변수. 장면과 연결될 수 있는 UIWindow 객체를 저장.

    // 새로운 장면이 세션에 연결될 때 호출됨. 창(window)과 장면(scene)을 설정하거나 초기화하는 데 사용.
    func scene(_ scene: UIS siltcene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // scene: 연결하려는 장면 객체.
        // session: 장면이 속한 세션 정보.
        // connectionOptions: 장면 연결에 대한 추가 정보(예: URL로 열림 등).
        // 스토리보드를 사용하면 window 속성이 자동으로 초기화되고 장면에 연결됨.
        // 이 메서드는 새 장면/세션이 반드시 새로 생성된 것임을 의미하지 않음(재사용 가능성 있음).
        guard let _ = (scene as? UIWindowScene) else { return }  // scene이 UIWindowScene 타입인지 확인. 아니면 메서드 종료.
        // 여기서 window를 설정하거나 초기 UI를 구성할 수 있음.
    }

    // 장면이 시스템에 의해 해제될 때 호출됨.
    func sceneDidDisconnect(_ scene: UIScene) {
        // 장면이 백그라운드로 전환된 직후 또는 세션이 삭제될 때 발생.
        // 다음 연결 시 재생성 가능한 리소스를 해제.
        // 세션이 삭제되지 않았다면 나중에 다시 연결될 수 있음(참고: `application:didDiscardSceneSessions`).
    }

    // 장면이 비활성 상태에서 활성 상태로 전환될 때 호출됨.
    func sceneDidBecomeActive(_ scene: UIScene) {
        // 장면이 사용자와 상호작용할 수 있는 상태가 되었음을 의미.
        // 비활성 상태에서 중단되었거나 시작되지 않은 작업(예: 타이머, 애니메이션)을 재개 가능.
    }

    // 장면이 활성 상태에서 비활성 상태로 전환될 때 호출됨.
    func sceneWillResignActive(_ scene: UIScene) {
        // 일시적인 중단(예: 전화가 오는 경우)으로 인해 장면이 비활성 상태로 바뀜.
        // 현재 진행 중인 작업을 일시 중지하거나 준비할 수 있음.
    }

    // 장면이 백그라운드에서 포어그라운드로 전환될 때 호출됨.
    func sceneWillEnterForeground(_ scene: UIScene) {
        // 앱이 다시 사용자에게 보이기 직전 호출.
        // 백그라운드 상태에서 변경된 내용을 되돌리거나 UI를 업데이트 가능.
    }

    // 장면이 포어그라운드에서 백그라운드로 전환될 때 호출됨.
    func sceneDidEnterBackground(_ scene: UIScene) {
        // 장면이 사용자에게 보이지 않는 상태로 전환됨.
        // 데이터를 저장하거나, 공유 리소스를 해제하고, 현재 상태를 복원할 수 있을 만큼의 정보를 저장해야 함.
    }
}

ViewController

import UIKit  // UIKit 프레임워크를 가져옴. UI 요소와 뷰 컨트롤러 관리에 필요한 도구 제공.
class ViewController: UIViewController {  // ViewController 클래스 정의. UIViewController를 상속받아 기본적인 뷰 관리 기능 제공.
    // 뷰가 메모리에 로드된 직후 호출되는 메서드. 뷰의 초기 설정을 수행하는 데 사용.
    override func viewDidLoad() {
        super.viewDidLoad()  // 부모 클래스(UIViewController)의 viewDidLoad 메서드를 호출하여 기본 설정을 수행.
        // 뷰가 로드된 후 추가적인 설정 작업(예: UI 구성, 데이터 로드 등)을 이곳에 추가 가능.
    }
}

swift의 함수에서 _(언더스코어)가 의미하는 것

  • Swift에서 _ (밑줄, underscore)는 메서드 정의나 호출에서 파라미터 이름을 생략하거나 무시할 때 사용하는 특별한 표기

parameter(매개변수) 와 argument(전달인자)

- 함수 정의부의 값을 매개변수
- 호출시의 값은 아규먼트라고 부름 (함수 내부)


메서드(method)


Playground 실습

import UIKit 

func sayHello() -> Void { // 함수 정의
    // 리턴 값이 없는 경우에는 "-> Void " 생략 가능하다
    print("Hello")
}

sayHello() // 함수 호출

func add(x:Int, y:Int) -> Int {
    return x + y
}
print(add(x: 10, y: 20)) // 30 출력

var x = 10
print(type(of: x)) // Int 출력
print(type(of: add)) // (Int, Int) -> Int
// 함수의 자료형은 (매개변수, 매개변수) -> 리턴형 으로 이루어져 있다.

함수의 자료형은 (매개변수, 매개변수) -> 리턴형 으로 이루어져 있다.


중요! 외부 매개변수와 내부 매개변수

func add(xx x:Int, yy y:Int) -> Int {
    // xx: argument label(외부 매개변수) , x: parameter name(내부 매개변수)
    return x + y // xx, yy 불가 (Error: Cannot find 'xx' in scope)
}
print(add(xx: 10, yy: 20)) // 30 출력

외부 매개변수명은 생략 가능하다

외부 매개변수명을 생략하는 경우 내부 매개변수명과 같은 이름으로 사용한다


4가지 함수 모두 자료형은 (Int, Int) -> Int 로 모두 같다


함수명과 매개변수

func add(first x:Int, second y:Int) -> Int {
    // xx: argument label(외부 매개변수) , x: parameter name(내부 매개변수)
    print(#function)
    return x + y // xx, yy 불가 (Error: Cannot find 'xx' in scope)
}
print(add(first: 5, second: 10))

func add(x:Int, y:Int) -> Int {
    // xx: argument label(외부 매개변수) , x: parameter name(내부 매개변수)
    print(#function)
    return x + y // xx, yy 불가 (Error: Cannot find 'xx' in scope)
}
print(add(x: 10, y: 20)) // 외부 매개변수명을 생략하는 경우 내부 매개변수명과 같은 이름으로 사용한다

func add(_ x: Int, _ y: Int) -> Int {
    print(#function)
    return x + y
}
print(add(1, 2)) // 매개변수명 생략

func add(_ x: Int, with y: Int) -> Int { // 가장 많이 사용하는 방식
    print(#function) // 함수 명을 호출하려면 return 전에 구문을 넣어줘야 됨
    return x + y
}
print(add(5, with: 3)) // 출력할 때 첫 번째만 생략함

swift 에서 함수명을 출력할 땐 return 전에 print(#function) 으로 출력한다.

  • swift에서 함수명은 콤마 없이 "매개변수명:" (콜론사용) 으로 표기된다.
  • 함수명이 같아도 매개변수명이 다르면 모두 사용 가능하다 (함수 중첩)


함수명과 함수 자료형


Swift 클래스와 프로퍼티

property(프로퍼티)는 클래스 안에 있는 변수(상수)

1. 초기값이 있거나
2. init을 이용해서 초기화하거나
3. 옵셔널 변수(상수)로 선언(자동으로 nil로 초기화)
- 위 세 가지 중 하나의 조건을 충족해야 한다.


저장 프로퍼티(stored property) 에 초기값을 주는 3가지 방법


메서드 정의

class Man{
    var age : Int = 1
    var weight : Double = 3.5
    // init(){}  - 명시하지 않으면 생략되어 있는 코드
    func display(){ //인스턴스 메서드
        print("나이=\(age), 몸무게=\(weight)")
    }
}

var han : Man = Man() // : Man 생략 가능, Man.init() 이 생략되어 있는 코드
han.display() // 나이와 몸무게 출력

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

class Man{
    var age : Int
    var weight : Double
    func display(){
        print("나이=\(age), 몸무게=\(weight)")
    }
    init(age: Int, weight : Double){ // 함수를 출력할 때 init()에 있는 값으로 출력해야 함
        self.age = age
        self.weight = weight
    } //designated initializer
}

var han = Man(age: 20, weight: 35.5)
han.display() // init() 메서드에서 정의된 값이 최종적으로 나옴

designated initializer

  • Designated initializer는 클래스의 "주요 초기화 메서드"로, 모든 속성을 초기화하는 역할을 합니다.
  • 반드시 구현되어야 하며, 다른 초기화 메서드의 기반이 됩니다.
  • Swift의 초기화 규칙을 통해 안전하고 명확한 객체 생성을 보장합니다.

self


클래스(class) 상속

Swift 상속

class Man{
    var age : Int
    var weight : Double
    func display(){
        print("나이=\(age), 몸무게=\(weight)")
    }
    init(age: Int, weight : Double){ // 함수를 출력할 때 init()에 있는 값으로 출력해야 함
        self.age = age
        self.weight = weight
    } //designated initializer
}

class Student : Man {
    
}
var kim : Student = Student(age: 25, weight: 55.5)
print(kim.age)
kim.display()

var han = Man(age: 20, weight: 35.5)
han.display() // init() 메서드에서 정의된 값이 최종적으로 나옴

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

    self.name = name
    super.init(age:age, weight:weight) //이 줄을 안쓰면?

위 두 줄의 순서를 바꾸면 에러가 발생함


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

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() {
        // 부모 함수와 똑같은 이름의 함수를 만들고 싶다면 함수 선언 앞에 "override" 로 선언해줘야 함
        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
} //자식 클래스에서 designated initializer를 만들면 부모 init()상속 안됨
var lee : Student = Student(age:20,weight:65.2,name:"홍길동")

lee.display()

부모 함수와 똑같은 이름의 함수를 만들고 싶다면 함수 선언 앞에 "override" 로 선언해줘야 한다


delegate (p.49)

AI 답변: Delegate 패턴은 언어에 관계없이 객체 간의 결합도를 낮추고 역할을 분리하여 유지보수성과 확장성을 높이는 데 사용됩니다. Java에서는 인터페이스를, Swift에서는 프로토콜과 weak 참조를 활용해 구현됩니다.


protocol


에러 발생, 아래와 같이 수정해야 함



Fix 후 아래와 같이 변경

아래와 같이 수정 후 실행

  • Man 이라는 클래스가 Runnable이라는 프로토콜채택
  • var x 는 값을 초기화 해줘야 함
  • 함수 run() 은 conform준수

protocol 사용 이유 : 객체가 특정 기능을 강제적으로 구현하도록 보장하기 위해서
- 코드의 구조를 명확히 하고, 필요한 기능을 강제적으로 제공하게 함으로써 유지보수성과 확장성을 개선


AI 질문 : swift에서 상속과 프로토콜을 동시에 사용하는 아주 쉬운 예제를 만들고 설명해줘

// 1. 프로토콜 정의
protocol Speakable {
    func speak() -> String
}

// 2. 부모 클래스 정의
class Animal {
    var name: String
    
    init(name: String) {
        self.name = name
    }
}

// 3. 상속과 프로토콜을 함께 사용하는 자식 클래스
class Dog: Animal, Speakable {
    func speak() -> String {
        return "\(name)이(가) 멍멍 짖습니다!"
    }
}

// 4. 사용 예시
let myDog = Dog(name: "바둑이")
print(myDog.speak()) // 출력: "바둑이가 멍멍 짖습니다!"

0개의 댓글