본문 바로가기

iOS 프로그래밍 실무

[25.04.30_9주차] iOS 프로그래밍 실무

Open API 기반 iOS앱 개발(1)

RESTful/JSON/Open API

 

요즘은 대부분 REST 방식 사용

 

JSON 코드 정리 사이트

https://codebeautify.org/jsonviewer

 

Best JSON Viewer and JSON Beautifier Online

Online JSON Viewer, JSON Beautifier and Formatter to beautify and tree view of JSON data - It works as JSON Pretty Print to pretty print JSON data.

codebeautify.org

 

퀵타입 (quicktype) : JSON 데이터의 데이터 모델 만들기

https://app.quicktype.io/

 

Instantly parse JSON in any language | quicktype

 

app.quicktype.io

 

API 플랫폼(테스트, 협업, 문서화)

https://www.postman.com/

 

Postman: The World's Leading API Platform | Sign Up for Free

Accelerate API development with Postman's all-in-one platform. Streamline collaboration and simplify the API lifecycle for faster, better results. Learn more.

www.postman.com

 

REST(REpresentational State Transfer)

: 웹에서 정보를 주고받는 방법(아키텍처 스타일)

 웹에서 컴퓨터들이 데이터를 주고받는 규칙

 

- REST의 특징

- 리소스(resource)

 인터넷에 존재하는 모든 정보(회원, 게시글 등)

 예: /users/1 (1번 회원), /posts (게시글 전체)

- 주소(URI, URL):

 리소스마다 주소가 있음

 예: https://site.com/users/1

- 행동(HTTP 메서드):

 어떤 행동을 할지 정하는 방법

 GET (가져오기), POST (생성), PUT (수정), DELETE (삭제)

 1번 유저 정보 가져오기

GET/users/1

 

RESTful

: REST의 규칙을 최대한 잘 지켜서 만든 서비스

- REST의 원칙대로 주소(URI)와 동작(HTTP 메서드)을 깔끔하게 잘 설계한 API는 “RESTful”하다. 

 

- RESTful한 API 예

GET /users → 회원 목록 보기

GET /users/1 → 1번 회원 정보 보기

POST /users → 새 회원 추가

PUT /users/1 → 1번 회원 정보 수정

DELETE /users/1 → 1번 회원 삭제 

 

- RESTful하지 않은 예

주소에 동작이 섞여 있음

POST /users/getUser → 회원 정보 보기

GET /users/deleteUser → 회원 삭제

 

RESTful API 와 HTTP 전송방식

- 일반적으로 서버에 요청하는 정보의 타입은 쓰기(Create), 읽기(Read), 수정(Update), 삭제(Delete) 로 구분되고, 네가지의 첫글자를 합쳐서 CRUD라고 부름

- URI 구성권고에 따르면 RESTful API 구성을 위한 URI에는 정보의 분류 체계만 포함되어야지, 정보를 어떻게 다룰 것인가 하는 동작에 관한 명세는 포함하지 않을 것을 권고함

    - URI 어떤 계층의 어떤 데이타라는 정보만 기재할뿐, 그 데이타를 읽을지 쓸지 등에 대한 액션 구분은 URI 에 나타내지 않음

- 권고안에서는 HTTP 메소드를 사용하여 이같은 액션을 구분해 줄 것을 권고함

- RESTful API 형식으로 데이터를 제공하면, 서버에서 작성해 놓은 URI 명세에 따라 원하는 요청을 식별할 수 있도록 URI 를 구성하여 보내면 됨

 

RESTful API 에서 HTTP 메소드의 종류

메소드(전송방식)  목 적
    POST     리소스를 create 
GET 리소스 정보 read 
PUT 리소스 update
DELETE 리소스 delete

 

XML(Extensible Markup Language)

- 시작 태그 <element>

- 끝 태그 </element>

- 빈 요소 태그 <element/>

- 파싱(Parsing)

    XML데이터를 추출하여 분석 

    파싱을 처리하는 모듈을 파서(parser)라 함

- 장점

    플랫폼 독립적

- 단점

    마크업 태그를 사용하므로 데이터량 큼

 

JSON(JavaScript Object Notation) 

- XML의 단점을 극복하기 위해 만들어진 경량의 데이터 교환 형식 

http://www.json.org/json-ko.html 

- 사람이 읽고 쓰기에 용이하며, 기계가 분석하고 생성하기도 용이 

- 프로그래밍 언어로부터 독립적이기 때문에 데이터 교환에 많이 사용

- JSON에 사용되는 데이터 구조 두가지 

    집합구조 : 여러가지 속성을 다양하게 정의할 수 있는 집합구조 {} 

    리스트구조 : 비슷한 상황이 반복되는 리스트 구조 []

구분 형식 명칭
여러속성을 정의하는 순서 없는 집합 { 키: 값, 키:값, …. } JSON 객체
비슷한 객체가 반복 나열되 는 순서있는 리스트 [ 객체1, 객체2, …..] JSON 배열

 

JSON의 구조

- name/value 형태의 쌍 

    collection 타입

    프로그래밍 언어에서 object, record, struct, dictionary, hash table, 키가 있는 list 등 

- 순서있는 값들의 리스트

    array, vector, list, sequence 

- JSON객체(object)는 name/value 쌍들의 순서없는 SET

    object는 "{" 로 시작하고 "}" 로 끝냄

    각 name 뒤에 ":"을 붙임 

    ", "로 name/value 쌍을 구분 

{ "이름": "김컴소", "나이": 20, "성별": "남" }
{
  "이름": "김컴소",
  "나이": 20,
  "성별": "남",
  "전화": {
    "휴대": "010-1111-2222",
    "집": "02-1111-2345"
  }
}

 

JSON 배열

- array는 순서가 있는 값의 collection

- array는 "["로 시작해서 "] " 로 끝냄

- ","로 array의 값들을 구분

{
"name":"김컴소",
"age":30,
"cars":["아반떼", "쏘나타", "그랜저" ]
}

 

API

- Application Programming Interface

- 두 개 이상의 컴퓨터 프로그램이 서로 통신하는 방법

- 다른 소프트웨어에 서비스를 제공하는 소프트웨어 인터페이스

- 컴퓨터와 사람을 연결하는 UI와 달리 API는 컴퓨터나 소프트웨어를 서로 연결

- printf, Java SE APIs, Windows API, SQLIte API, OpenGL API, Open API 등

예시) API는 손님과 셰프 사이의 웨이터의 역할

 

오픈 API (Open API)

일부 웹사이트에서 SOAP 프로토콜이나 RESTful 형식을 사용하여 공공 컨텐츠를 제공하는데 이를 오픈 API (Open API)라 함

https://github.com/dl0312/open-apis-korea

 

GitHub - dl0312/open-apis-korea: 🇰🇷 한국어 사용자를 위한 서비스에 사용하기 위한 오픈 API 모음

🇰🇷 한국어 사용자를 위한 서비스에 사용하기 위한 오픈 API 모음. Contribute to dl0312/open-apis-korea development by creating an account on GitHub.

github.com

https://rapidapi.com/blog/most-popular-api/

 

Top 50 Most Popular APIs (Updated for 2023) | Rapid Blog

Check out the most popular APIs on Rapids API Hub in 2022. Sign up today for a FREE account to begin testing these top APIs!

rapidapi.com

https://data.seoul.go.kr/datasetRanking/popular.do

 

열린데이터광장 메인

데이터분류,데이터검색,데이터활용

data.seoul.go.kr

공공데이터 포털 Open API

http://www.data.go.kr

네이버 Open API

https://developers.naver.com/main/ 

https://www.ncloud.com/product/applicationService/maps

카카오 개발자 서비스

https://developers.kakao.com

11번가 Open API Center

https://openapi.11st.co.kr/openapi/OpenApiFrontMain.tmall

쿠팡 Open API 

https://developers.coupangcorp.com/hc/ko

YouTube Data API 

https://developers.google.com/youtube/v3/getting-started?hl=ko

 

Open API를 이용한 앱 개발 단계

1. 원하는 정보를 제공하는 웹 서비스와 사용할 Open API 선정

2. Open API 사용을 위한 신청과 인증키 발급

3. 네트워크를 통해 데이터 요청

4. 받은 데이터를 파싱하여 앱에서 사용

 

내가 사용하고 싶은 Open API

https://www.data.go.kr/data/15099883/openapi.do

 

한국교통안전공단_주차정보 제공 API

통합 주차정보 서비스를 민간주차장 서비스 제공업체에 제공하여 대국민들이 실시간으로 다양한 채널을 통하여 편리하게 주차장 관련 서비스를 활용하도록 하고, 축적된 주차장 정보들을 빅데

www.data.go.kr

 

JSON데이터 기반으로 Swift구조체 만들기 예시

import Foundation

struct ParkingLotResponse: Codable {
    let items: [ParkingLot]
}

struct ParkingLot: Codable {
    let prk_center_id: String
    let prk_plce_nm: String
    let prk_plce_adres: String
    let prk_cmprt_co: Int
    let prk_plce_entrc_la: Double
    let prk_plce_entrc_lo: Double
}

 

 

 


✅ present(_:animated:completion:) 설명 정리

이 메서드는 현재 화면 위에 새로운 화면(ViewController)을 모달 방식으로 띄우는 함수예요.


📌 함수 원형

func present(
    _ viewControllerToPresent: UIViewController, 
    animated flag: Bool, 
    completion: (() -> Void)? = nil
)

📌 각 매개변수 설명

번호 매개변수 설명

1️⃣ viewControllerToPresent 새롭게 띄울 화면. 현재 화면 위에 올라감
2️⃣ animated 애니메이션 효과를 줄지 (true/false)
3️⃣ completion 새로운 화면이 완전히 뜬 후 실행할 추가 작업. 없으면 nil (생략 가능)

📌 모달이란?

새 화면이 현재 화면 위에 덮어서 나타나는 방식

  • 예: 팝업, 알림창, 설정창 등
  • 모달은 닫아야 그 아래 화면이 다시 보여요

✅ 예제 1: 기본 사용

present(alert, animated: true, completion: nil)
  • alert라는 뷰 컨트롤러(예: UIAlertController)를
  • 애니메이션과 함께 띄우고,
  • **추가 작업은 없으므로 nil**로 설정

✅ 예제 2: 클로저 생략

present(alert, animated: true)
  • completion 매개변수는 기본값이 nil이라 생략 가능
  • 이건 예제 1과 동일한 동작

✅ 예제 3: 완료 후 작업 추가

present(alert, animated: true) {
    print("새로운 화면이 완전히 떴어요!")
}
  • 새 화면이 다 뜬 후에 print()를 실행

📌 한눈에 요약

용어 의미

모달 현재 화면 위에 덮어서 새 화면을 띄우는 방식
animated 화면 전환에 애니메이션 효과 줄지 여부
completion 새 화면이 나타난 뒤 실행할 추가 작업 (클로저)

 

if let과 guard let은 Swift에서 옵셔널 바인딩을 할 때 사용하는 구문이지만, 사용 목적과 코드의 흐름이 다름.


✅ 1. if let — 조건부 실행

  • 옵셔널 값이 존재할 때만 실행되는 코드 블록을 만들고 싶을 때 사용
  • 바인딩된 값은 if 블록 내부에서만 사용 가능
  • 중첩되기 쉬움

예제:

if let name = optionalName {
    print("이름은 \(name)입니다.")
} else {
    print("이름이 없습니다.")
}

✅ 2. guard let — 조기 탈출(Early Exit)

  • 조건이 실패하면 빠르게 함수 종료 등 처리하고, 성공 시 아래 코드 계속 실행
  • 바인딩된 값은 guard가 있는 블록 이후에서도 사용 가능
  • 코드 흐름을 평평하게 유지 (덜 중첩됨)
  • 주로 함수 안에서 사용

예제:

func greet(_ name: String?) {
    guard let name = name else {
        print("이름이 없습니다.")
        return
    }
    print("안녕하세요, \(name)님!") // name은 여기서 계속 사용 가능
}

🔍 비교 요약

항목 if let guard let

실행 흐름 조건 만족 시 코드 블록 실행 조건 불만족 시 함수 등에서 조기 종료
사용 가능 범위 바인딩된 변수는 if 블록 내부 바인딩된 변수는 이후 전체 범위에서 사용 가능
코드 스타일 중첩 구조 발생 가능 코드 납작하게 유지 (early return)
주로 사용하는 곳 일반적인 조건 검사 시 함수 내부 유효성 검사 등 필수 체크

🧠 언제 어떤 걸 써야 할까?

  • 단순한 조건 분기: if let
  • 필수 조건 만족하지 않으면 일찍 종료해야 하는 경우: guard let → 주로 함수나 메서드 내부에서 사용

💡 생성자 (init)

Swift에서 init은 새로운 객체(인스턴스)를 만들 때 쓰는 함수예요.

struct 학생 {
    var 이름: String

    init(이름: String) {
        self.이름 = 이름
    }
}

이렇게 하면 학생(이름: "민수")처럼 학생을 만들 수 있어요.


❗ 그런데 모든 값으로 학생을 만들 수 있을까요?

예를 들어 이름이 빈 칸("")이면 학생을 만들면 안 되겠죠?

그래서 실패할 수도 있는 생성자를 만들 수 있어요. 그게 바로...


✅ 실패 가능한 생성자 (init?)

init?는 "조건이 맞지 않으면 아예 객체를 못 만들게 하자"라는 뜻이에요.

struct 학생 {
    var 이름: String

    init?(이름: String) {
        if 이름.isEmpty {
            return nil // 실패! 학생을 만들 수 없어
        }
        self.이름 = 이름
    }
}

🎯 어떻게 작동하나요?

let a = 학생(이름: "민수")   // 성공! a는 학생 객체예요
let b = 학생(이름: "")       // 실패! b는 nil이 돼요
  • 이름이 있으면 학생이 만들어지고 (a는 학생)
  • 이름이 없으면 실패해서 아무것도 안 만들어져요 (b는 nil)

📦 왜 필요할까?

어떤 조건을 만족하지 않으면 객체를 만들면 안 되는 상황이 있기 때문이에요.

예:

  • 비밀번호가 너무 짧을 때
  • 나이가 음수일 때
  • 파일 이름이 잘못됐을 때

이럴 땐 init?로 안전하게 "만들 수 없는 건 만들지 마!"라고 말할 수 있어요.


📌 쉽게 정리하면...

내용 설명

init 무조건 객체를 만든다
init? 조건에 따라 실패할 수도 있다 (nil을 반환)
사용 이유 잘못된 값으로 객체가 만들어지는 걸 막기 위해서

실패 가능한 생성자(init?)는 어떤 조건에서 객체를 만들 수 없으면, nil을 반환하는 생성자.

📝 간단하게 설명:

  • 생성자는 객체를 "만드는" 역할을 합니다.
  • 하지만 때때로, 객체를 만들 수 없는 상황이 있을 수 있어요. 예를 들어, 사용자로부터 받는 값이 잘못되었을 때!
  • 이때, init?을 사용하면 조건에 맞지 않으면 객체를 만들지 않고 nil을 반환합니다.

📌 예시 1: 잘못된 값으로 객체 만들지 않기

예를 들어, "나이"를 입력받는 객체가 있다고 할 때, 나이가 음수이면 객체를 만들 수 없어요.

struct 사람 {
    var 나이: Int
    
    init?(나이: Int) {
        if 나이 < 0 {
            return nil  // 나이가 음수면 객체를 만들 수 없음
        }
        self.나이 = 나이
    }
}

✅ 실행:

let a = 사람(나이: 25)   // a는 객체를 만들 수 있음
let b = 사람(나이: -5)   // b는 실패해서 nil이 됨

⚡ 핵심:

  • init?을 사용하면 조건에 맞지 않으면 객체를 만들지 않고 실패하는 방식이에요.
  • 실패하면 nil을 반환합니다.

쉽게 말하면, 잘못된 값으로 객체를 만들지 않도록 하는 방법이 바로 init?입니다!

 

 

 

함수의 자료형? (Int, Int) -> Int

리턴형이 void형이면? (Int, Int) -> ()

 

 

 

함수명? add(first:second:)

 

1급 객체 (First-Class Object) 또는 1급 시민 (First-Class Citizen) 이란, 프로그래밍 언어에서 특정 객체나 개념이 다른 객체와 동일한 수준에서 다뤄질 수 있을 때 사용되는 용어입니다. 즉, 이 객체는 변수에 저장되고, 함수의 매개변수로 전달되며, 함수의 반환값으로 사용될 수 있다는 특성을 가집니다.


1급 객체의 특징

  1. 변수에 저장할 수 있다.
    • 객체나 함수 등을 변수에 저장할 수 있다는 뜻입니다. 예를 들어, 함수나 다른 객체를 변수에 할당할 수 있죠.
    let add = { (a: Int, b: Int) -> Int in return a + b }
    let result = add(3, 5)  // add라는 함수를 변수에 저장하고 사용
    print(result)  // 8
    
  2. 매개변수로 전달할 수 있다.
    • 함수에 매개변수로 객체나 함수를 넘길 수 있다는 의미입니다. 즉, 함수나 객체를 다른 함수의 인자로 전달할 수 있어요.
    func applyOperation(a: Int, b: Int, operation: (Int, Int) -> Int) -> Int {
        return operation(a, b)
    }
    
    let sum = applyOperation(a: 3, b: 5, operation: add)
    print(sum)  // 8
    
  3. 리턴값으로 사용할 수 있다.
    • 함수에서 객체나 함수반환할 수 있습니다. 이때 반환되는 값이 다른 함수에서 사용될 수 있죠.
    func getAddFunction() -> (Int, Int) -> Int {
        return add
    }
    
    let returnedAdd = getAddFunction()
    print(returnedAdd(2, 3))  // 5
    

Swift에서 함수가 1급 객체인 이유

Swift에서 함수는 1급 객체이기 때문에 위의 조건을 모두 만족합니다:

  • 변수에 저장할 수 있습니다.
  • 매개변수로 전달할 수 있습니다.
  • 리턴값으로 사용할 수 있습니다.

이러한 특성 덕분에 Swift에서는 함수를 일급 객체처럼 다루며, 이를 통해 고차 함수를 작성하거나, 함수형 프로그래밍의 패러다임을 쉽게 적용할 수 있습니다.


예시: 함수가 1급 객체인 경우

1) 변수에 저장할 수 있다.

let greet = { (name: String) -> String in return "Hello, \(name)!" }
print(greet("Alice"))  // "Hello, Alice!"

2) 매개변수로 전달할 수 있다.

func greetUser(greeter: (String) -> String, name: String) {
    print(greeter(name))
}

greetUser(greeter: greet, name: "Bob")  // "Hello, Bob!"

3) 리턴값으로 사용할 수 있다.

func getMultiplier() -> (Int) -> Int {
    return { number in number * 2 }
}

let multiplyByTwo = getMultiplier()
print(multiplyByTwo(5))  // 10

📌 결론

1급 객체변수에 저장, 함수의 매개변수로 전달, 함수의 반환값으로 사용될 수 있는 객체를 의미합니다. Swift에서 함수는 1급 객체로 다뤄지므로, 함수 자체도 변수처럼 사용하고, 다른 함수에 전달하고, 다른 함수로부터 반환받을 수 있습니다.

이 특성 덕분에 Swift는 고차 함수를 잘 지원하며, 함수형 프로그래밍에 적합한 언어입니다.

 

func mul(val1: Int, val2: Int) -> Int
 {
 return val1 * val2
 }
 let result = mul(val1:10, val2:20) 
print(result)

클로저 표현식으로 변경하기 

let mul = { (val1: Int, val2: Int) -> Int in
    return val1 * val2
}

let result = mul(10, 20)
print(result)  // 200

 

Swift의 중요한 기능 중 하나인 클로저 표현식


✅ 클로저(Closure)란?

클로저는 간단히 말해서,

“이름 없는 함수” 또는 “변수처럼 다룰 수 있는 코드 덩어리”예요.

함수처럼 어떤 작업을 수행하는 코드 블록인데,
그걸 변수에 담거나 다른 함수에 전달할 수 있는 것이에요.


🔧 클로저 표현식 기본 문법

{ (매개변수들) -> 반환타입 in
    실행할 코드
}

예를 들어, 두 수를 더하는 클로저는 이렇게 쓸 수 있어요:

let add = { (a: Int, b: Int) -> Int in
    return a + b
}
print(add(3, 5))  // 출력: 8

💡 왜 클로저를 사용할까?

  • 간단한 작업을 잠깐 쓰고 싶을 때
  • 함수처럼 전달할 수 있도록 하고 싶을 때
  • 코드가 짧아지고 간단해짐

🧠 클로저 표현식 줄여쓰기

Swift는 클로저 문법을 점점 짧게 쓸 수 있도록 도와줘요.

예제: 배열 정렬

let numbers = [3, 1, 5, 2]

// 1) 일반 함수 사용
func bigger(a: Int, b: Int) -> Bool {
    return a > b
}
let sorted1 = numbers.sorted(by: bigger)

// 2) 클로저 전체 문법
let sorted2 = numbers.sorted(by: { (a: Int, b: Int) -> Bool in
    return a > b
})

// 3) 타입 추론
let sorted3 = numbers.sorted(by: { a, b in return a > b })

// 4) return 생략
let sorted4 = numbers.sorted(by: { a, b in a > b })

// 5) 축약형 인자($0, $1)
let sorted5 = numbers.sorted(by: { $0 > $1 })

// 6) 더 줄이기 (연산자 함수)
let sorted6 = numbers.sorted(by: >)

🎯 정리

특징 설명

이름 없음 함수를 만들지만 이름을 붙이지 않음
변수에 저장 가능 let greet = { ... }
전달 가능 함수에 인자로 넘길 수 있음
표현식 짧아짐 $0, $1 등으로 축약 가능

📌 예시: 클로저를 함수에 전달하기

func printResult(_ operation: (Int, Int) -> Int) {
    let result = operation(4, 2)
    print("결과: \(result)")
}

printResult({ (a, b) in a + b })  // 결과: 6
printResult({ $0 * $1 })         // 결과: 8

Swift의 아주 자주 쓰이는 문법인 후행 클로저


✅ 후행 클로저(Trailing Closure)란?

후행 클로저는 말 그대로,

함수의 마지막 인자가 클로저일 때, 괄호 바깥으로 클로저를 빼서 쓰는 문법이에요.

이렇게 쓰면 코드가 더 깔끔하고 보기 좋아져요.


🔍 기본 클로저 전달 방식

func sayHi(action: () -> Void) {
    action()
}

sayHi(action: {
    print("안녕하세요!")
})

✅ 후행 클로저로 쓰기

sayHi {
    print("안녕하세요!")
}
  • 괄호 안의 action: { ... } 부분을 밖으로 뺀 것이에요.
  • 결과는 완전히 같지만 코드가 더 깔끔하죠!

🎯 왜 쓰냐면?

  • 함수 안에 클로저를 넘길 일이 많을 때,
  • 특히 클로저가 긴 코드일 경우, 가독성이 훨씬 좋아져요.
  • Swift의 UI 코드나 네트워킹 코드에서 아주 자주 사용됩니다.

🧠 예제: 정렬(sorted)

일반 방식

let numbers = [3, 1, 5, 2]
let sorted = numbers.sorted(by: { (a, b) in
    return a < b
})
print(sorted)  // [1, 2, 3, 5]

후행 클로저 방식

let sorted = numbers.sorted {
    $0 < $1
}
print(sorted)

🧪 예제: 애니메이션 (UIKit 예시)

UIView.animate(withDuration: 0.5, animations: {
    myView.alpha = 0
})

→ 후행 클로저로 줄이면:

UIView.animate(withDuration: 0.5) {
    myView.alpha = 0
}

📝 정리

항목 설명

언제 사용? 함수의 마지막 인자가 클로저일 때
장점 코드가 더 짧고, 깔끔하고, 읽기 쉽다
자주 쓰는 곳 정렬, 애니메이션, 네트워크 콜백, SwiftUI 등등

// 1. 일반 함수 정의
func mul(a: Int, b: Int) -> Int {
    return a * b
}

// 2. 클로저를 변수에 저장한 예
let multiply = { (a: Int, b: Int) -> Int in
    return a * b
}

print(mul(a: 10, b: 20))        // 200
print(multiply(10, 20))         // 200

// 3. 덧셈용 클로저
let add = { (a: Int, b: Int) -> Int in
    return a + b
}

print(add(10, 20))              // 30

// 4. 계산용 함수 정의 (클로저를 받아서 계산)
func math(x: Int, y: Int, cal: (Int, Int) -> Int) -> Int {
    return cal(x, y)
}

// 5. 클로저 변수를 매개변수로 전달
var result = math(x: 10, y: 20, cal: add)         // add(10, 20)
print(result)                                     // 30

result = math(x: 10, y: 20, cal: multiply)        // multiply(10, 20)
print(result)                                     // 200

// 6. 클로저를 직접 math 함수의 인자로 작성
result = math(x: 10, y: 20, cal: { (a: Int, b: Int) -> Int in
    return a + b
})
print(result)                                     // 30

// 7. 후행 클로저(Trailing Closure) 방식
result = math(x: 10, y: 20) { (a: Int, b: Int) -> Int in
    return a + b
}
print(result)                                     // 30

 

번호 코드 설명
1 func mul 그냥 기본 함수예요. mul(10, 20) 하면 200을 반환하죠.
2~3 let multiply, let add 이름 없는 함수(클로저)를 변수에 담았어요. 함수처럼 쓸 수 있어요.
4 func math 숫자 2개와 계산 방법(클로저)을 받아서 계산해주는 "계산기 함수"예요.
5 math(x: 10, y: 20, cal: add) add 클로저를 함수에 넘겨서 덧셈 계산했어요.
6 cal: { ... } 클로저를 바로 함수 인자 자리에 작성한 거예요.
7 math(x: 10, y: 20) { ... } 마지막 인자가 클로저라서 후행 클로저 문법으로 바깥에 빼서 썼어요. 코드가 더 깔끔하죠!

 

// 1. 곱셈 클로저를 변수에 저장
let multiply = { (a: Int, b: Int) -> Int in
    return a * b
}

var result = multiply(10, 20)
print(result)  // 200

// 2. 덧셈 클로저
let add = { (a: Int, b: Int) -> Int in
    return a + b
}

result = add(10, 20)
print(result)  // 30

// 3. 클로저를 받아서 계산하는 함수
func math(x: Int, y: Int, cal: (Int, Int) -> Int) -> Int {
    return cal(x, y)
}

// 4. 클로저를 직접 전달 (리턴형 생략)
result = math(x: 10, y: 20, cal: { (val1: Int, val2: Int) in
    return val1 + val2
})
print(result)  // 30

// 5. trailing closure + 리턴형 생략
result = math(x: 10, y: 20) { (val1: Int, val2: Int) in
    return val1 + val2
}
print(result)  // 30

// 6. 매개변수 이름 생략 + 단축 인자($0, $1) 사용
result = math(x: 10, y: 20, cal: {
    return $0 + $1
})
print(result)  // 30

// 7. trailing closure + 단축 인자
result = math(x: 10, y: 20) {
    return $0 + $1
}
print(result)  // 30

// 8. return 생략
result = math(x: 10, y: 20, cal: {
    $0 + $1
})
print(result)  // 30

// 9. 완전히 간단한 형태 (trailing + return 생략)
result = math(x: 10, y: 20) { $0 + $1 }
print(result)  // 30

// 10. 클로저 변수 add, multiply도 다시 사용 가능
result = math(x: 10, y: 20, cal: add)
print(result)  // 30

result = math(x: 10, y: 20, cal: multiply)
print(result)  // 200

// 11. 일반 클로저 작성 (리턴 타입 포함)
result = math(x: 10, y: 20, cal: { (val1: Int, val2: Int) -> Int in
    return val1 + val2
})
print(result)  // 30

// 12. trailing + 리턴 타입 포함
result = math(x: 10, y: 20) { (val1: Int, val2: Int) -> Int in
    return val1 + val2
}
print(result)  // 30