iOS 프로그래밍 6주차

CDH·2024년 10월 9일

출처 : SmileHan - iOS 프로그래밍 기초 강의


복습하기

함수

매개변수 (parameter) 와 인수 (argument)의 차이점

  • 함수나 메서드를 정의할 때와 호출할 때의 관점에서 구분된다

스위프트 공식 사이트 한국어 버전(함수) - https://bbiguduk.gitbook.io/swift/language-guide-1/functions


함수 선언 (void는 생략 가능)


예시코드

func add (x : Int, y : Int) -> Int {
    return(x + y)
}
add (x : 10, y : 20) // swift에서는 argument lable을 항상 적어줘야 됨 (x, y)
print(type(of:add))

결과
(Int, Int) -> Int // add 함수의 타입


내부 매개변수(parameter name) 이름과
외부 매개변수(argument label) 이름


Swift 함수 실습 : and 함수의 type은?


#function 리터럴(literal)


4가지 add함수의 함수명

※ 함수 안에서 #function을 출력할 땐 return문 전에 해야 된다

func add(x : Int, y : Int) -> Int {
	print(#function) // return문 전에 함수 리터럴을 출력해야 함
    return x + y
}
print(add(x : 10, y :20))
print(type(of:add))

함수명 : add(x:y:)

// add함수의 타입 : (Int, Int) -> Int

  • 외부매개변수명(argument label) 생략하면
  • 내부매개변수명(parameter name)이 외부 매개변수명까지 겸함

func add2(first x : Int, second y : Int) -> Int {

    return x + y
} 
print(add2(first:10, second:20))
print(type(of:add2))

함수명 : add2(first:second:)

// add2함수의 타입 : (Int, Int) -> Int

  • first 와 second 는 argument lable에 해당함 (외부 매개변수명, 호출)
  • x와 y는 parameter name에 해당함 (내부 매개변수명, 함수내부)

func add3(_ x : Int, _ y : Int) -> Int {
    return(x + y)
}
print(add3(10, 20)) // x와 y를 (레이블) 표시하지 않고 생략
print(type(of:add3))

함수명 : add3(_:_:)

// add3함수의 타입 : (Int, Int) -> Int

  • 외부매개변수명 생략한다는 의미
  • 다른 언어처럼 호출 가능하지만 추천X


func add4(_ x : Int, with y : Int) -> Int {
    return (x + y)
}
print(add4(10, with : 20))
print(type(of:add4))

함수명 : add4(_:with:)

// add4함수의 타입 : (Int, Int) -> Int

  • 첫번째 외부매개변수명만 생략하는 경우가 많음
  • Objective-C언어의 호출 방식이 이러함
  • 두번째 매개변수부터는 외부매개변수 사용
  • ※ 제일 많이 쓰는 방법

※ 함수의 type이 모두 같고, 함수명이 모두 다르다


ChatGPT 과제

  • iOS 테이블뷰에서 많이 사용하는 메서드를 많이 사용하는 순서대로 나열하고 예를 들어 기능을 설명하고, 전체 메서드 이름과 메서드 자료형을 알려달라고 하기

    1. tableView(:cellForRowAt:)
    셀 구성: 각 행에 표시할 셀을 반환
    자료형: UITableViewCell

    2. tableView(
    :numberOfRowsInSection:)
    행 수 반환: 섹션 내의 행 수를 반환
    자료형: Int

    3. tableView(:didSelectRowAt:)
    행 선택 시 동작: 사용자가 특정 행을 선택할 때 호출
    자료형: Void

    4. numberOfSections(in:)
    섹션 수 반환: 테이블의 섹션 수를 반환
    자료형: Int

    5. tableView(
    :heightForRowAt:)
    셀 높이 설정: 각 행의 높이를 반환
    자료형: CGFloat


참고


(복습 끝) guard let

optional binding

if let이나 if var를 사용하여 Optional값을 안전하게 언래핑할 수 있다.


guard문(조건식이 거짓이면 실행)

- guard문은 표현식이 거짓(false)으로 판단될 경우에 수행될 else 절을 반드시 포함해야 함

  • else 절에 속한 코드는 현재의 코드 흐름을 빠져 나갈 수 있는 구문(return, break, continue, throw 구문)을 반드시 포함해야 함
  • 또는 다른 함수를 else 코드 블록 안에서 호출할 수도 있음

- guard문은 기본적으로 특정 조건에 맞지 않을 경우에 현재의 함수나 반복문에서 빠져 나갈 수 있도록 하는 ‘조기 출구(early exit)’ 전략을 제공


guard~let의 활용

※ guard문은 조건을 정할 때 거짓을 기준으로 함

var x = 1
while true {
    guard x < 5 else {break}
    print(x)
    x += 1
}

결과
1
2
3
4


guard let~else로 옵셔널 바인딩

- guard let~else 에서 조건식이 참일 때 실행하는 문구에서 number 사용 가능

func multiplyByTen(value: Int?) {
    guard let number = value else { // 조건식이 거짓(nil)일 때 else 블록 실행
        print("nil") 
        return
    }
    print(number * 10) /* 조건식이 참일 때 실행, 
    주의: number를 guard문 밖인 여기서도 사용 가능 */
}
multiplyByTen(value: 3)   // 30
multiplyByTen(value: nil)  // nil
multiplyByTen(value: 10)   // 100

if~let vs guard~let

- if~let 은 참 -> 거짓의 순서로, guard~let 은 거짓 -> 참 순서로 작성

if~let

func printNameIfLet(firstName: String, lastName: String?) {
    // if let
    if let lName = lastName { // lastName이 nil이 아니면
        print(lName, firstName)
    } else {
        print("성이 없네요!")
    }
}

printNameIfLet(firstName: "길동", lastName: "홍")
printNameIfLet(firstName: "길동", lastName: nil)

guard~let

func printNameGuardLet(firstName: String, lastName: String?) {
    // guard let
    guard let lName = lastName else { // lastName이 nil이면
        print("성이 없네요!")
        return // early exit
    }
    print(lName, firstName)
}

printNameGuardLet(firstName: "길동", lastName: "홍")
printNameGuardLet(firstName: "길동", lastName: nil)

결과는 둘 다 같음
홍 길동
성이 없네요!


guard let을 사용하는 이유 - 가독성이 더 높음

if let


guard let (중괄호가 현저하게 줄어든다)


디폴트 매개변수(아규먼트) 정의하기

기본적인 코드

func sayHello(count: Int, name: String = "길동") -> String {
    return ("\(name), 너의 번호는 \(count)")
}
var message = sayHello(count:10, name: "소프트") 

print(message) // 소프트, 너의 번호는 10

디폴트를 활용한 코드 (guard let 응용)

  • 아래 코드는 sayHello 함수를 호출했을 때 name의 값을 지정하지 않았지만 처음에 정의한 "길동"이 출력됨
  • count 값이 nil일 경우 "번호가 없습니다" 가 출력됨
func sayHello(count: Int?, name: String = "길동") -> String {
    guard let test = count else {
        return("번호가 없습니다")
    }
    return ("\(name), 너의 번호는 \(test)")
}

var message = sayHello(count:10)
print(message) // 결과 : 길동, 너의 번호는 10

※ Tip : print문 사용 시 개행을 안 하고 싶다면

- terminator 사용하기

예시 코드

for i in 1...5 {
    print(i, terminator: "")
}

결과
12345


함수로부터 여러 개의 결과 반환하기

- 함수는 여러 결과 값들을 튜플로 감싸서 반환할 수 있음

- 인치 단위의 수를 매개변수로 받아 야드, 센티미터, 미터로 변환하고 이 세 개의 값을 하나의 튜플에 넣어 반환

func converter(length: Float) -> (yards: Float, centimeters: Float, meters: Float) {
    let yards = length * 0.02777778
    let centimeters = length * 2.54
    let meters = length * 0.0254
    return (yards, centimeters, meters)
}

var legnthTuple = converter(length:10)
print(legnthTuple)
print(legnthTuple.yards)
print(legnthTuple.centimeters)
print(legnthTuple.meters)

※ 함수 선언 부분과 출력을 반대로 해도(함수 선언이 아래 있어도) 코드가 실행됨


2개의 정수를 입력받아 가감제 리턴 (과제)

import Foundation // format 사용

func sss(x: Int, y: Int) -> (sum: Int, sub: Int, mul: Int, div: Double, mod: Int, roundeDiv: Double)
{
    let sum = x + y
    let sub = x - y
    let mul = x * y
    let div = Double(x) / Double(y) // 같은 자료형만 연산 가능함
    let mod = x % y // 나머지
    
    let roundeDiv = Double(round(1000 * div) / 1000) // 소수점 3자리에서 반올림
    
    return (sum, sub, mul, div, mod, roundeDiv)
}

var result = sss(x:10, y:3)
print(result.sum)
print(result.sub)
print(result.mul) // 곱
print(result.div)
print(result.mod) // 나머지
print(result.roundeDiv) // 소수점 3자리에서 반올림

print(String(format: "%.3f", result.div)) // 사용하려면 import Foundation 선언하기
print(type(of:sss)) // sss 함수의 자료형

결과
13 // result.sum
7 // result.sub
30 // result.mul
3.3333333333333335 // result.div
1 // result.mod
3.333 // String(format: "%.3f", reuslt.div)
3.333 // result.roundeDiv
(Int, Int) -> (sum: Int, sub: Int, mul: Int, div: Double, mod: Int, roundedDiv: Double)


가변 매개변수(variadic parameter)

과제 : 임의의 개수의 정수 값의 합을 출력하는 함수 작성 + 호출하기

func add(numbers:Int...) { // ... (점 3개)를 이용하여 가변매개변수를 선언
    var sum:Int = 0
    for num in numbers{
        sum += num
    }
    print(sum)
}
add(numbers:1, 2, 3, 4, 5, 10)

결과
25


inout매개변수:call by address 구현

- Swift는 기본적으로 call by value

- Swift에서 call by address를 구현하는 방법

- 함수가 값을 반환한 후에도 매개변수에 일어난 변화를 유지하려면, 함수의 선언부에서 매개변수를 입출력 매개변수(in-out parameter)로 선언해야 함


BMI 계산

Swift 문자열 서식(swift string format 자리수)

import Foundation

let weight = 60.0
let height = 170.0
let bmi = weight / (height * height * 0.0001) // kg/m*m 
let shortenedBmi = String(format: "%.1f", bmi) // 소수점 1번 째까지 (자동 반올림)

var body = ""

if bmi >= 40 { 
    body = "3단계 비만"
} else if bmi >= 30 && bmi < 40 {
    body = "2단계 비만"
} else if bmi >= 25 && bmi < 30 {
    body = "1단계 비만"
} else if bmi >= 18.5 && bmi < 25 {
    body = "정상"
} else {
    body = "저체중"
}

print("BMI: \(shortenedBmi), 판정: \(body)")

결과
BMI: 20.8, 판정: 정상


BMI 를 판정하는 calcBMI()함수 정의


calcBMI() 함수

import Foundation

func calcBMI(weight: Double, height: Double) -> String { // 반환 String으로
    let bmi = weight / (height * height * 0.0001) // kg/m*m 
    let shortenedBmi = String(format: "%.1f", bmi) 
    var body = ""

    if bmi >= 40 { 
        body = "3단계 비만"
    } else if bmi >= 30 && bmi < 40 {
        body = "2단계 비만"
    } else if bmi >= 25 && bmi < 30 {
        body = "1단계 비만"
    } else if bmi >= 18.5 && bmi < 25 {
        body = "정상"
    } else {
        body = "저체중"
    }

    return "BMI: \(shortenedBmi), 판정: \(body)"
}

print(calcBMI(weight: 62.5, height: 172.3))

주의할 점
1. 함수의 return형을 String으로 하기
2. 함수에서 벗어난 후 print(출력)을 해줘야 값이 나옴


switch ~ case

위 코드는 case 별로 출력을 함 (권장 X)

위 코드와 같이 결과값만 대입 후 마지막에 값을 return하고, 마지막에 출력(print)하는 것이 좋음


1급 객체(first class object)
1급 시민(first class citizen)


1급 객체(first class object) 또는 1급 시민(first class citizen)

- https://en.wikipedia.org/wiki/First-class_citizen

- Swift의 함수는 1급 객체이다.
1급 객체(first class object) 또는 1급 시민(first class citizen)

- 다음 조건을 충족하는 객체를 1급 객체라고 한다.

1) 변수에 저장할 수 있다.
2) 매개변수로 전달할 수 있다.
3) 리턴값으로 사용할 수 있다


함수 : 일급 객체 실습

func up(num: Int) -> Int {
    return num + 1
}

func down(num: Int) -> Int {
    return num - 1
}

let toUp = up
print(up(num: 10))
print(toUp(10))
print(type(of:up)) // toup도 똑같이 (Int) -> Int 로 나옴

let toDown = down 

func upDown(Fun: (Int) -> Int, value: Int) { 
    let result = Fun(value)
    print("결과 = \(result)")
}

upDown(Fun: toUp, value: 10)   // toUp(10)
upDown(Fun: toDown, value: 10) // toDown(10)

func decideFun(x: Bool) -> (Int) -> Int { 
    // 매개변수형 리턴형이 함수형
    if x {
        return toUp
    } else {
        return toDown
    }
}

let r = decideFun(x: true) // let r = toUp
print(type(of: r))         // (Int) -> Int
print(r(10))               // toUp(10)

Swift의 함수는 1급 객체이다.
1급 객체(first class object) 또는 1급 시민(first class citizen)
다음 조건을 충족하는 객체를 1급 객체라고 한다.
1) 변수에 저장할 수 있다.
2) 매개변수로 전달할 수 있다.
3) 리턴값으로 사용할 수 있다.

결과
11
11
(Int) -> Int
결과 = 11
결과 = 9
(Int) -> Int
11


사진 참조 1

사진 참조 2

사진 참조 3

사진 참조 4


클로저(Closure)

클로저 표현식 (과제)

일반적인 형식

func add(x: Int, y: Int) -> Int {
    return(x+y)
}
print(add(x:10, y:20))
print(type(of:add))

결과
30
(Int, Int) -> Int

클로저 형식 (Closure)

let add1 = {(x: Int, y: Int) -> Int in
    return(x+y)
}
print(add1(10, 20)) // x: 과 y:를 쓰지 않음
print(type(of:add1)) // 과제

결과
30
(Int, Int) -> Int

해당 코드의 결과 : 200

0개의 댓글