이 포스트는 한성현 교수님의 iOS 프로그래밍 실무 수업을 듣고 작성하였습니다.
오늘은 간단한 문법에 들어가기 전에,
Xcode 내에서 App 파일을 만들었을 때 기본적으로 구성되어있는 코드를 한 번 살펴보겠습니다.
저는 Perplexity 에게 질문하여, 모든 코드에 주석을 달아 보게 하였습니다.
세 가지 파일 중 먼저 AppDeleate 파일입니다.
import UIKit
// AppDelegate 클래스는 앱의 생명주기를 관리하는 역할을 합니다.
// @main 속성은 이 클래스가 앱 실행의 진입점(entry point)임을 나타냅니다.
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
// 이 메서드는 앱이 실행된 직후 호출됩니다.
// launchOptions에는 앱이 실행된 이유와 관련된 정보가 포함될 수 있습니다.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 앱 실행 후 초기 설정을 할 수 있는 지점입니다.
// 예를 들어, 초기화 작업이나 로그 설정 등을 할 수 있습니다.
return true // true를 반환하면 앱이 정상적으로 실행됩니다.
}
// MARK: UISceneSession Lifecycle
// MARK는 코드의 가독성을 높이기 위해 사용됩니다. Xcode에서 자동으로 섹션 구분을 제공합니다.
// 새로운 Scene Session이 생성될 때 호출되는 메서드입니다.
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// UISceneConfiguration 객체를 반환하여 새 Scene을 설정합니다.
// Scene은 iOS 13 이상에서 멀티 윈도우를 지원하기 위해 도입된 개념입니다.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
// "Default Configuration"은 기본 Scene 설정 이름입니다.
// sessionRole은 Scene의 역할(예: WindowScene)을 나타냅니다.
}
// 사용자가 특정 Scene Session을 삭제했을 때 호출되는 메서드입니다.
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// 사용자가 앱 실행 중 또는 백그라운드 상태에서 Scene을 제거했을 때 호출됩니다.
// 여기서 제거된 Scene과 관련된 리소스를 해제하거나 정리할 수 있습니다.
// 예를 들어, 메모리 관리 작업 등을 수행할 수 있습니다.
}
}
이 파일 속에서 새 Scene 을 설정하는 함수 부분에 대해 자세히 알아 보겠습니다.
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
}
그 속에 _ 의 의미가 무엇인지 함께 물어 보았습니다.
언더 스코어는 사용 시에 외부 이름을 생략할 수 있으며, 외부 매개변수 이름을 생략하면 호출 시 간결하게 사용할 수 있기 때문이었습니다.
이는 코드 가독성을 높이는 데에 도움이 된다는 것이겠지요.
configurationForConnecting connectingSceneSession:
그리고 configuartionForConnecting 과 connectingSceneSession 을 두 가지 다 사용하는 이유는 무엇일까요?
그 이유는 Swift 의 함수 매개변수 선언 방식 때문입니다.
함수의 매개변수를 정의할 때 외부 이름과 내부 이름을 각각 지정할 수 있게 됩니다.
외부 이름은 전자(Parameter)에 있는 것으로 함수 호출 시 사용되며, 후자(Argument) 의 경우 함수 내부에서 사용되며 매개변수 참조 시에 사용됩니다.
이렇게 코드를 작성하게 된다면 가독성과 명확성이 제공됩니다.
간단하게 함수명을 알아 볼 수 있는 예제를 통해 함수명을 출력해 보겠습니다.
func add(first x: Int, second y: Int) -> Int {
print(#function) //add(first:second:)
return(x+y)
}
print(add(first:10, second:20))
이렇게 되면 함수명은 add(first: second:) 로 출력이 됩니다.
출력은 콤마 없이 출력되며, 있을 필요 없습니다.
즉, 함수의 개수는 콜론의 개수라고 생각하면 더 쉽게 이해가 가능합니다!
다시 원래 코드로 돌아가여,
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
}
위 코드의 함수명을 출력해 볼까요?
간단히 설명해 둔 것을 토대로 결과를 보면
application(_: configurationForConnecting: options:)
가 함수명이 됩니다!
두 번째는 SceneDelegate 입니다.
import UIKit
// SceneDelegate는 iOS 13 이상에서 도입된 멀티윈도우(Scene) 기능을 관리하는 클래스입니다.
// UIWindowSceneDelegate 프로토콜을 채택하여 Scene의 생명주기 이벤트를 처리합니다.
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
// 앱의 UI를 표시하는 메인 윈도우를 정의합니다.
var window: UIWindow?
// MARK: - Scene Lifecycle Methods
// Scene이 처음 연결될 때 호출되는 메서드입니다.
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// 이 메서드는 UIWindow를 UIWindowScene에 연결하거나 초기 설정을 수행하는 데 사용됩니다.
// 스토리보드를 사용하는 경우, window 속성이 자동으로 초기화되고 Scene에 연결됩니다.
guard let _ = (scene as? UIWindowScene) else { return }
// 위 코드는 scene이 UIWindowScene 타입으로 캐스팅 가능한지 확인하며, 그렇지 않으면 메서드를 종료합니다.
}
// Scene이 시스템에 의해 해제될 때 호출되는 메서드입니다.
func sceneDidDisconnect(_ scene: UIScene) {
// 이 메서드는 Scene이 백그라운드로 전환되거나 세션이 삭제될 때 호출됩니다.
// 여기서 해당 Scene과 관련된 리소스를 해제하거나 상태를 저장할 수 있습니다.
// 단, 세션이 완전히 삭제되지 않을 수도 있으므로 복구 가능한 상태를 유지해야 합니다.
}
// Scene이 활성화되었을 때 호출되는 메서드입니다.
func sceneDidBecomeActive(_ scene: UIScene) {
// 이 메서드는 Scene이 비활성 상태에서 활성 상태로 전환될 때 호출됩니다.
// 일시 중단된 작업을 재개하거나 타이머를 다시 시작해야 할 때 유용합니다.
}
// Scene이 비활성화되기 직전에 호출되는 메서드입니다.
func sceneWillResignActive(_ scene: UIScene) {
// 이 메서드는 Scene이 활성 상태에서 비활성 상태로 전환될 때 호출됩니다.
// 예를 들어, 전화가 오거나 다른 알림으로 인해 앱이 일시 중단될 경우 이 메서드가 호출됩니다.
// 작업을 일시 중단하거나 중요한 데이터를 저장할 수 있습니다.
}
// Scene이 백그라운드에서 포그라운드로 전환될 때 호출되는 메서드입니다.
func sceneWillEnterForeground(_ scene: UIScene) {
// 이 메서드는 앱이 백그라운드에서 다시 활성화되기 전에 호출됩니다.
// 백그라운드로 전환 시 적용했던 변경 사항을 되돌리거나 UI를 업데이트할 수 있습니다.
}
// Scene이 포그라운드에서 백그라운드로 전환될 때 호출되는 메서드입니다.
func sceneDidEnterBackground(_ scene: UIScene) {
// 이 메서드는 앱이 백그라운드 상태로 전환될 때 호출됩니다.
// 데이터를 저장하거나 공유 리소스를 해제하는 등 백그라운드 작업을 수행할 수 있습니다.
// 예를 들어, Core Data의 변경 사항을 저장하거나 사용자 데이터를 안전하게 저장하는 데 사용됩니다.
}
}
마지막으로 ViewController 입니다.
import UIKit
// ViewController 클래스는 화면(View) 하나를 관리하는 역할을 합니다.
// UIViewController를 상속받아 iOS 앱의 화면 생명주기를 관리합니다.
class ViewController: UIViewController {
// MARK: - UIViewController Lifecycle Methods
// viewDidLoad는 뷰 컨트롤러의 뷰가 메모리에 로드된 후 호출됩니다.
// 이 메서드는 앱 실행 시 한 번만 호출되며, 초기 설정을 수행하는 데 적합합니다.
override func viewDidLoad() {
위 코드를 간단하게 다루어 봤으니 Swift 문법에 대해서 알아 보겠습니다.
먼저, 클래스입니다.
사람이라는 클래스를 정의해 보며, 살펴 보겠습니다!
class Man {
var age : Int = 0 // 초기 값을 주지 않으면 에러
}
클래스 안에서의 변수는 프로퍼티라고 부르는데, 이는 초기 값을 지정해 주어야 합니다.
간단하게 = 0 을 적어 주며, 초기 값을 지정해 줄 수 있겠죠?
그렇다면 직접 지정해 주지 않고 초기 값을 지정하려면 어떠한 방법이 있을까요?
class Man {
var age : Int? // 초기 값이 nil
}
옵셔널 형태로 ? 를 통해 정의해 주면, 초기 값이 nil 로 초기 값이 있는 상태가 됩니다.
이를 stored property(저장 프로퍼티) 라고 부릅니다.
이제 윤이라는 사람을 생성해 준 뒤, 나이를 적어 보겠습니다.
class Man {
var age : Int = 0 // 초기 값을 주지 않으면 에러
}
var x : Int
var yoon : Man
yoon.age = 22
윤의 나이를 22 로 지정해 주었는데 에러가 발생합니다.
그 이유는 무엇일까요?
객체 초기화가 되지 않았기 때문입니다.
이는 이렇게 해결이 가능합니다.
class Man {
var age : Int = 0 // 초기 값을 주지 않으면 에러
}
var x : Int
var yoon : Man = Man()
yoon.age = 22
초기화를 시켜 주는 initalizer 에 대해 더욱 자세하게 알아 보겠습니다.
designated initializer 를 간단히 살펴 보겠습니다.
이는 Swift에서 클래스, 구조체, 또는 열거형의 인스턴스를 생성할 때 사용하는 초기화 메서드입니다.
제가 작성한 Man 클래스에 주석을 달아 설명해 보겠습니다.
// Man 클래스 정의
class Man {
// 저장 속성 정의: 나이 (정수형)
var age: Int
// 저장 속성 정의: 몸무게 (실수형)
var weight: Double
// display() 메서드 정의: 나이와 몸무게를 출력하는 기능을 제공
func display() {
// 나이와 몸무게를 출력
print("나이=\(age), 몸무게=\(weight)")
}
// Designated Initializer 정의
// 매개변수를 통해 age와 weight 값을 받아 저장 속성을 초기화
init(age: Int, weight: Double) {
self.age = age // 전달받은 age 값을 저장 속성 age에 할당
self.weight = weight // 전달받은 weight 값을 저장 속성 weight에 할당
}
}
// Man 클래스의 객체 생성 및 초기화
// 매개변수로 나이 22와 몸무게 30.5를 전달하여 초기화
var yoon = Man(age: 22, weight: 30.5)
// 생성된 객체의 display() 메서드를 호출하여 나이와 몸무게를 출력
yoon.display()
다음으로는 Delegation 입니다.
쉽게 이야기해서 도움을 받아서 처리를 해 주는 디자인 패턴입니다.
하나의 객체가 모든 일을 처리하는 것이 아니라 처리해야 할 일 중 일부를 다른 객체에 넘기는 것입니다.
위임된 기능은 프로토콜에서 정의하며, delegate가 위임된 기능을 제공합니다.
그렇다면 프로토콜에 대해 간단히 알아 보겠습니다.
프로토콜은 특정 클래스와 관련없는 함수(메서드)들의 선언 집합입니다.
protocol 프로토콜명{
프로퍼티명
메서드 선언 //메서드는 선언만 있음
}
protocol 프로토콜명 : 부모1프로토콜, 부모2프로토콜{
// 프로토콜은 다중 상속도 가능
}
이렇게 정의가 가능합니다.
쉬운 이해를 위해서, perplexity 에게 "swift 에서 상속과 프로토콜을 동시에 사용하는 아주 쉬운 예제를 만들고 설명해 줘" 라고 질문해 보았습니다.
// 기본 직원 클래스
class 직원 {
var 이름: String
init(이름: String) {
self.이름 = 이름
}
func 출근하기() {
print("\(이름)이(가) 출근했습니다.")
}
}
// 주문 처리 프로토콜
protocol 주문처리 {
func 주문받기()
func 음식준비하기()
}
// 서빙 프로토콜
protocol 서빙 {
func 음식서빙하기()
}
// 웨이터 클래스: 직원을 상속받고, 주문처리와 서빙 프로토콜을 채택
class 웨이터: 직원, 주문처리, 서빙 {
func 주문받기() {
print("\(이름) 웨이터가 주문을 받습니다.")
}
func 음식준비하기() {
print("\(이름) 웨이터가 주방에 주문을 전달합니다.")
}
func 음식서빙하기() {
print("\(이름) 웨이터가 음식을 서빙합니다.")
}
}
// 요리사 클래스: 직원을 상속받고, 주문처리 프로토콜을 채택
class 요리사: 직원, 주문처리 {
func 주문받기() {
print("\(이름) 요리사가 주문을 확인합니다.")
}
func 음식준비하기() {
print("\(이름) 요리사가 음식을 조리합니다.")
}
}
// 사용 예시
let 김웨이터 = 웨이터(이름: "김철수")
let 이요리사 = 요리사(이름: "이영희")
김웨이터.출근하기()
김웨이터.주문받기()
김웨이터.음식준비하기()
이요리사.음식준비하기()
김웨이터.음식서빙하기()
- 상속 사용:
• `직원` 클래스는 기본 클래스로, 모든 직원의 공통 속성과 메서드를 정의합니다.
• `웨이터`와 `요리사` 클래스는 `직원` 클래스를 상속받아 `이름` 속성과 `출근하기()` 메서드를 물려받습니다. - 프로토콜 사용:
• `주문처리` 프로토콜은 주문과 관련된 메서드를 정의합니다.
• `서빙` 프로토콜은 서빙과 관련된 메서드를 정의합니다.
• `웨이터` 클래스는 `주문처리`와 `서빙` 프로토콜을 모두 채택합니다.
• `요리사` 클래스는 `주문처리` 프로토콜만 채택합니다. - 상속과 프로토콜의 조합:
• `웨이터` 클래스는 `직원`을 상속받으면서 동시에 `주문처리`와 `서빙` 프로토콜을 채택합니다.
• `요리사` 클래스는 `직원`을 상속받으면서 `주문처리` 프로토콜을 채택합니다.
'iOS' 카테고리의 다른 글
[iOS] 옵셔널 체이닝 Error_Handling Generic Array (0) | 2025.04.09 |
---|---|
[iOS] Table View (0) | 2025.04.02 |
[iOS] 무드등 앱 개발 및 Swift 문법 복습 2 (0) | 2025.03.19 |
[iOS] Swift 문법 복습 (0) | 2025.03.18 |
[iOS] 생성형 AI 및 오픈 API 활용 (0) | 2025.03.05 |