2025. 11. 25. 17:50ㆍiOS 기초/수업 내용 및 수업 후 과제

move to trash를 눌러서 삭제해야 한다

스토리보드와 클래스를 연결하는 것은? ->identity inspector이다 기말고사 문제
원래는

import WebKit만 추가하면 안되고

+버튼 눌러서

add눌러야 한다

추가가 완료된 모습


아주 좋아! 지금 보여준 이미지에 나온 Swift의
init?(string: String)
을 기반으로 왜 “페이셔널 이니셜라이저(failable initializer)”인지,
왜 옵셔널 형태인지 정확하게 설명해줄게.
✅ 1. 이 생성자는 “페이셔널 이니셜라이저”다 (init? 형태)
이미지처럼, Apple 문서에서 URL 생성자는 이렇게 되어 있어:
init?(string: String)
여기서 init? 는 Failable Initializer(실패 가능한 초기화 메서드) 를 의미해.
즉,
"주어진 문자열이 URL 형식이 아니면 객체 생성에 실패할 수 있다."
라는 뜻이야.
🔍 왜 실패가 가능한가?
URL 생성은 절대 100% 성공이 보장되지 않기 때문이야.
예를 들어:
- "https://apple.com" → 정상 URL → 생성 성공
- "hello world" → URL 형식 아님 → 생성 실패(nil 반환)
- "ht!tp://wrong^^format.com" → 잘못된 URL → 실패(nil)
문자열이 반드시 URL 규칙을 따라야 하는데
잘못된 형식이면 URL 객체를 만들 수 없어.
그래서 “실패 가능” → init?
✅ 2. 반환 타입이 Optional인 이유
init?() 형태는 초기화 실패 시 nil을 반환하기 때문에,
URL 객체가 Optional이 되는 거야.
즉, 이 생성자는 URL? 타입을 만든다.
예시:
let url = URL(string: "https://google.com")
// url은 URL? 타입
왜 옵셔널?
- 성공: 유효한 URL 객체 → URL
- 실패: 생성 불가 → nil
옵셔널로 감싸지 않으면 실패 케이스를 표현할 방법이 없어.
📌 이미지 기준 핵심 정리
이미지에서 보인 것:
init?(string: String)
- init? → Failable initializer
- URL은 문자열이 잘못되면 생성 불가 → 실패 가능
- 따라서 반환 타입은 무조건 Optional(URL?)
📘 한 줄 요약
URL(string:)은 문자열이 잘못되면 URL을 만들 수 없기 때문에 “실패 가능한 이니셜라이저(init?)”로 설계되었으며, 결과도 Optional(URL?)로 반환된다.
필요하면
📌 Optional과 Forced Unwrapping (!), Optional Binding(if let)
📌 Swift 초기화 방식(init / init? / init!)
이것도 간단하게 정리해서 이어서 설명해줄게!
기말고사에 나올 수 있는 내용임 ^위 아래 내용 둘다

좋아! 지금 보여준 이미지는 URLRequest의 초기화(init) 중 하나인
⭐ init(url:cachePolicy:timeoutInterval:)
을 설명하는 Apple 공식 문서야.
이 초기화 메서드를 정확히 이해하면, 네트워크 요청을 직접 제어할 수 있어.
✅ 1. 이 초기화 메서기가 하는 일
init(
url: URL,
cachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy,
timeoutInterval: TimeInterval = 60.0
)
이 생성자는 다음 3가지를 입력받아 URLRequest 객체를 만들어.
① url: URL
- 요청을 보낼 URL(필수)
- Optional이 아니라 반드시 유효한 URL 타입이어야 함
예:
let url = URL(string: "https://apple.com")!
② cachePolicy: URLRequest.CachePolicy
요청이 캐시 데이터를 어떻게 사용할지 결정함.
대표 옵션:
옵션 설명
| .useProtocolCachePolicy | 서버/클라이언트 캐시 규칙을 그대로 따름 (기본값) |
| .reloadIgnoringLocalCacheData | 캐시 무시하고 무조건 새로 요청 |
| .returnCacheDataElseLoad | 캐시 데이터가 있으면 캐시 사용, 없으면 로드 |
| .returnCacheDataDontLoad | 캐시가 없으면 로드하지 않음 |
③ timeoutInterval: TimeInterval
- 요청이 몇 초 이상 걸리면 실패(timeout) 할지 설정
- 기본값: 60초
- 단위: 초(Double)
📌 2. 이 초기화 메서드는 왜 존재하나?
URLRequest는 단순 URL만 로드하는 것이 아니라,
네트워크 통신의 여러 동작을 제어할 수 있도록 설계된 객체야.
즉, URL 하나만 넣는 단순 초기화:
let request = URLRequest(url: url)
이렇게 쓰면 "기본 설정"으로만 동작함.
하지만 아래 메서드를 사용하면:
let request = URLRequest(
url: url,
cachePolicy: .reloadIgnoringLocalCacheData,
timeoutInterval: 15
)
- 캐시를 무시할지
- 몇 초 후 타임아웃 시킬지
까지 세세하게 조절 가능함.
⭐ 3. 사용 예제 (실제 코드)
let url = URL(string: "https://www.naver.com")!
let request = URLRequest(
url: url,
cachePolicy: .reloadIgnoringLocalCacheData,
timeoutInterval: 10
)
wkwebview.load(request)
이 요청은:
- 캐시 사용 안 하고 항상 새 데이터 요청
- 10초 이상 응답 없으면 실패
📘 4. 간단 요약
init(url:cachePolicy:timeoutInterval:)은
특정 URL에 대해 캐시 전략과 타임아웃 시간을 직접 지정하여
URLRequest 객체를 생성하게 해주는 초기화 메서드이다.
즉, 네트워크 요청의 동작을 더 세밀하게 조절하고 싶을 때 사용하는 초기화.
원하면
📌 URLRequest의 다른 초기화들
📌 GET/POST HTTP Method 설정
📌 URLSession을 이용한 네트워크 통신 예제
이런 것도 이어서 설명해줄게!

기말고사에 나옴^ 디폴트 인자(매개변수)

옵셔널 url형
//
// WebViewController.swift
// BMIA
//
// Created by 소프트웨어컴퓨터 on 2025/11/18.
//
import UIKit
import WebKit
class WebViewController: UIViewController {
@IBOutlet weak var wkwebview: WKWebView!
@IBAction func goYouTube(_ sender: UIButton) {
// 유튜브 URL
let youtubeUrl = "https://m.youtube.com/"
// URL 객체로 변환
if let url = URL(string: youtubeUrl) {
let request = URLRequest(url: url)
wkwebview.load(request) // ★ 웹뷰에 사이트 로드
} else {
print("유효하지 않은 URL입니다.")
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
이렇게 써도 되지만

강제 업래핑하는 방식
//
// WebViewController.swift
// BMIA
//
// Created by 소프트웨어컴퓨터 on 2025/11/18.
//
import UIKit
import WebKit
class WebViewController: UIViewController {
@IBOutlet weak var wkwebview: WKWebView!
@IBAction func goYouTube(_ sender: UIButton) {
let url = URL(string: "https://m.youtube.com/")!
let request = URLRequest(url: url)
wkwebview.load(request)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
guard let 사용하는 방식
//
// WebViewController.swift
// BMIA
//
// Created by 소프트웨어컴퓨터 on 2025/11/18.
//
import UIKit
import WebKit
class WebViewController: UIViewController {
@IBOutlet weak var wkwebview: WKWebView!
@IBAction func goYouTube(_ sender: UIButton) {
guard let url = URL(string: "https://m.youtube.com/") else { return }
let request = URLRequest(url: url)
wkwebview.load(request)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
//
// WebViewController.swift
// BMIA
//
// Created by 소프트웨어컴퓨터 on 2025/11/18.
//
import UIKit
import WebKit
class WebViewController: UIViewController {
@IBOutlet weak var wkwebview: WKWebView!
@IBAction func goYouTube(_ sender: UIButton) {
guard let url = URL(string: "https://m.youtube.com/") else { return }
let request = URLRequest(url: url)
wkwebview.load(request)
}
override func viewDidLoad() {
super.viewDidLoad()
guard let url = URL(string: "https://m.youtube.com/") else { return }
let request = URLRequest(url: url)
wkwebview.load(request)
}
}
최종 완성코드
override func viewDidLoad() {
super.viewDidLoad()
guard let url = URL(string: "https://m.youtube.com/") else { return }
let request = URLRequest(url: url)
wkwebview.load(request)
} 이 코드 설명
너가 추가한 코드는 앱이 화면에 처음 들어왔을 때 자동으로 유튜브를 로드하는 기능이야.
즉,
⭐ “viewDidLoad() 실행 시 웹뷰가 자동으로 유튜브 페이지를 띄운다”
라는 뜻!
🔍 한 줄씩 정확하게 설명해줄게
✔️ 1) override func viewDidLoad() {
- ViewController가 화면에 처음 나타날 때 가장 먼저 실행되는 함수.
✔️ 2) super.viewDidLoad()
- 부모 클래스(UIViewController)의 기본 초기화 동작을 먼저 실행해야 하므로 항상 호출해야 함.
✔️ 3) guard let url = URL(string: "https://m.youtube.com/") else { return }
- 문자열을 URL로 변환
- 만약 URL 문자열이 잘못되었다면 → 함수 종료(return)
👉 guard let이므로 url은 Optional이 아닌 URL 타입으로 안전하게 사용 가능
✔️ 4) let request = URLRequest(url: url)
- URL을 기반으로 URLRequest 객체 생성
- 즉, "이 URL로 요청을 보낼 준비"를 하는 단계
✔️ 5) wkwebview.load(request)
- 실제로 웹뷰가 해당 주소를 로드함
- iPhone 화면에서 바로 YouTube 모바일 페이지가 뜨는 이유
📌 요약하면
너가 작성한 코드는:
앱 실행 → viewDidLoad 실행 → 자동으로 https://m.youtube.com/ 을 WKWebView에 로드
그래서 앱 시작하자마자 유튜브가 보이는 거야.

이렇게 하면 기본적으로 네이버를 띄우지만
유튜브 버튼을 누르면 유튜브가 뜨게 된다

각각 뭔지 알아두기 기말고사문제

Align알아두기

화면에서 수평, 수직을 유지하도록 만드는것
Xcode에서 오토레이아웃(Auto Layout) 설정하는 방법을
가장 쉽게, 단계별로 완전 기초부터 설명해줄게!
(스토리보드 기준, UIKit 기반)
⭐ 오토레이아웃(Auto Layout)이란?
iPhone 화면 크기(8, 11 Pro, 14 Pro Max 등)가 모두 달라도
UI가 자동으로 위치/크기를 조절하도록 만드는 규칙 시스템이야.
그래서 오토레이아웃이 꼭 필요함.
✅ 1. Storyboard에서 UI 요소를 배치하기
- Xcode 왼쪽에서 Main.storyboard 클릭
- 오른쪽 상단의 + 버튼(라이브러리) 클릭
- Label / Button / ImageView 등을 화면에 드래그해서 배치
UI를 올렸으면 이제 오토레이아웃을 설정해야 움직이지 않음.
✅ 2. UI 요소 선택 → Constraints 추가하기
- 레이블 또는 버튼을 선택
- 스토리보드 오른쪽 하단에서 이 버튼 찾기👇
🔹 Constraints(사각형 + 막대기) 아이콘 
- 클릭하면 이런 창이 뜸:
Top Left Bottom Right
Width Height
- 원하는 제약을 체크하고 Add Constraints 클릭
📌 가장 기본적인 설정 예시
✔️ 버튼을 화면 아래 중앙에 고정하려면
- 버튼 선택
- 아래 Constraints 버튼 클릭
- Bottom: 20 (safe area 기준) 체크
- Center Horizontally in Safe Area 체크
- Add 2 Constraints
👉 이렇게 하면
- 아래에서 20px
- 가로 중앙 정렬
이 보장됨
⭐ 3. 오토레이아웃 핵심 3가지
제약 의미
| 위치 제약 (Top, Bottom, Leading, Trailing) | 어디에 붙을지 결정 |
| 크기 제약 (Width, Height) | UI의 크기 결정 |
| 정렬 제약 (Center X, Center Y) | 가운데 정렬할 때 사용 |
⭐ 4. Ambiguous / Missing Constraints 해결하기
빨간색 경고(❗️) 뜨면:
- Constraints 부족 → "모호한 레이아웃"
- Constraints 충돌 → "서로 다른 규칙이 싸움"
해결법:
🔧 1) UI 선택 → 오른쪽 Size Inspector(자) 클릭
여기서 어떤 제약이 잘못됐는지 볼 수 있음
🔧 2) 자동 해결 기능 사용
스토리보드 아래의 "Resolve Auto Layout Issues" 메뉴에서
- Add Missing Constraints
- Update Frames
- Reset Constraints
등 선택 가능
⭐ 5. Safe Area란?
iPhone의 상단 노치, 하단 홈바를 피해서
UI가 잘려보이지 않도록 안전한 영역.
대부분 제약은 Safe Area 기준으로 잡는 게 좋음.
🎯 예시: 웹뷰를 전체 화면에 꽉 채우기
- WKWebView 드래그
- Constraints 버튼 클릭
- Top, Bottom, Leading, Trailing 모두 0으로 설정
- Add 4 Constraints
👉 모든 화면 크기에서 꽉 차게 됨!


present함수 기말고사 10점짜리 문제
이 함수는 iOS에서 새 화면(ViewController)을 모달 방식으로 띄울 때 사용하는 함수야.
원형은 다음과 같아:
func present(
_ viewControllerToPresent: UIViewController,
animated flag: Bool,
completion: (() -> Void)? = nil
)
하나씩 풀어 설명하고, 실제 사용하는 예시 코드 3가지도 보여줄게.
✅ 1) 파라미터 설명
파라미터 의미
| viewControllerToPresent | 보여줄 ViewController 객체 |
| flag | 애니메이션 여부 (true면 부드럽게 올라옴) |
| completion | 화면 표시가 끝난 뒤 실행할 코드 (옵션) |
⭐ 2) 가장 기본적인 사용 예
예를 들어, 현재 화면에서 NextViewController 라는 새로운 화면을 모달로 띄우고 싶다면:
let vc = NextViewController()
present(vc, animated: true, completion: nil)
- 화면이 위로 올라오는 애니메이션으로 열린다
- 추가 작업은 없음 → completion=nil
⭐ 3) 스토리보드에서 화면 띄우기 예시
스토리보드에 “NextVC”라는 Storyboard ID가 있을 때:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let nextVC = storyboard.instantiateViewController(withIdentifier: "NextVC")
present(nextVC, animated: true)
⭐ 4) completion을 사용하는 예시
화면이 보여진 후에 “완료!”라는 출력문을 실행하고 싶다면:
let vc = NextViewController()
present(vc, animated: true) {
print("새 화면 표시 완료!")
}
⭐ 5) 전체 실습 예시 (버튼 눌렀을 때 화면 띄우기)
Sender 버튼에서 모달 띄우기
@IBAction func goNext(_ sender: UIButton) {
let vc = NextViewController()
present(vc, animated: true)
}
⭐ 6) 풀스크린으로 띄우기 (.fullScreen)
let vc = NextViewController()
vc.modalPresentationStyle = .fullScreen
present(vc, animated: true)
⭐ 7) 예시 — Alert 띄우기에도 내부적으로 present 사용됨
swift 내부적으로 Alert도 present로 띄워짐:
let alert = UIAlertController(title: "알림", message: "완료!", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true)
📌 요약
present()는 현재 화면 위에 새로운 화면을 모달 방식으로 표시하는 함수이고,
- 화면 객체 전달 → present
- 애니메이션 true/false 지정
- 화면 표시 후 실행할 동작은 completion에 작성
실제 앱에서 가장 많이 쓰는 화면 전환 방식 중 하나야.


매개변수도 없고 반환값도 없는 함수로 되어 있다, 옵셔널로 되어있다.
엔터를 쳐서 후행 클로져 방식으로 바꾼다


강의자료 75p
3개의 소스의 차이점
(기말고사 시험에 자주 나오는 문제)
present(playerViewController, animated: true)
player.play()
self.present(playerViewController, animated: true)
player.play()
self.present(playerViewController, animated: true) {
player.play()
} //후행 클로저(trailing closure)

아주 좋아!
지금 보여준 3개의 코드는 겉으로 보기에는 비슷하지만 완전히 다른 시점(timing)에 실행되는 코드야.
즉, 언제 player.play()가 실행되느냐 가 포인트야.
아래에서 정확하게 비교해줄게.
✅ 1)
present(playerViewController, animated: true)
player.play()
✔️ 실행 순서
- present(...) 호출만 함 (애니메이션은 비동기적으로 진행)
- 바로 다음 줄에서 player.play() 실행됨 (화면 전환이 끝나기 전!)
✔️ 문제점
- 화면이 아직 뜨기 전에 play가 실행될 수 있음
- 영상이 깜빡이거나 늦게 재생될 가능성 있음
📌 요약
present 호출 직후 즉시 실행
화면이 뜨기 전에 재생될 가능성이 큼 → 권장되지 않음
✅ 2)
self.present(playerViewController, animated: true)
player.play()
✔️ 차이점?
present 앞에 self. 만 붙었을 뿐 1번과 완전히 동일한 동작임.
- self.present(...) = 현재 ViewController에서 present 실행
- present(...)와 완전히 동일한 코드
📌 요약
1번과 동작 100% 동일
self. 를 붙여도 실행 시점은 바뀌지 않음
⭐ 핵심: 1번과 2번은 “present 애니메이션이 끝나기 전에 play()가 실행”된다.
✅ 3) 후행 클로저(Trailing Closure)
self.present(playerViewController, animated: true) {
player.play()
}
✔️ 실행 순서
- present(...) 호출 → 애니메이션 시작
- 새 화면이 모두 표시된 후(completion)
- 클로저 실행 → player.play() 실행
✔️ 가장 안정적, 권장 방식
- 화면이 완전히 나타난 후 재생됨
- 영상, 음악, 애니메이션 등을 보여줄 때 정확한 타이밍 확보
📌 요약 비교 표
코드 실행 시점 결과
| present(...); player.play() | present 실행 직후 (애니메이션 완료 전) | 재생 타이밍이 어긋날 수 있음 |
| self.present(...); player.play() | 위와 동일 | 동일한 문제 발생 |
| present(..., completion: { player.play() }) | ✔ 화면 표시가 완전히 끝난 후 | 가장 정확하고 안정적 |
⭐ 결론
🔥 1번 & 2번
- present는 비동기 → 화면이 뜨기 전에 player.play() 실행됨
- 재생 타이밍 불안정
🔥 3번(후행 클로저)
- present 애니메이션 완료 후 실행
- player.play()를 넣기에 유일하게 정확한 위치
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
클로저
func add(x: Int, y: Int) -> Int {
return(x+y)
}
print(add(x:10, y:20))
클로저 형식으로 바꾸기
func add(x: Int, y: Int) -> Int {
return(x+y)
}
print(add(x:10, y:20))
let add1 = {(x: Int, y: Int) -> Int in
return(x+y)
}
print(add1(x:10, y:20))
expression failed to parse:
error: 1125a.playground:9:11: error: extraneous argument labels 'x:y:' in call
print(add1(x:10, y:20))
^~~ ~~
오류 뜸
------------------------
일반 함수를 사용할때는 아규먼트 레이블을 사용하지 않고, 값만 지정한다
func add(x: Int, y: Int) -> Int {
return(x+y)
}
print(add(x:10, y:20))
let add1 = {(x: Int, y: Int) -> Int in
return(x+y)
}
print(add1(10, 20))
실행결과
30
30
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
함수안에 함수가 또 들어가 있으면 복잡해지기 때문에 바꾼다
후행 클로저 하는 두가지 방법 (아래)


let multiply = {(a: Int, b: Int) -> Int in
return a * b
}
var result = multiply(10, 20)
print(result)
실행결과
200
let multiply = {(a: Int, b: Int) -> Int in
return a * b
}
var result = multiply(10, 20)
print(result)
let add = {(a: Int, b: Int) -> Int in
return a + b
}
result = add(10, 20)
print(result)
실행결과
200
30
let multiply = {(a: Int, b: Int) -> Int in
return a * b
}
var result = multiply(10, 20)
//print(result)
let add = {(a: Int, b: Int) -> Int in
return a + b
}
result = add(10, 20)
//print(result)
func math(x: Int, y: Int, cal: (Int, Int) -> Int) -> Int {
return cal(x, y)
}
result = math(x: 10, y: 20, cal: add)
print(result)
result = math(x: 10, y: 20, cal: multiply)
print(result)
실행결과
30
200

중요한 부분
함수가 들어가야함 무슨 형식이 들어갈 수 있는지 gpt질문
좋아!
네가 표시한 부분은 이 함수의 매개변수 타입이야:
func math(x: Int, y: Int, cal: (Int, Int) -> Int) -> Int
즉, cal에는 (Int, Int) -> Int 타입의 함수(또는 클로저) 만 들어갈 수 있어.
⭐ 1. 들어갈 수 있는 타입의 조건
✔ 두 개의 Int를 입력으로 받고 → 하나의 Int를 반환하는 함수 타입
따라서 이런 형태의 함수 or 클로저만 전달 가능:
(Int, Int) -> Int
예:
- (10, 20) → 30
- (10, 20) → 200
- (10, 20) → -10
- (10, 20) → gcd (정수의 최대공약수)
- (10, 20) → min (작은 값 반환)
- (10, 20) → max (큰 값 반환)
⭐ 2. 어떤 함수들이 들어갈 수 있는지 구체적 예시
① 일반 함수 형태
func add(a: Int, b: Int) -> Int {
return a + b
}
func subtract(a: Int, b: Int) -> Int {
return a - b
}
func multiply(a: Int, b: Int) -> Int {
return a * b
}
func divide(a: Int, b: Int) -> Int {
return a / b
}
이런 함수들은 방식이 일치하므로 모두 cal에 들어갈 수 있음
math(x: 10, y: 20, cal: add)
math(x: 10, y: 20, cal: subtract)
math(x: 10, y: 20, cal: multiply)
math(x: 10, y: 20, cal: divide)
⭐ 3. 클로저도 가능
② 클로저 형태 (너 코드처럼)
let add = { (a: Int, b: Int) -> Int in
a + b
}
let multiply = { (a: Int, b: Int) -> Int in
a * b
}
math(x: 10, y: 20, cal: add)
math(x: 10, y: 20, cal: multiply)
⭐ 4. 후행 클로저로 넘길 수도 있음
math(x: 10, y: 20) { a, b in
return a % b
}
위 클로저도 (Int, Int) -> Int 형태이므로 가능.
⭐ 5. 표준 라이브러리 함수도 가능
Swift는 min 과 max 함수가 이미 존재하고, 이 둘도 (Int, Int) -> Int 형태로 사용 가능함.
math(x: 10, y: 20, cal: min) // 10 반환
math(x: 10, y: 20, cal: max) // 20 반환
🎯 최종 정리
표시한 칸에 들어갈 수 있는 것은?
두 개의 Int를 입력받고 하나의 Int를 반환하는 모든 함수 또는 클로저
즉, 형식이 (Int, Int) -> Int 인 모든 것.
let multiply = {(a: Int, b: Int) -> Int in
return a * b
}
var result = multiply(10, 20)
//print(result)
let add = {(a: Int, b: Int) -> Int in
return a + b
}
result = add(10, 20)
//print(result)
func math(x: Int, y: Int, cal: (Int, Int) -> Int) -> Int {
return cal(x, y)
}
result = math(x: 10, y: 20, cal: add)
print(result)
result = math(x: 10, y: 20, cal: {(a: Int, b: Int) -> Int in
return a + b
})
print(result)
add를 넣거나 add의 부분
{(a: Int, b: Int) -> Int in
return a + b
}이부분을 넣어도 결과는 같다
실행결과
30
30

let multiply = {(a: Int, b: Int) -> Int in
return a * b
}
var result = multiply(10, 20)
//print(result)
let add = {(a: Int, b: Int) -> Int in
return a + b
}
result = add(10, 20)
//print(result)
func math(x: Int, y: Int, cal: (Int, Int) -> Int) -> Int {
return cal(x, y)
}
result = math(x: 10, y: 20, cal: add)
print(result)//add를 직접
result = math(x: 10, y: 20, cal: {(a: Int, b: Int) -> Int in
return a + b //add값을 직접씀
})
print(result)
result = math(x: 10, y: 20, cal: {(a: Int, b: Int) in
return a + b // -> in 생략
})
print(result)
result = math(x: 10, y: 20, cal: {
return $0 + $1//매개변수를 생략
})
print(result)
result = math(x: 10, y: 20, cal: {$0 + $1}) //return까지 생략
print(result)
설명 추가하기

let multiply = {(a: Int, b: Int) -> Int in
return a * b
}
var result = multiply(10, 20)
//print(result)
let add = {(a: Int, b: Int) -> Int in
return a + b
}
result = add(10, 20)
//print(result)
func math(x: Int, y: Int, cal: (Int, Int) -> Int) -> Int {
return cal(x, y)
}
result = math(x: 10, y: 20, cal: add)
print(result)//add를 직접
result = math(x: 10, y: 20) {(a: Int, b: Int) -> Int in
return a + b
}//후행 클로저 스타일로 변경
print(result)
result = math(x: 10, y: 20) {(a: Int, b: Int) in
return a + b
}//후행 클로저 스타일, 리턴형 생략
print(result)
result = math(x: 10, y: 20) {
return $0 + $1
}//후행 클로저 스타일, 매개변수 생략하고 단축인자(shorthand argument name)사용
print(result)
result = math(x: 10, y: 20) {$0 + $1}//후행 클로저 스타일 return생략
print(result)
이게 맞는건지 확인

Swift에서 trailing closure(후행 클로저) 를 사용하는 이유는 딱 두 가지야:
✅ 1. 코드 가독성이 훨씬 좋아지기 때문
✅ 2. 중첩 구조가 많은 코드(콜백, 애니메이션, 네트워크 요청)를 더 자연스럽게 표현할 수 있기 때문
아래에서 예와 함께 쉽고 간단하게 설명해줄게!
🟦 1. 왜 trailing closure를 사용할까?
🔥 이유 1) 가독성 향상
함수 괄호 안에 클로저를 넣으면 코드가 복잡해져서 읽기 어려워.
예)
fetchData(completion: { result in
print(result)
})
하지만 trailing closure를 사용하면:
fetchData() { result in
print(result)
}
→ 훨씬 깔끔하고 Swift답게 보임
🔥 이유 2) 중첩 구조에서 훨씬 명확함
네트워크나 애니메이션은 클로저 안에서 다시 클로저를 쓰는 경우가 많아.
Trailing closure를 쓰면 구조가 “계층적으로” 보이기 때문에 이해하기 쉬움.
예)
UIView.animate(withDuration: 0.5, animations: {
box.alpha = 0.0
})
Trailing closure 사용:
UIView.animate(withDuration: 0.5) {
box.alpha = 0.0
}
→ 훨씬 자연스럽다.
🟦 2. Trailing Closure란?
함수의 마지막 매개변수가 클로저일 때, 그 클로저를 함수 괄호 밖으로 빼서 작성하는 문법
정의 자체가 매우 간단함.
🟦 3. trailing closure 사용하지 않는 방식 (일반 방식)
func test(number: Int, action: (Int) -> Void) { }
test(number: 10, action: { num in
print(num)
})
→ 읽기 어렵고 함수 괄호 안이 복잡해짐.
🟦 4. trailing closure 사용 방식
test(number: 10) { num in
print(num)
}
→ 깔끔하고 이해하기 쉽다.
🟦 5. 실제 iOS에서 자주 쓰는 예
▶️ 예 1) present() completion에 후행 클로저 적용
present(vc, animated: true) {
print("화면이 열렸습니다!")
}
→ completion이 trailing closure라서 안에 {} 만 쓰면 된다.
▶️ 예 2) 네트워크 요청
loadData { data in
print(data)
}
▶️ 예 3) 지도, 애니메이션, Firebase, Alamofire 등도 모두 trailing closure 사용
UIView.animate(withDuration: 1.0) {
view.alpha = 0
}
🟩 최종 정리
이유 설명
| 가독성 향상 | 함수 괄호 안의 복잡한 클로저를 밖으로 빼서 코드가 깔끔해짐 |
| 자연스러운 문법 | Swift 스타일과 매우 잘 맞아 Swift다운 코드가 됨 |
| 중첩된 콜백 구조에 유용 | 네트워크, 애니메이션, completion 등에서 필수적 |
원하면
📌 "왜 함수의 마지막 매개변수만 가능한가?"
📌 "후행 클로저 + 여러 클로저 매개변수 있을 때 문법"
📌 "데이터 넘기기, escaping 클로저"
까지 예제로 설명해줄게!
'iOS 기초 > 수업 내용 및 수업 후 과제' 카테고리의 다른 글
| iOS 12주차 수업 내용 및 수업 후 과제 (0) | 2025.11.18 |
|---|---|
| iOS 11주차 수업 내용 및 수업 후 과제 (1) | 2025.11.11 |
| iOS 수업 내용 및 수업 후 과제 (0) | 2025.11.11 |
| iOS 9주차 수업 내용 및 수업 후 과제 (0) | 2025.10.28 |
| iOS 6,7주차 (0) | 2025.10.14 |