본문 바로가기

iOS-Study

iOS Study : 3주차 - 함수, 제어 구문, 옵셔널

함수

함수선언의 기본 형태

func 함수이름(매개변수1이름: 매개변수1타입, 매개변수2이름: 매개변수2타입 ...) -> 반환타입 {
    /* 함수 구현부 */
    return 반환값
}
// 예)
// sum이라는 이름을 가지고
// a와 b라는 Int 타입의 매개변수를 가지며
// Int 타입의 값을 반환하는 함수
func sum(a: Int, b: Int) -> Int {
    return a + b
}

 

변환 값이 없는 함수

func 함수이름(매개변수1이름: 매개변수1타입, 매개변수2이름: 매개변수2타입 ...) -> Void {
    /* 함수 구현부 */
    return
}
// 예)
func printMyName(name: String) -> Void {
    print(name)
}
// 반환 값이 없는 경우, 반환 타입(Void)을 생략해 줄 수 있습니다
func printYourName(name: String) {
    print(name)
}

 

매개변수가 없는 함수

func 함수이름() -> 반환타입 {
    /* 함수 구현부 */
    return 반환값
}
// 예)
func maximumIntegerValue() -> Int {
    return Int.max
}

 

매개변수와 반환값이 없는 함수

func 함수이름() -> Void {
    /* 함수 구현부 */
    return
}
// 함수 구현이 짧은 경우
// 가독성을 해치지 않는 범위에서
// 줄바꿈을 하지 않고 한 줄에 표현해도 무관합니다
func hello() -> Void { print("hello") }
// 반환 값이 없는 경우, 반환 타입(Void)을 생략해 줄 수 있습니다
func 함수이름() {
    /* 함수 구현부 */
    return
}
func bye() { print("bye") }

 

함수 호출

sum(a: 3, b: 5) // 8
printMyName(name: "yagom") // yagom
printYourName(name: "hana") // hana
maximumIntegerValue() // Int의 최댓값
hello() // hello
bye() // bye

 

매개변수 기본 값

  • 매개변수에 기본적으로 전달될 값을 미리 저장할 수 있다.
  • 기본값을 갖는 매개변수는 매개변수 목록중에 뒤쪽에 위치하는 것이 좋다.
func 함수이름(매개변수1이름: 매개변수1타입, 매개변수2이름: 매개변수2타입 = 매개변수 기본값 ...) -> 반환타입 {
    /* 함수 구현부 */
    return 반환값
}

func greeting(friend: String, me: String = "yagom") {
    print("Hello \(friend)! I'm \(me)")
}

// 매개변수 기본값을 가지는 매개변수는 호출시 생략할 수 있습니다
greeting(friend: "hana") // Hello hana! I'm yagom
greeting(friend: "john", me: "eric") // Hello john! I'm eric

 

전달인자 레이블

  • 함수를 호출할 때 함수 사용자의 입장에서 매개변수의 역할을 좀 더 명확하게 수행하고자 할 때 사용한다.
func 함수이름(전달인자 레이블 매개변수1이름: 매개변수1타입, 전달인자 레이블 매개변수2이름: 매개변수2타입 ...) -> 반환타입 {
    /* 함수 구현부 */
    return
}

// 함수 내부에서 전달인자를 사용할 때에는 매개변수 이름을 사용합니다
func greeting(to friend: String, from me: String) {
    print("Hello \(friend)! I'm \(me)")
}

// 함수를 호출할 때에는 전달인자 레이블을 사용해야 합니다
greeting(to: "hana", from: "yagom") // Hello hana! I'm yagom

 

가변 매개변수

  • 전달 받을 값의 개수를 알기 어려울때 사용할 수 있다.
  • 가변 매개변수는 함수당 하나만 가질 수 있다.
  • 매개변수 타입 뒤에 ... 을 붙여서 사용한다.
func 함수이름(매개변수1이름: 매개변수1타입, 전달인자 레이블 매개변수2이름: 매개변수2타입...) -> 반환타입 {
    /* 함수 구현부 */
    return
}

func sayHelloToFriends(me: String, friends: String...) -> String {
    return "Hello \(friends)! I'm \(me)!"
}
print(sayHelloToFriends(me: "yagom", friends: "hana", "eric", "wing"))
// Hello ["hana", "eric", "wing"]! I'm yagom!

print(sayHelloToFriends(me: "yagom"))
// Hello []! I'm yagom!

 

테이터 타입으로의 함수

스위프트 함수는 일급 객체이기 때문에 변수, 상수 등에 저장 가능하고 매개변수를 통해 전달도 가능하다.

  • 함수의 타입 표현
    • 반환 타입을 생략할 수 없다.
    • (매개변수1타입, 매개변수2타입 ...) -> 반환타입
  • 함수 타입 사용
var someFunction: (String, String) -> Void = greeting(to:from:)
someFunction("eric", "yagom") // Hello eric! I'm yagom

someFunction = greeting(friend:me:)
someFunction("eric", "yagom") // Hello eric! I'm yagom


// 타입이 다른 함수는 할당할 수 없습니다 - 컴파일 오류 발생
//someFunction = sayHelloToFriends(me: friends:)


func runAnother(function: (String, String) -> Void) {
    function("jenny", "mike")
}

// Hello jenny! I'm mike
runAnother(function: greeting(friend:me:))

// Hello jenny! I'm mike
runAnother(function: someFunction)

 

제어 구문

조건문

if-else문

  • 기본 형태
    • if문만 단독적으로 사용해도 되고, else if, else와 조합해서 사용 가능하다.
    • if 뒤의 조건 값에는 Bool타입 값만 위치해야 하며, 조건을 감싸는 소괄호는 선택 사항이다.
    • 중괄호는 생략할 수 없다.
if 조건 {
    /* 실행 구문 */
} else if 조건 {
    /* 실행 구문 */
} else {
    /* 실행 구문 */
}

 

  • if-else문 사용
let someInteger = 100

if someInteger < 100 {
    print("100 미만")
} else if someInteger > 100 {
    print("100 초과")
} else {
    print("100")
} // 100

// 스위프트의 조건에는 항상 Bool 타입이 들어와야합니다
// someInteger는 Bool 타입이 아닌 Int 타입이기 때문에
// 컴파일 오류가 발생합니다
//if someInteger { }

 

switch 구문

  • 각각의 case 내부에는 실행 가능한 코드가 반드시 있어야 한다.
  • 매우 한정적인 값이 비교값이 아닌 한 defaul 구문은 반드시 작성해야 한다.
  • 명시적 break를 하지 않아도 자동으로 case마다 break 된다.
  • fallthrough 키워드를 사용하여 break를 무시할 수 있다.
  • 쉼표(,)를 사용하여 하나의 case에 여러 패턴을 명시할 수 있다.
//기본 형태
switch 비교값 {
case 패턴:
    /* 실행 구문 */
default:
    /* 실행 구문 */
}

//사용
// 범위 연산자를 활용하면 더욱 쉽고 유용합니다
switch someInteger {
case 0:
    print("zero")
case 1..<100:
    print("1~99")
case 100:
    print("100")
case 101...Int.max:
    print("over 100")
default:
    print("unknown")
} // 100

// 정수 외의 대부분의 기본 타입을 사용할 수 있습니다
switch "yagom" {
case "jake":
    print("jake")
case "mina":
    print("mina")
case "yagom":
    print("yagom!!")
default:
    print("unknown")
} // yagom!!

 

반복문

for-in구문

  • 기존 언어의 for-each문과 비슷한다.
//기본 형태
for item in items {
    /* 실행 구문 */
}

//for-in 구문의 사용
var integers = [1, 2, 3]
let people = ["yagom": 10, "eric": 15, "mike": 12]

for integer in integers {
    print(integer)
}

// Dictionary의 item은 key와 value로 구성된 튜플 타입입니다
for (name, age) in people {
    print("\(name): \(age)")
}

 

while문

//while 구문의 기본 형태
while 조건 {
    /* 실행 구문 */
}

//while 구문의 사용
while integers.count > 1 {
    integers.removeLast()
}

 

repeat-while문

  • 기존 언어의 do-while구문과 형태 및 동작이 유사하다
//repeat-while 구문의 기본 형태
repeat {
    /* 실행 구문 */
} while 조건

//repeat-while 구문의 사용
repeat {
    integers.removeLast()
} while integers.count > 0

 

옵셔널

옵셔널

  • 값이 있을 수도 있고 없을 수도 있다라는 것을 뜻한다.
  • nil의 가능성을 명시적으로 표현하기 위해 사용
    • nil 가능성을 문서화 하지 않아도 코드만으로 충분히 표현 가능 -> 문서/주석 작성 시간 절약
    • 전달받은 값이 옵셔널이 아니라면 nil 체크를 하지 않더라도 안전하게 사용 가능 -> 효율적이고 안전한 코딩
  • 옵셔널을 사용할 때 타입 뒤에 ?나 !를 붙여서 사용

암시적 추출 옵셔널(Implicitly Unwrapped Optional)

  • 타입 뒤에 !를 붙여서 사용
var implicitlyUnwrappedOptionalValue: Int! = 100
switch implicitlyUnwrappedOptionalValue {
case .none:
    print("This Optional variable is nil")
case .some(let value):
    print("Value is \(value)")
}

// 기존 변수처럼 사용 가능
implicitlyUnwrappedOptionalValue = implicitlyUnwrappedOptionalValue + 1

// nil 할당 가능
implicitlyUnwrappedOptionalValue = nil

 

옵셔널

  • 타입 뒤에 ?를 붙여서 사용
var optionalValue: Int? = 100

switch optionalValue {
case .none:
    print("This Optional variable is nil")
case .some(let value):
    print("Value is \(value)")
}

// nil 할당 가능
optionalValue = nil

// 기존 변수처럼 사용불가 - 옵셔널과 일반 값은 다른 타입이므로 연산불가
//optionalValue = optionalValue + 1

 

옵셔널 값 추출(Optional Unwrapping)

옵셔널 바인딩(Optional Binding)

  • nil 체크를 함과 동시에 안전한 값 추출 가능
  • if-let 구문을 사용하여 옵셔널 값을 추출한다.
func printName(_ name: String) {
    print(name)
}

var myName: String? = nil

//printName(myName)
// 전달되는 값의 타입이 다르기 때문에 컴파일 오류발생
if let name: String = myName {
    printName(name)
} else {
    print("myName == nil")
}
// name 상수는 if-let 구문 내에서만 사용가능합니다


// ,를 사용해 한 번에 여러 옵셔널을 바인딩 할 수 있습니다
// 모든 옵셔널에 값이 있을 때만 동작합니다
var myName: String? = "yagom
var yourName: String? = nil

if let name = myName, let friend = yourName {
    print("\(name) and \(friend)")
}
// yourName이 nil이기 때문에 실행되지 않습니다
yourName = "hana"

if let name = myName, let friend = yourName {
    print("\(name) and \(friend)")
}
// yagom and hana

 

강제 추출(Forced Unwrapping)

  • 옵셔널의 값을 강제 추출
func printName(_ name: String) {
    print(name)
}

var myName: String? = "yagom"

printName(myName!) //강제 언래핑, yagom

myName = nil
printName(myName)	//값이 nil이므로 오류 발생

var myName: String! = nil	//!로 선언하면 강제 언래핑을 가정하고 선언하는 것
printName(myName)	//!를 붙인 것과 같은 효과를 가짐, nil값이 전달되기 때문에 오류 발생