스위프트 고차함수 swift higher-order function



import Swift


/*

 - 고차함수

 전달인자로 함수를 전달받거나

 함수실행의 결과를 함수로 반환하는 함수

 

 map, filter, reduce

 

 */


// - map

// 컨테이너 내부의 기존 데이터를 변형(transform)하여 새로운 컨테이너 생성


let numbers: [Int] = [0,1,2,3,4]

var doubledNumbers: [Int]

var strings: [String]


// for 구문 사용

doubledNumbers = [Int]()

strings = [String]()


for number in numbers {

    doubledNumbers.append(number * 2)

    strings.append("\(number)")

}


print(doubledNumbers) // [0,2,4,6,8]

print(strings) // ["0","1","2","3","4"]


// map 메서드 사용

// numbers의 각 요소를 2배하여 새로운 배열 반환

doubledNumbers = numbers.map({ (number: Int) -> Int in

    return number * 2

})


// numbers의 각 요소를 문자열로 변환하여 새로운 배열 반환

strings = numbers.map({ ( number: Int) -> String in

    return "\(number)"

})


print(doubledNumbers)

print(strings)



// 매개변수, 반환 타입, 반환 키워드(return) 생략, 후행 클로저

doubledNumbers = numbers.map { $0 * 2 }


print(doubledNumbers)


// - filter

// 컨테이너 내부의 값을 걸러서 새로운 컨테이너로 추출


// for 구문 사용

// 변수 사용에 주목하세요

var filtered: [Int] = [Int]()


for number in numbers {

    if number % 2 == 0 {

        filtered.append(number)

    }

}


print(filtered)


// filter 메서드 사용

// numbers의 요소 중 짝수를 걸러내어 새로운 배열로 반환

let evenNumbers: [Int] = numbers.filter {

    (number: Int) -> Bool in

    return number % 2 == 0

}


print(evenNumbers) // [0, 2, 4]


// 매개변수, 반환 타입, 반환 키워드(return) 생략, 후행 클로저

let oddNumbers: [Int] = numbers.filter{

    $0 % 2 != 0

}


print(oddNumbers) // [1, 3]


//MARK: - reduce

// 컨테이너 내부의 콘텐츠를 하나로 통합


let someNumbers: [Int] = [2, 8, 15]


//MARK: for 구문 사용

//변수 사용에 주목하세요

var result: Int = 0


// someNumbers의 모든 요소를 더합니다.

for number in someNumbers {

    result += number

}


print(result) // 25


//MARK: reduce 메서드 사용

// 초기값이 0 이고 someNumbers 내부의 모든 값을 더합니다.

let sum: Int = someNumbers.reduce(0, {

    (first: Int, second: Int) -> Int in

    return first + second

})


print(sum) // 25


// 초기값이 0이고 someNumbers 내부의 모든 값을 뺍니다.

var subtract: Int = someNumbers.reduce(0, {

    (first: Int , second: Int ) -> Int in

    return first - second

})


print(subtract) // -25


// 초기값이 3이고 someNumbers 내부의 모든 값을 더합니다.

let sumFromThree = someNumbers.reduce(3) { $0 + $1}


print(sumFromThree) // 28


// 모든 값을 곱하고 싶을 때

print(someNumbers.reduce(1) { $0 * $1}) // 240



스위프트 오류처리 swift Error




import Swift


/*

 Error 프로토콜과 (주로) 열거형을 통해서 오류를 표현합니다.

 


 enum 오류종류이름: Error {

    case 종류1

    case 종류2

    case 종류3

 }

 

 */



// 자판기 동작 오류의 종류를 표현한 VendingmachinError 열거형


enum VendingMachineError: Error {

    case invalidInput

    case insufficientFunds(moneyNeeded: Int)

    case outOfStock

}


/*

 자판기 동작 도중 발생한 오류 던지기

 오류 발생의 여지가 있는 메서드는 throws를 사용하여

 오류를 내포하는 함수임을 표시합니다.

 */


class VendingMachine {

    let itemPrice: Int = 100

    var itemCount: Int = 5

    var deposited: Int = 0

    

    // 돈 받기 메서드

    func receiveMoney(_ money: Int ) throws {

        

        // 입력한 돈이 0 이하면 오류를 던집니다.

        guard money > 0  else {

            throw VendingMachineError.invalidInput

        }

        

        // 오류가 없으면 정상처리를 합니다.

        self.deposited += money

        print("\(money)원 받음")

    } // 300원 받음

    

    // 물건 팔기 메서드

    func vend(numberOfItems numberOfItemsToVend: Int) throws -> String {

        

        // 원하는 아이템의 수량이 잘못 입력되었으면 오류를 던집니다.

        guard numberOfItemsToVend > 0 else {

            throw VendingMachineError.invalidInput

        }

        

        // 구매하려는 수량보다 미리 넣어둔 돈이 적으면 오류를 던집니다.

        guard numberOfItemsToVend * itemPrice <= deposited else {

            let moneyNeeded: Int

            moneyNeeded = numberOfItemsToVend * itemPrice - deposited

            

            throw VendingMachineError.insufficientFunds(moneyNeeded: moneyNeeded)

        }

        

        // 구매하려는 수량보다 요구하는 수량이 많으면 오류를 던집니다.

        guard itemCount >= numberOfItemsToVend else {

            throw VendingMachineError.outOfStock

        }

        

        // 오류가 없으면 정상처리를 합니다.

        let totalPrice = numberOfItemsToVend * itemPrice

        

        self.deposited -= totalPrice

        self.itemCount -= numberOfItemsToVend

        

        return "\(numberOfItemsToVend)개 제공함"

    }

}


// 자판기 인스턴스

let machine: VendingMachine = VendingMachine()


// 판매 결과를 전달받은 변수

var result: String?


/*

 - 오류처리

오류발생의 여지가 있는 throws 함수(메서드)는

try를 사용하여 호출해야 합니다.

try, try?, try!

 

 - do-catch

 오류발생의 여지가 있는 throws 함수(메서드)는

 do-catch 구문을 활용하여 오류발생에 대비합니다.

 

 */


do {

    try machine.receiveMoney(0)

}catch VendingMachineError.invalidInput {

    print("입력이 잘못되었습니다.")

}catch VendingMachineError.insufficientFunds(let moneyNeeded){

    print("\(moneyNeeded)원이 부족합니다")

}catch VendingMachineError.outOfStock {

    print("수량이 부족합니다")

} // 입력이 잘못되었습니다.


do {

    try machine.receiveMoney(300)

}catch /*(let error)*/ {

    switch error {

    case VendingMachineError.invalidInput:

        print("입력이 잘못되었습니다.")

    case VendingMachineError.insufficientFunds(let moneyNeeded):

        print("\(moneyNeeded)원이 부족합니다")

    case VendingMachineError.outOfStock:

        print("수량이 부족합니다")

    default:

        print("알수없는 오류 \(error)")

        

    }

} // 300원 받음


do {

    result = try machine.vend(numberOfItems: 4)

}catch {

    print(error)

} // insufficientFunds(100)


do {

    result = try machine.vend(numberOfItems: 4)

}



/*

 try?

 별도의 오류 처리 결과를 통보받지 않고

 오류가 발생했으면 결과값을 nil로 돌려받을 수 있습니다.

 정상동작 후에는 옵셔널 타입으로 정상 반환값을 돌려 받습니다.

 */


result = try? machine.vend(numberOfItems: 2)

result // Optional("2개 제공함")


result = try? machine.vend(numberOfItems: 2)

result // nil



/*

 try!

 오류가 발생하지 않을 것이라는 강력한 확신을 가질 때

 try!를 사용하면 정상동작 후에 바로 결과값을 돌려받습니다.

 오류가 발생하면 런타입 오류가 발생하여

 애플리케이션 동작이 중지됩니다.

 

 */


result = try! machine.vend(numberOfItems: 1)

result // 1개 제공함


//result = try! machine.vend(numberOfItems: 1)






//

//  Question.swift

//  DISCTest

//

//  Created by stayfoolish on 08/10/2018.

//  Copyright © 2018 stayfoolish. All rights reserved.

//


import UIKit


struct Question: Codable {

    let d: String

    let i: String

    let s: String

    let c: String

}


extension Question {

    static var all: [Question] = {

        guard let dataAsset: NSDataAsset = NSDataAsset(name: "Questions") else {

            return []

        }

        

        let jsonDecoder: JSONDecoder = JSONDecoder()

        do {

            return try jsonDecoder.decode([Question].self, from: dataAsset.data)

        } catch {

            return[]

        }

    }()

}


//

//  Result.swift

//  DISCTest

//

//  Created by stayfoolish on 08/10/2018.

//  Copyright © 2018 stayfoolish. All rights reserved.

//


import UIKit


struct Result: Codable {

    static let shared: Result? = Result()

    

    let d: Info

    let i: Info

    let s: Info

    let c: Info

    

    private init?() {

        guard let dataAsset: NSDataAsset = NSDataAsset(name: "Result") else {

            return nil

        }

        

        do {

            let result: Result = try JSONDecoder().decode(Result.self , from: dataAsset.data)

            self = result

        } catch {

            return nil

        }

    }

}


extension Result {

    struct Info: Codable {

        let title: String

        let typeDescription: String

    }

}





//

//  UserInfo.swift

//  DISCTest

//

//  Created by stayfoolish on 08/10/2018.

//  Copyright © 2018 stayfoolish. All rights reserved.

//


import Foundation


class UserInfo {

    static let shared: UserInfo = UserInfo()

    

    var name: String!

    var score: Score = Score()

    

    var hightestScoreResult: Result.Info? {

        let hightest: Int = max(self.score.d, self.score.i, self.score.s, self.score.c)

        switch hightest{

        case self.score.d:

            return Result.shared?.d

        case self.score.i:

            return Result.shared?.i

        case self.score.s:

            return Result.shared?.s

        default:

            return Result.shared?.c

        }

    }

    

    var scorePercentageText: String {

        

        let sum: Double = Double(self.score.d + self.score.i + self.score.s + self.score.c)

        let percentageD = Double(self.score.d) / sum * 100

        let percentageI = Double(self.score.i) / sum * 100

        let percentageS = Double(self.score.s) / sum * 100

        let percentageC = Double(self.score.c) / sum * 100

        

        return String(format: "D: %.0lf%%, I : %.0lf%%, S : %.0lf%%, C : %.0lf%%",

                    percentageD,

                    percentageI,

                    percentageS,

                    percentageC)

    }

    

}


extension UserInfo {

    class Score {

        var d: Int = 0

        var i: Int = 0

        var s: Int = 0

        var c: Int = 0

    }

    

    func reset() {

        self.score.d = 0

        self.score.i = 0

        self.score.s = 0

        self.score.c = 0

        self.name = nil

    }

    

    enum ScoreType {

        case d, i, s, c

    }

}


//

//  ResultViewController.swift

//  DISCTest

//

//  Created by stayfoolish on 08/10/2018.

//  Copyright © 2018 stayfoolish. All rights reserved.

//


import UIKit



class ResultViewController: UIViewController {


    @IBOutlet weak var nameLabel: UILabel!

    @IBOutlet weak var percentageLabel: UILabel!

    @IBOutlet weak var titleLabel: UILabel!

    @IBOutlet weak var descriptionTextView: UITextView!

    

    override func viewWillAppear(_ animated: Bool) {

        super.viewWillAppear(animated)

        

        self.nameLabel.text = UserInfo.shared.name

        self.percentageLabel.text = UserInfo.shared.scorePercentageText

        

        guard let result: Result.Info = UserInfo.shared.hightestScoreResult else { return }

        

        self.titleLabel.text = result.title

        self.descriptionTextView.text = result.typeDescription

    }

    

    

    @IBAction func touchUpDismissButton(_ sender: UIButton) {

        self.navigationController?.presentingViewController?.dismiss(animated: true, completion: nil)

    }



    override func didReceiveMemoryWarning() {

        super.didReceiveMemoryWarning()

        // Dispose of any resources that can be recreated.

    }

    


    /*

    // MARK: - Navigation


    // In a storyboard-based application, you will often want to do a little preparation before navigation

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        // Get the new view controller using segue.destinationViewController.

        // Pass the selected object to the new view controller.

    }

    */


}


//

//  QuestionViewController.swift

//  DISCTest

//

//  Created by stayfoolish on 08/10/2018.

//  Copyright © 2018 stayfoolish. All rights reserved.

//


import UIKit


class QuestionViewController: UIViewController {

    

    // 인터페이스 빌더에서 설정한 버튼의 tag

    enum ButtonTag: Int {

        case d = 101

        case i, s, c

    }

    // 몇번째 질문인지 확인하기 위해 변수 설정

    var questionIndex: Int!

    

    @IBOutlet weak var backButton: UIButton!

    


    

    @IBAction func touchUpBackButton(_ sender: UIButton) {

        self.navigationController?.popViewController(animated: true)

    }

    

    @IBAction func touchUpAnswerButton(_ sender: UIButton) {

        

        guard let tag: ButtonTag = ButtonTag(rawValue: sender.tag) else {

            return

        }

        

        switch tag {

        case .d:

            UserInfo.shared.score.d += 1

        case .i:

            UserInfo.shared.score.i += 1

        case .s:

            UserInfo.shared.score.s += 1

        case .c:

            UserInfo.shared.score.c += 1

        }

        

        let nextIndex: Int = self.questionIndex + 1

        

        if Question.all.count > nextIndex,

            let nextViewController: QuestionViewController = self.storyboard?.instantiateViewController(withIdentifier: "QuestionViewController") as? QuestionViewController { nextViewController.questionIndex = nextIndex

            self.navigationController?.pushViewController(nextViewController, animated: true)

        } else {

            self.performSegue(withIdentifier: "ShowResult", sender: nil)

        }

        

    }

    

    override func viewWillAppear(_ animated: Bool) {

        super.viewWillAppear(animated)

        

        self.questionIndex = self.questionIndex ?? 0

        

        if self.questionIndex < 1 {

            self.backButton.isHidden = true

        }

        

        let question: Question = Question.all[questionIndex]

        

        guard let dButton: UIButton = self.view.viewWithTag(ButtonTag.d.rawValue) as? UIButton else { return }

        dButton.setTitle(question.d, for: UIControlState.normal)

        

        guard let iButton: UIButton = self.view.viewWithTag(ButtonTag.i.rawValue) as? UIButton else { return}

        iButton.setTitle(question.i, for: UIControlState.normal)

        

        guard let sButton: UIButton = self.view.viewWithTag(ButtonTag.s.rawValue) as? UIButton  else { return }

        sButton.setTitle(question.s, for: UIControlState.normal)

        

        guard let cButton: UIButton = self.view.viewWithTag(ButtonTag.c.rawValue) as? UIButton else { return }

        cButton.setTitle(question.c, for: UIControlState.normal)

    }

    

    override func viewDidLoad() {

        super.viewDidLoad()


        // Do any additional setup after loading the view.

    }


    override func didReceiveMemoryWarning() {

        super.didReceiveMemoryWarning()

        // Dispose of any resources that can be recreated.

    }

    


    /*

    // MARK: - Navigation


    // In a storyboard-based application, you will often want to do a little preparation before navigation

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        // Get the new view controller using segue.destinationViewController.

        // Pass the selected object to the new view controller.

    }

    */


}


//

//  ViewController.swift

//  DISCTest

//

//  Created by stayfoolish on 08/10/2018.

//  Copyright © 2018 stayfoolish. All rights reserved.

//


import UIKit


class ViewController: UIViewController {


    @IBOutlet weak var nameField: UITextField!

    @IBAction func touchUpStartButton(_ sender: UIButton) {

        guard let name: String = self.nameField.text,

        name.isEmpty == false else {

            let alert: UIAlertController

            alert = UIAlertController(title: "알림", message: "이름을 입력해주세요", preferredStyle: .alert)

            

            let okAction: UIAlertAction

            okAction = UIAlertAction(title: "확인", style: .cancel, handler: nil)

            

            alert.addAction(okAction)

            self.present(alert, animated: true, completion: nil)

            return

        }

        UserInfo.shared.name = self.nameField.text

        

        self.performSegue(withIdentifier: "PresentTest", sender: nil)

    }

    

    override func viewDidLoad() {

        super.viewDidLoad()

        // Do any additional setup after loading the view, typically from a nib.

    }

    

    override func viewWillAppear(_ animated: Bool) {

        super.viewWillAppear(animated)

        

        self.nameField.text = nil

    }


    override func didReceiveMemoryWarning() {

        super.didReceiveMemoryWarning()

        // Dispose of any resources that can be recreated.

    }



}







+ Recent posts