optional binding
- 옵셔널에 할당된 값을 임시 변수 또는 상수에 할당
if let constantname = optionalName{
//옵셔널 변수가 값이 있다면 언래핑해서 일반 상수 constantname에 대입하고 if문 실행
//값이 없다면 if문의 조건이 거짓이 되어 if문을 실행하지 않음
}
if var variablename = optionalName {
//옵셔널 변수가 값이 있다면 언래핑해서 일반 변수 variblename에 대입하고 if문 실행
//값이 없다면 if문의 조건이 거짓이 되어 if문을 실행하지 않음
}
// 예시 코드
var x : Int?
x = 10
if let xx = x { print(x,xx) }
else { print("nil") }
//옵셔널 변수 x가 값(10)이 있으므로 언래핑해서 일반 상수 xx에 대입하고 if문 실행
// 출력 : Optional(10) 10
var x1 : Int?
if let xx = x1 { print(xx) }
else { print("nil") }
//옵셔널 변수 x1이 값이 없어서 if문의 조건이 거짓이 되어 if문 실행하지 않고 else로 감
// 출력 : nil
var x2 : Int?
x2 = 10
if let x2 { print(x2) }
else { print("nil") }
// 출력 : 10
// Swift 5.7 부터는 이런식으로 코드를 작성가능.
guard문
- guard문은 표현식이 거짓(false)로 판단될 경우에 실행 그러므로 꼭 else절 포함해야함
// guard문 예시 코드
guard <불리언 표현식> else {
// 표현식이 거짓일 경우에 실행될 코드
<코드 블록을 빠져 나갈 구문>
}
// 표현식이 참일 경우에 실행되는코드는 이곳에 위치
guard ~ let의 활용
- guard는 return, break, continue, throw 등 제어문 전환 키워드를 쓸 수 있는 상황이라면
사용이 가능 - 그래서 함수 뿐 아니라 반복문 등 특정 블록 내부에 있으면 사용 가능
- 함수 내부에 있다면 보통 return을 써서 해당 함수를 조기에 빠져나오는 조기 출구
용도로 사용
실제 앱을 만들다 보면 옵셔널 바인딩 때문에 다중 if~else를 사용해야 하는데, guard~let을
사용하면 다중 루프 없는 훨씬 가독성이 좋은 코드가 가능해서 그런 경우 많이 사용한다.
// 주의 이런 코드와같이 guard문은 사용하지않는다.
var x = 1
while true {
guard x < 5 else { break } //조건(x<5)이 거짓일 때 실행(break)
print(x) //1 2 3 4, 조건(x<5)이 참일 때 실행
x = x + 1
}
guard let ~ else로 옵셔널 바인딩
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)
multiplyByTen(value: 10)
특징을 보자면 언래핑된 number 변수를 guard문 밖에 있는 코드가 사용할 수 있다!!
만약 if문을 사용한다면 언래핑된 변수는 그렇게 못함.
if let vs guard let
두개의 코드를 먼저 보여 드리겠습니다.
func printName(firstName:String, lastName:String?){
// 외부매개변서 2개인 함수.
// if let
if let lName = lastName { // lastName이 nil이 아닐때
print(lName,firstName)
}else{ print("성이 없네요!") }
// guard let
guard let lName = lastName else { // lastName이 nil일때
print("성이 없네요!")
return // early exit
}
print(lName,firstName)
}// 함수 끝
printName(firstName:"승현", lastName:"김")
printName(firstName: "승현", lastName:nil)
guard let문을 썼을때 코드가 보기 편함
디폴트 매개변수(parameter) 정의하기
- parameter로 전달하는 값이 없는 경우, 디폴트 매개변수 값을 사용
- 함수를 선언할 때 매개변수에 디폴트 값을 할당
//이름이 인자로 전달되지 않을 경우에 디폴트로 "길동"이라는 문자열이 사용되도록 함
// 함수 이름 : sayHello(count:name:)
// 반환형 : String
func sayHello(count: Int, name: String = "길동") -> String {
return ("\(name), 너의 번호는 \(count)")
}
// 이름을 가지고 함수를 호출하면 argument를 사용
print(sayHello(count:10, name: "소프트"))
// 출력 : 소프트, 너의 번호는 10
// 이름을 전달하지 않고도 호출 가능하며 디폴트로 "길동"을 사용
print(sayHello(count:100))
// 출력 : 길동, 너의 번호는 100
함수로부터 여러 개의 결과 반환
- 함수는 여러 결과 값들의 튜플로 감싸서 반환 가능(강점)
// 예시코드
// 함수 이름 : converter(length:)
// 반환형 : tuple
func converter(length: Float) -> (yards: Float, centimeters: Float, meters: Float) {
let yards = length * 0.0277778
let centimeters = length * 2.54
let meters = length * 0.0254
return (yards, centimeters, meters)
}
var lengthTuple = converter(length:10)
// converter함수를 호출해 lengthTuple 변수에 할당.
print(lengthTuple) // 출력 : (yards: 0.277778, centimeters: 25.4, meters: 0.254)
print(lengthTuple.yards) // 출력 : 0.277778
print(lengthTuple.centimeters) // 출력 : 25.4
print(lengthTuple.meters) // 출력 : 0.254
2개의 정수를 입력받아 가감제 리턴
// 함수 이름 : sss(x:y:)
// 반환형 : tuple
import Foundation
func sss(x : Int, y : Int) -> (sum : Int, sub : Int, div : Double, rmd : Int)
{
let sum = x + y
let sub = x - y
let div = Double(x) / Double(y) //같은 자료형만 연산 가능
let rmd = x % y // 나머지 연산
return (sum, sub, div, rmd)
}
var result = sss(x:10,y:3)
// sss함수를 호출해 result 변수에 할당.
print(result.sum) // 출력 : 13
print(result.sub) // 출력 : 7
print(result.div) // 출력 : 3.3333333333333335
print(result.rmd) // 출력 : 1
// swift print format으로 구글링하여 소수점 3자리에서 반올림하는 코드
print(String(format: "%.3f", result.div)) // 출력 : 3.333
// 가감승제,나머지까지 나오도록 소스 수정.
// 이 함수의 자료형 : (Int, Int) -> (sum: Int, sub: Int, div: Double)
가변 매개변수
- 함수가 가변 매개변수를 받는다는 것을 가리키기 위해서 세 개의 점(...) 사용
// 예시코드
func displayStrings(strings: String...)
{
for string in strings{
print(string)
}
}
displayStrings(strings: "일", "이", "삼", "사")
displayStrings(strings: "one", "two")
// 출력 : 일 이 삼 사 one two (줄 바뀜 생략.)
// 임의의 개수의 정수 값의 합을 출력하는 함수
func add(numbers: Int...)
{
var total = 0 // 타입 추론
for num in numbers{
total = total + num
}
print(total)
}
add(numbers:1,2,3) // 출력 : 6
add(numbers:2,2,2,2,2) // 출력 : 10
add(numbers:1,1,1,1,1,1,1,1,1,1) // 출력 : 10
add(numbers:1,1,1,1) // 출력 : 4
inout매개변수 : call by address 구현
- Swift는 기본적으로 call by value
- Swift에서 call by address를 구현하는 방법
- 함수가 값을 반환한 후에도 매개변수에 일어난 변화를 유지하려면, 함수의 선언부에서 매개변수를 입출력 매개변수(in-out parameter)로 선언해야 함
var myValue = 10
// call by address하고 싶은 매개변수의 자료형 앞에 inout 씀
func doubleValue (value: inout Int) -> Int {
value += value
return(value)
}
print(myValue) // 출력 : 10
print(doubleValue(value : &myValue)) // 출력 : 20
print(myValue) // 출력 : 20
이제 함수의 마지막으로 BMI 계산 결과 판정하는 프로그램을 다양한 형태로 만들어보겠습니다.
// 평범한 if-else문을 이용한 코드
let weight = 60.0
let height = 170.0
let bmi = weight / (height*height*0.0001) // kg/m*m
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:\(bmi), 판정:\(body)")
// 츨력 : BMI:20.761245674740483, 판정:정상
// Swift문자열 서식을 이용한 코드
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()함수 정의
import Foundation
func calcBMI(weight : Double, height : Double) -> String{
let bmi = weight / (height*height*0.0001) // kg/m*m
let shortenedBmi = String(format: "%.1f", bmi) // 소수점 1자리 까지 출력
var body = "" // 타입추론(String)
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:82, height: 179.8))
// 출력 : BMI : 25.4, 판정 : 1단계 비만
// switch~case를 이용한 코드
import Foundation
func calcBMI (weight : Double, height : Double) { // Void형(없다는 뜻)
let bmi = weight / (height*height*0.0001) // kg/m*m
let shortenedBmi = String(format: "%.1f", bmi) // 소수점 1자리까지 표현
switch bmi {
// 범위 연산자 사용
case 0.0..<18.5: // 0.0 ~ 18.5 미만
print("BMI:\(shortenedBmi),판정:저체중")
case 18.5..<25.0 : // 18.5 ~ 25.0 미만
print("BMI:\(shortenedBmi),판정:정상")
case 25.0..<30.0 : // 25.0 ~ 30.0 미만
print("BMI:\(shortenedBmi),판정:1단계 비만")
case 30.0..<40.0 : // 30.0 ~ 40.0 미만
print("BMI:\(shortenedBmi),판정:2단계 비만")
default : // 위의 조건이 아무것도 아닐때
print("BMI:\(shortenedBmi),판정:3단계 비만")
}
}
calcBMI(weight:62.5, height: 172.3)
// 출력 : BMI:21.1,판정:정상
// switch~case + 판정 결과 리턴하는 함수
import Foundation
func calcBMI(weight : Double, height : Double) -> String {
let bmi = weight / (height*height*0.0001) // kg/m*m
let shortenedBmi = String(format: "%.1f", bmi)
var body = ""
switch bmi {
case 0.0..<18.5:
body = "저체중"
case 18.5..<25.0:
body = "정상"
case 25.0..<30.0:
body = "1단계 비만"
case 30.0..<40.0 :
body = "2단계 비만"
default :
body = "3단계 비만"
}
return "BMI:\(shortenedBmi), 판정:\(body)"
}
print(calcBMI(weight:60.0, height: 170.0))
// 출력 : BMI:20.8, 판정:정상
// 이 코드가 보기 편하고 제일 간결함
강의 2번째 프린트문 17:31
1급 객체 1급 시민
다음 조건을 충족하는 객체를 1급 객체라고 한다.
- 변수에 저장할 수 있다.
Swift는 함수를 데이터 타입처럼 처리할 수 있음
함수를 상수 또는 변수에 할당하는 것이 가능
함수를 호출하려면 원래의 함수 이름 대신에 상수 이름을 이용하여 호출 가능func inchesToFeet (inches: Float) -> Float { return inches * 0.0833333 } let toFeet = inchesToFeet //함수를 자료형처럼 사용 print(inchesToFeet(inches:10)) print(toFeet(10)) //주의 : argument label인 (inches:) 안 씀
- 매개변수로 전달할 수 있다.
// Int와 Double형을 매개변수로 받아서 String을 반환하는 함수의 데이터 타입
// (Int, Double) -> String // (매개변수형, 매개변수형) -> 리턴형
// 매개변수로 함수를 받으려면, 함수를 받게 될 함수는 함수의 데이터 타입을 선언함
func outputConversion(converterFunc: (Float) -> Float, value: Float) {//함수를 매개변수로 사용
let result = converterFunc(value) //toFeet(10)
print("Result = \(result)")
}
outputConversion(converterFunc:toFeet, value: 10) // 피트로 변환는inchesToFeet함수 호출
- 리턴값으로 사용할 수 있다.
func inchesToFeet (inches: Float) -> Float {
return inches * 0.0833333
}
func inchesToYards (inches: Float) -> Float {
return inches * 0.0277778
}
let toFeet = inchesToFeet
let toYards = inchesToYards
//단위를 변환하고 콘솔에 결과를 출력하는 다른 함수
func outputConversion(converterFunc: (Float) -> Float, value: Float) { //함수를 매개변수로 사용
let result = converterFunc(value)
print("Result = \(result)")
}
// outputConversion 함수를 호출할 때 선언된 데이터 타입과 일치하는 함수를 전달
// 매개변수로 적절한 변환 함수를 전달하면 인치를 피트 또는 야드로 변환하기 위하여 동일한 함수가 호출될 수 있음
outputConversion(converterFunc: toYards, value: 10) // 야드로 변환하는 inchesToYards함수 호출
outputConversion(converterFunc: toFeet, value: 10) // 피트로 변환하는 inchesToFeet함수 호출
//반환 타입으로 함수의 타입을 선언하면 함수도 반환될 수 있음
//다음 함수는 Boolean 매개변수의 값에 따라 toFeet 함수 또는 toYards 함수를 반환
func decideFunction(feet: Bool) -> (Float) -> Float
{ //매개변수형 리턴형이 함수형
if feet{
return toFeet //함수를 리턴
}else{
return toYards
}
}
함수 : 일급 객체 길습
func up(num: Int) -> Int {
return num + 1
}
func down(num: Int) -> Int {
return num - 1
}
let toUp = up
print(up(num:10)) // 출력 : 11
print(toUp(10)) // 출력 : 11
let toDown = down
func upDown(Fun: (Int) -> Int, value: Int){
let result = Fun(value)
print("결과 = \(result)") // 출력 : 결과 = 11
}
upDown(Fun:toUp, value: 10) //toUp(10), 출력 : 결과 = 11
upDown(Fun:toDown, value: 10) //toDown(10), 출력 : 결과 = 9
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), 출력 : 11
클로저 표현식
특정 작업(함수)과 그 작업이 일어난곳(환경 또는 상태)을 모두 기억하고 있는 도구
- 클로저 표현식은 독립적인 코드 블록
// 클로저 표현식은 매개변수를 받거나, 값을 반환하도록 만들 수도 있다
// 클로저 표현식 코드
{func <함수명>(<매개변수 이름>: <매개변수 타입>, … ) -> <반환 타입> in
}
두 개의 정수 매개변수를 받아서 정수 결과 값을 반환
let multiply = {(val1: Int, val2: Int) -> Int in
//매개변수 리턴형
return val1 * val2
}
// 여기서 multiply의 자료형은 (Int, Int) -> Int
let result = multiply(10, 20) //상수를 함수처럼 호출,200
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))
//주의 error: extraneous(관련 없는) argument labels 'x:y:' in call
print(add1(10, 20)) //OK, 출력 : (Int, Int) -> Int
print(type(of:add1)) // 출력 : (Int, Int) -> Int
위의 코드에서 in 키워드는 클로저(closure) 문법의 일부입니다.
Swift에서 클로저를 사용할 때 in 키워드는 중요한 역할을 합니다:
- 목적: in 키워드는 클로저의 매개변수 및 반환 타입 선언부와 실제 클로저 본문을 구분함
- 위치: in 키워드는 클로저의 매개변수 목록과 반환 타입 선언 다음에 위치
- 의미: "이 다음에 오는 코드가 클로저의 실제 구현부입니다"라는 의미를 나타냄
'iOS프로그래밍 (2학년 2학기)' 카테고리의 다른 글
241031 iOS프로그래밍기초 9주차 (5) | 2024.10.31 |
---|---|
241017 iOS프로그래밍기초 7주차 (1) | 2024.10.17 |
241002 iOS프로그래밍기초 5주차 (2) | 2024.10.14 |
240926 iOS프로그래밍기초 4주차 (3) | 2024.09.26 |
240919 iOS 프로그래밍기초 3주차 (0) | 2024.09.19 |