[Swift] 놓치고 있던 기초 문법 4

‍deprecated·2021년 9월 21일
0

Swift 시작하기

목록 보기
12/12

열거형

연관성 있는 값들을 모아 놓은 것.

enum CompassPoint {
    case north
    case south
    case east, west
}
var direction = CompassPoint.east
direction = .west

switch direction {
case .north: //direction 변수가 north이면
    print("north")
case .south:
    print("south")
case .east:
    print("east")
case .west:
    print("west") 
}

특정 타입의 값을 원시값으로 가지게 하려면 열거형 오른쪽에 타입 명시하면 된다.

enum CompassPoint2: String {
    case north = "북"
    case south = "남"
    case east = "동"
    case west = "서"
}

var direction2 = CompassPoint2.east
switch direction2 {
case .north:
    print(direction2.rawValue)
case .south:
    print(direction2.rawValue)
case .east:
    print(direction2.rawValue)
case .west:
    print(direction2.rawValue)
}

원시값으로 열거형을 반환할 수도 있다.

let direction3 = CompassPoint2(rawValue: "남") // south

열거형은 연관값도 가질 수 있다. 각 항목 옆에 소괄호로 묶어 표현이 가능하다.

enum PhoneError {
    case unknown
    case batteryLow(String)
}
let error = PhoneError.batteryLow("배터리가 곧 방전됩니다.")

// 추출하려면 if case 아니면 switch문
switch error{
case .batteryLow(let message): //연관값 추출
    print(message)
case .unknown:
    print("알 수 없는 에러")
}

옵셔널 체이닝

옵셔널에 속해 있는 nil일지도 모르는 프로퍼티, 메서드, 서브스크립션 등을 가져오거나 호출할 때 사용할 수 있는 일련의 과정.
옵셔널에 값이 있다면 프로퍼티, 메소드 등을 호출할 수 있으며, 값이 없다면 nil을 반환한다.

struct Developer {
    let name: String
}
struct Company {
    let name:String
    var developer:Developer?
}
var company1 = Company(name: "Kakao", developer: nil)
print(company1.developer) // nil


var developer = Developer(name: "Shawn")
var company2 = Company(name: "Kakao", developer: developer)
print(company2.developer) // developer 프로퍼티는 옵셔널 타입임 -> optional로 감싸져있음
//print(company2.developer.name) // 에러발생 : 디벨로퍼 옵셔널이 언래핑되어야 한다는 메세지
print(company2.developer?.name) // ? : 접근한 프로퍼티의 값은 옵셔널로 감싸져있음. 값이 nil일 수도 있어서. 벗겨내고 싶다면 옵셔널 바인딩
print(company2.developer!.name) // ! : 강제 언래핑

try - catch

에러 처리 : 프로그램 내에서 에러가 발생한 상황에 대해 대응하고 이를 복구하는 과정
에러 처리 과정 : 발생(throw) -> 감지(catching) -> 전파(propagating) -> 조작(manipulating)

오류를 처리하는 4가지 방법.

  1. 함수에서 발생한 오류를 해당함수를 호출한 코드에 전파
  2. do catch 구문
  3. optional 값으로 오류 처리
  4. 오류가 발생하지 않을 것이라 확신하고 강제 언래핑
// 열거형을 통해 오류를 표현하는 것이 일반적
enum iPhoneError:Error { // 에러프로토콜 채택
    case unknown
    case batteryLow(batteryLevel:Int) 
}

throw iPhoneError.batteryLow(batteryLevel: 20) // 에러가 발생할 것 같은 지점에 에러를 던져줌 // 실제로 에러 발생.
  • Do - catch
 do {
    try 오류 발생 가능 코드
 } catch 오류 패턴 {
    처리 코드
 }
 
func checkPhoneBatteryStatus(batteryLevel:Int) throws -> String { // throwing 함수. 함수의 반환값이 있다면 이와 같이 Throw 키워드 뒤에 반환값
    guard batteryLevel != -1 else { throw iPhoneError.unknown} // -1이면 else구문 실행 -> iPhoneError를 발생
    guard batteryLevel > 20 else { throw iPhoneError.batteryLow(batteryLevel: 20)}
    return "배터리 상태가 정상입니다."
}

do {
    try checkPhoneBatteryStatus(batteryLevel: 20)
} catch iPhoneError.unknown {
    print("알 수 없는 에러")
} catch iPhoneError.batteryLow(let batteryLevel){
    print("배터리 부족. 남은 배터리 : \(batteryLevel)")
} catch {
    print("그 외 오류 발생 : \(error)")
}
  • try?
    오류를 옵셔널 값으로 변환하여 처리할 수 있다.
    동작하던 코드가 오류를 던지면 그 코드의 반환값은 nil이 된다.
let status = try? checkPhoneBatteryStatus(batteryLevel: -1) // unknown을 던져주기 때문에 status 상태가 nil
print(status) // 출력값 : nil
let status2 = try? checkPhoneBatteryStatus(batteryLevel: 34)
print(status2) // 출력값 : Optional(배터리 상태 정상)
let status3 = try? checkPhoneBatteryStatus(batteryLevel: 19)
print(status3) // nil
  • try!
    오류를 던져주지 않을 것이라 확신
let status4 = try! checkPhoneBatteryStatus(batteryLevel: -1)
print(status4) // 오류발생!

Closure

코드에서 전달 및 사용할 수 있는 독립 기능 블록. 일급 객체의 역할 가능
일급 객체 : 전달인자로 보낼 수 있고, 변수/상수 등으로 저장하거나 전달할 수 있으며, 함수의 반환 값이 될 수도 있다.
보통 Unnamed Closure를 지칭함.

형식 :

{(매개변수) -> 리턴타입 in
    실행구문
}
  • 파라미터와 리턴 타입 둘 다 없는 경우
let hello = { () -> () in // 파라미터와 리턴타입 둘 다 없다
    print("hello")
}
hello()
  • 파라미터와 리턴 타입 존재하는 경우
let hello2 = { (name:String) -> (String) in
    return "Hello, \(name)"
}
//hello2(name:"Shawn") // 에러 : 전달인자 레이블을 적지 않고 파라미터 값 넘겨줘야
hello2("Shawn")
  • 클로저는 함수의 파라미터 타입으로 전달이 가능하다 - 일급객체 특성
func doSomething(closure: () -> ()) {
    closure() // dosomething이 호출되면 closure 실행되게
}
doSomething(closure: {() -> () in
    print("hello~~")
})
  • 반환 타입에 클로저 -> 클로저도 반환 가능.
func doSomething2() ->() -> () {
    return { () -> () in
        print("hello4")
    }
}
doSomething2()()
  • 클로저가 길어지거나 가독성 떨어지면 후행 클로저도 사용한다. 맨 마지막 매개변수로 전달되는 클로저만 후행 클로저로 사용 가능.
func doSomething(closure: () -> ()) {
    closure() // dosomething이 호출되면 closure 실행되게
}
doSomething(closure: {() -> () in
    print("hello~~")
})

doSomething(){
    print("closure too long")
}
doSomething{ // 소괄호도 생략 가능
    print("closure too long")
}

로!

  • 클로저가 여러개라면, 맨 앞 파라미터 레이블은 생략할 수도.
func multipleClosure(success:() -> (), fail: () -> (), neutral:() -> ()){
    
}
multipleClosure {
    <#code#>
} fail: {
    <#code#>
} neutral: {
    <#code#>
}
  • 파라미터를 받아 리턴값을 내놓는 클로저의 다양한 표현법
func doSomething3(closure:(Int, Int, Int) -> Int){
    closure(1,2,3)
}

doSomething3(closure:{(a, b, c) in // 표현 간소화하지 않은 Full version
    return a+b+c
})
doSomething3(closure: { // 데이터타입 생략. 약식인수 사용
    return $0+$1+$2
})
doSomething3(closure: { // 단일 리턴문일경우 리턴타입 생략. 아무것도 다른게 없을 때 가능
    $0+$1+$2
})
doSomething3(){ // 후행클로저 표현으로
    $0+$1+$2
}
doSomething3{ // 클로저가 단 하나만일때
    $0+$1+$2
}

고차함수

다른 함수를 전달인자로 받거나 함수 실행의 결과를 함수로 반환하는 함수이다.
swift 함수는 일급객체 -> 함수의 전달인자로 전달 가능하며, 함수의 결괏값으로 반환할 수도 있다.

스위프트에서 제공하는 고차함수는 3가지로, map, filter, reduce가 있다.

map

// map : 컨테이너 내부의 기존 데이터를 변형하여 새로운 컨테이너를 생성한다.
let numbers = [0,1,2,3]
let mapArray = numbers.map{(number) -> Int in
    return number*2
}
print("map \(mapArray)")

filter

// filter : 컨테이너 내부의 값을 걸러서 새로운 컨테이너로 추출.
let intArray = [1, 3, 20, 156, 4]
let filterArray = intArray.filter { $0 > 5}
print("filter \(filterArray)")

reduce

// reduce : 컨테이너 내부의 요소를 하나로 통합시켜줌.
let someArray = [1,2,3,4,5]
let reduceResult = someArray.reduce(0) { // 초기값을 0으로 설정. result는 누적값을 뜻하고, element는 배열의 요소를 뜻함. 초기값이 0이 아닌2라면 15가 아닌 17이 됨.
    (result: Int, element: Int) -> Int in
    print("\(result) + \(element)")
    return result+element
}
print("reduce \(reduceResult)")

let reduceResult2 = someArray.reduce(0){
    $0-$1
}
print("reduce2 \(reduceResult2)")
profile
deprecated

0개의 댓글