Swift 언어 총정리

Yoon Yeoung-jin·2022년 3월 6일
0

iOS 개발

목록 보기
2/11

Swift 언어의 특징

safe type 이다.

  • 타입 안전한, 강타입, 타입이 엄격하다.
  • 변수를 처음 만들때의 선언된 형식을 변경할 수 없다.
ex.
var str = "hello" 
str = 123 <-- error 

Type Annotations

  • 타입을 명시해주는 거라고 생각하자.
ex. 
var myAge: Int = 0
var screenHeight: Float = 560

var vs let

  • var: 변할수 잇는 값을 저장하는 변수를 선언
  • let: const 와 동일

booleans

  • true or false
ex.
var isOpen = false
if isOpen { <-- !isOpen 하면 기존 false 가 true 로 변함 
    /* code */
} else {
    /* code */
}

Tuples

  • ( , ) 의 형태
ex. 
var topTitle = ("main", "mainIcon.png")
                  |           |
                  0           1
topTitle.0  --> main
topTitle.1. --> mainIcon.png

/* dictionary 처럼 키를 지정할 수 있다. */
vat httpError = (statusCode: 404, description: "not found")
httpError.statusCode
httpError.decription

optional

  • 값이 있을수도 있고 없을수도 있다.
  • 값이 있다.
    - 0 --> 다쓴 상태인 값
  • 값이 없다.
    - NULL --> 값이 아에 없는 상태
var myAge: Int? = 0 <-- int 타입이긴 한데 값이 없을 수도 있다. (?)

 myAge = nill <-- 위 처럼 옵셔널을 해주어야지 에러가 안난다.

// 값이 없는 상태 체크 --> 하지만 이렇게 하면 틀릭 로직이다. (Swift 언어 스팩)
if myAge == 0 {
    // alert - 나이를 입력해 주세요.
}

if myAge == nil {
    // alert - 나이를 입력해 주세요.
}
  • 옵셔널은 그냥 사용할 수 없는 경우가 많이 있다.
var a: Int? = 10
var b: Int? = 20
var sum = a + b 
- unwrapped or unwrapping
	- Int? -> Int
	- String? -> String
- 이러한 에러를 해결하려면 다음과 같이 하면됨
	- var sum = (a ?? 0) + (b ?? 0) : coalesce
	- var sum = a! + b!: force unwrap 
		- 주의사항: 값이 무조건 있는 상태로 가정한다. --> 값이 없는 상태면 예외상황이 발생한다. 
		- 값이 무조건 있을때만 사용하자. 아니면 앱이 죽는다. 
	- if Statements 를 사용한다. 
var a: Int? = 20
if a != nil {
    print(a) --> Optional(20) 으로 출력됨
}

if let hasNumber = a {
    print(hasNumber) --> 20으로 출력됨
}

if var hasNumber = a { --> unwrapping 도 해주고 var 로 선언했기 때문에 변수 수정이 가능하다. 
    hasNumber = hasNumber * 2
    print(hasNumber) --> 20으로 출력됨
}
	- guard 사용 : class 나 function 안에 쓴다. 
		- 함수의 시작부분에 써서 반드시 가져가야할 조건들을 검사하는 파트
		- 조건이 True 이면 guard 문은 그냥 지나가고, false 이면 else 구문을 수행한 뒤 함수를 바로 종료한다. 
func testFunc(){
    guard let hasNumber = a else{
        return 
    }
    print(hasNumber)
    print("end")
}

기초 연산자

  • +, -, *, /
  • %: trunctaiong reminder operation
  • 주의사항: c언어 처럼 변수의 타입을 주의하자., 변수 타입을 통일해야 한다. (type safe)

비교 연산자

  • ==, 부등호 등등...

유니코드

  • 조건: 숫자만 입력받을 수 있어야 한다.
let inputValue = "7"

"\u{30}" == "0" --> true
if inputValue >= "\u{30}" && inputValue <= "\u{39}" {
    print("숫자다")
}else{
    print("숫자가 아니다")
}
  • 알파벳 : "\u{41}" ~ "\u{7a}"

String

  • 문자열의 문자 하나하나를 가지고 오려면 다음과 같이 하면 된다.
let myName = "yoon yeoung jin"
for character in myName {
    print(character)
}
  • 문자열의 '+' 은 두 문자열을 붙이는 역할을 한다.
  • value.description --> value를 string 으로 변환해준다.
let isOn = true
isOn.description --> "true"
let myNumber = 123
myNumber.description --> "123"
  • 문자열 안에 값을 넣고싶다. ==> (변수)
let myNumber = 123
"my number is \(myNumber)"
  • 문자열 나누기 --> split(separator: "")
let myNumber = 12.33
myNumber.split(separator: ".") ==> ["12", "33"]

collection type

  1. array
    • 선언 방법: var myName = Array() or var myName = Int
var myNames = Array<String>()
var myAges = [Int]()
- .append() 를 사용해서 데이터를 넣는다. 
myNames.append("yoon")
myNames.append("yeoung")
myNames.append("jin)
- index 개념으로 접근
- index out of range에 대한 방어 코드를 만드는 것이 매우매우 좋다.  (안전한 코딩 스타일)
let index = 3
if myNames.count > index { // out of range에 대한 방어 코드 추가.
    print(myNames[index])
}
- .append(contentsOf: array): array 자체를 넣는다. 
myNames.append(contentsOf: ["hi", "hello"]) ==> ["yoon", ..., "hello"]
myNames + ["hi", "hello"]
- .remove() : 값을 지움 (first, last, all)
- .isEmpty: 리스트 안에 값이 없는지 확인하는 함수
- .insert(value, at: int): int 자리에 값을 넣는다.
- for문으로 하나한 값을 추출할 수 있다. 
- .enumerated(): index와 value를 둘다 가져올 수 있다. 
for (index, name) in myNames.enumerated() {
    print(index, name)
}
  1. set
    • 기본 형태: var names = Set()
    • set은 순서를 보장하지 않는다.
    • 값이 동일한 건 중첩되서 넣어지지 않는다.
    • .insert() 를 사용해서 데이터를 넣는다.
var numbers1: Set = [1,2,3,4,5]
var numbers2: Set = [4,5,6,7,8]

numbers1.intersection(numbers2) // 교집합
numbers1.union(numbers2)        // 합집합
numbers1.symmetricDifference(numbers2) // 대칭차집합
numbers1.subtracting(numbers2) // 여집합
  1. dictionary
    • 키-value 형식으로 되어있음
    • 순서 정의 개념이 없다.
    • 선언 방법 : var nameOfStreet = String : String (Any: 어떤 타입이든 상관 없다는 의미)
    • 결과값은 무조건 optional 이다. nil 값이 있을 수 있음
    • crash 부분은 신경 안써도 됨. (값이 있고 없고만 생각하면 됨.)
    • nil 넣으면 해당 값이 없으니까 키도 없어진다.
    • .keys ==> 키 값 리스트를 가져올 수 있음

Control Flow (흐름 제어)

  • for, if, switch, while
for index in 0..<5 { <-- 0 1 2 3 4
    print(index)
}
  • while : 왠만하면 사용하지 않는게 좋다.
    - 무한으로 반복문안에서 계속 실행되는 경우 -> 멈춰버림.
while condition {
    // code..
}

function

  • class 와 sturcture 안에도 만들 수 있다.
    - 계산기 만들기 --> class
    - 더하기 기능 --> function
  • 선언
let a = 10
func plus(num1: Int){
    print("받은값", num1)
}

plus(num1: a)
let a = 10
let b = 20
func plus(num1: Int, num2: Int) -> Int{ <-- 리턴 값을 받고 싶을  -> <type> 을 넣어주면 된다. 
    print("sum = ", num1 + num2)
    return num1 + num2
}

plus(num1: a, num2: b)
func plus(num1: Int, num2: Int) -> (String, Int) { <-- 여러개의 결과값 리턴
    return ("결과값은", num1 + num2)
}
func plus(_ num1: Int, _ num2: Int) -> (String, Int) { <-- argument label 을 밖에서 안써도 됨
    return ("결과값은", num1 + num2)
}

plus(a,b)
  • View, present, Display : 화면에 뿌려주는 로직.
  • 화면에 뿌려주는 로직도 많이 필요하다.
let a = 10
let b = 20

func plus(_ num1: Int, _num2: Int) -> Int {
    return num1 + num2
}

func minus(_ num1: Int, _num2: Int) -> Int {
    return num1 - num2
}

func multiply(_ num1: Int, _num2: Int) -> Int {
    return num1 * num2
}

var inputButtonType = "+"

if inputButtonType == "+"{
    printf("연산 결과", plus(a,b))
}else if inputButtonType == "-"{
    print("연산 결과", minus(a,b))
}else if inputButtonType == "*"{
    print("연산 결과", multiply(a,b))
}
// 위와 같이 형식이 비슷한 함수를 계속 사용하기에는 유지보수에 좋지 않다. 이를 다음과 같이 할 수 있다. 

func displayCalc(result: (Int, Int) -> Int){ <-- 함수를 입력받을 수 있게 설정
    print("연산 결과", result(a,b)) 
}
if inputButtonType == "+"{
    displayCalc(result: plus)
}else if inputButtonType == "-"{
    displayCalc(result: minus)
}else if inputButtonType == "*"{
    displayCalc(result: multiply)
}
  • 위와 같이 하는 것에 장점
    - 코드를 읽을때 쉽게 읽을 수 있다.
    - 실수 유발을 최소화 할 수 있다.
    - 유지보수 포인트가 적어진다.
  • 함수를 작성하는데 하나의 기능만 하는 함수를 만들도록 하자.
    - 기능이 많은 함수를 만들게 되면 나중에 코드를 보았을 때 읽기 힘들어 진다.
    - 코드가 지저분해진다.

Closure

  • func 과 유사하다.
  • 이름이 없다. - 그렇기 때문에 따로 변수로 이름을 지정해주어야 한다.
//function
func myScore(a: Int) -> String {
    return "\(a)점"
}

// closure
let myScore2 = { (a:Int) -> String in
    return "\(a)점"
}

// let score = myScore(a:40)
let score = myScore <-- (int) -> String : int 가 들어가고 String 이 나오는 타입이다. (type)
score(50)    // function 호출
myScore2(20) // closure 호출 
  • 축약 (생략)
// closure
let myScore3 = { (a:Int) -> String in
    "\(a)점" <-- 리턴문 한줄만 있을 경우 return 을 생략 가능
}

// closure
let myScore4 = { (a:Int) in <-- return 값으로 추론할  있어서 String이 생략 가능
    "\(a)점"
}

let myScore5: (Int) -> String = { a in <-- 타입을 먼저 선언
    "\(a)점"
}  

let myScore6: (Int) -> String = { 
    return "\{$0}점"                <-- 첫번쨰 파라미터의 값을 $0으로 표시 가능 (n번째 --> $(n-1))
                                    <-- in을 쓰면 안된다.
}
  • 예제
let names = ["apple", "air", "brown", "red", "orange", "blue", "candy"]

// 특정 문자열을 찾는 함수

// 조건 -> 찾는다 -> 특정한 글자가 포함된 것을 찾는다. 
// 조건 -> 찾는다 -> 입력한 글자로 시작하는 첫글자를 찾는다. 

let containsSomeText: (String, String) -> Bool = { name, find in 
    name.contains(find){
        return true
    }
    return false
}

let isStartSomeText: (String, String) -> Bool = { name, find in
    if name.first?.description == find {
        return true
    }
    return false
}

func find(findString: String, condition: (String, String) -> Bool) -> [String] {
    var newNames = [String]()
    for name in names {
        if condition(name, findString) {
            newNames.append(name)
        }
    }
    return newNames
}

find(findString: "a", condition: containSomeText)
find(findString: "a", condition: isStartSomeText)

func someFind(find: String) -> [String] { <-- 이렇게 하면 새로운 조건이 추가될 때 함수 내부를 수정해야된다. 이를 위처럼 closure을 사용하면 이쁘게                                                 코딩 할 수 있다.
    var newNames = [String]()

    for name in names {
        if name.contains(find) {
            newNames.append(name)
        }
    }
    return names
}
  • 실제로 사용해보자.
import UIKit

var names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

// sort
// let sorted = names.sort() // <-- 결과물이 나오는 형태면 과거형으로 네이밍 되어 있다.
names.sort { $0 < $1 } // throws : error handling

names.sort(by: { $0 < $1 }) // 여기서 by: 하나밖에 없음으로 생략 가능 위에꺼랑 동일

names.sort(by: <) // < 자체가 closure 이다. 여기서는 by: 를 생략할 수 없다.

===================================================================================
import UIKit

var names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]

// sort
names.sort { (lhs, rhs) -> bool in
    return lhs > rhs
}

names.sort(by: {$0 > $1 })

names.sort() {$0 > $1}

names.sort{$0 > $1 }

names.sort(by: >)

Enumerations

  • enum
  • 타입을 분류한다.
  • Ex. 도서관 -> 항목 -> 소설, 문제집, 패션, 만화책
import UIKit

// 분류만 하고 싶다.
enum BookType {
    case fiction(title: String, prince: Int, year: Int)
    case comics(title: String, prince: Int, year: Int)
    case workbook(title: String, prince: Int, year: Int)
}

extension BookType {             <- enum의 확장 기능을 만들 수 있다.
    var typeName: String {
        switch self {
        case .comics:
            return "comics"
        case .fiction:
            return "fiction"
        case .workbook:
            return "workbook"
        default:
            ""
        }
    }
}

var bookStyle: BookType?

var books = [BookType]()

func saveBook(book: BookType) {
    books.append(book)
}

saveBook(book: .comics(title: "aaa", prince: 5000, year: 2020))


for book in books {
    
    if case let BookType.comics(title, _, _) = book {         <- 안쓰는 변수를 _ 처리 하지 않으면 워닝 뜸
        print("comics", title, book.typeName)
    }
    
    switch book{
    case let .comics(_, prince, _):
        print(prince)
    case let .fiction(_, prince, _):
        print(prince)
    default:
        break
    }
}

class

  • 정의
class MyInfo {

    init (gender GenderType){
        self.genderType = gender
    }
    enum GenderType {    <- enum 선언 가능 
        case male
        case female
    }    
    
    private var genderType: GenderType <- init에서 gender 값을 받아오면 operator 설정을 안해도 된다. private  외부에서는 값에 접근   없다. 
    
    var name = ""    <-- 변수 만들기 가능
    var age = ""

    func isAdult() -> Bool {     <-- 함수도 가능
        if age > 19 {
            return true
        }
        return false
    }
}

var myInfo = MyInfo(gender: .female)
myInfo.genderType = .male <- private 로 외부에서 접근 할 수 없다. 즉 에러 발생

myInfo.age = 20
var myInfo2 = myInfo        <- 원본은 하나가 있는거고 그거를 참조하는게 myInfo2와 myInfo 두개가 있는 거다. 
myInfo2.age = 100

var myInfo3 = myInfo2

myInto.age        // 100
myInto2.age       // 100
myInto3.age       // 100
  • class는 참조 타입이다.
  • class에는 상속 개념이 존재한다.
import UIKit

// 클래스 내부의 동일한 것들을 하나로 만들어서 관리하자.

/* 부모 클래스 */
class GameInfo {
    var homeScore = 0
    var awayScore = 0
    
    final func presentScore() -> String { // final을 사용하면 override를 사용할 수 없다. 
        return homeScore.description + " : " + awayScore.description
    }
}

/* 자식 클래스 */
class Soccer: GameInfo {
    var time = 0 // <-- 자식 클래스 만의 변수를 선언 가능
}

class Baseball: GameInfo {
    /* 기존의 부모 클래스에 있는 로직을 쓰지 않고 override func으로 정의되어있는 로직대로 쓰겠다는 의미 */
    override func presentScore() -> String {
        return homeScore.description + " 대 " + awayScore.description
    }
    var round = 0
}

class Football:GameInfo {
    
}

let soccer = Soccer()
soccer.awayScore = 1
soccer.homeScore = 2
soccer.presentScore()

properties

  • 어딘가에 들어있는 형태를 properties라고 한다.
import UIKit

class MyInfo {
    
    // stored property : 값을 저장할 수 있는 property
    var name = ""
    var age = 0
    
    // lazy stored property
    /* lazy 를 사용하면 사용하려고 할때 메모리를 사용한다. (class를 생성할때 메모리에 올라가는게 아님) */
    lazy var myProfiles = [UIImage(named: "n"), UIImage(named: "a"), UIImage(named: "b"), UIImage(named: "c"), UIImage(named: "d")] // <- 한번에 너무 많은 변수를 사용하면 오버헤드 발생
    
    // computed property : 계산된 프로퍼티
    // 로직이 실행되서 값을 만들어지는 변수
    // 값을 입력할 순 없고 사용만 할 수 있다.
    // 해당 로직에서는 get을 생략 가능하다.
    var isAdult: Bool {
        get{
            if age > 19 {
                return true
            }
            return false
        }
    }
    
    // email -> 보안 -> 암호화 된 값으로 사용한다. (항상)
    // 항상 무언가를 해야된다고 하면 아래와 같이 로직을 작성할 수 있다.
    var _email = ""
    var email: String {
        get {   // 값을 가져오기
            return _email
        }
        set{    // 값을 셋팅하기
            _email = newValue.hash.description
        }
    }
}

let myInfo = MyInfo() // 이때는 lazy 변수는 메모리에 올라가지 않는다.
myInfo.email = "alwns28@kookmin.ac.kr" // 값을 입력하면 set이 실행된다.
myInfo.email // 값을 호출하면 get 이 실행된다.

initializer

  • 생성자
import UIKit

class MyInfo {
    var name: String
    var myId: String
    
    var age = 0
    var isAdult: Bool
    
    // designated initializer
    init(n: String, id: String) {
        self.name = n
        self.myId = id
        self.isAdult = (age > 19) ? true : false
    }
    
//    init(){             // 위에 선언된 변수에서 값을 정해주지 않은것은 무조건 init에 셋팅 해주어야 한다.
//        self.name = ""
//        self.myId = ""
//        self.isAdult = (age > 19) ? true : false
//    }
    
//    init(id: String){   // init 은 여러개 만들 수 있다.
//        self.name = ""
//        self.myId = id
//        self.isAdult = (age > 19) ? true : false
//    }
    
    // convenience initializer (편의)
    // 필수 조건 - 다른 init을 반드시 실행해야 한다.
    // 하나의 init을 공통으로 사용할 수 있게 만든다.
    convenience init(){
        self.init(n: "", id: "")
    }
    
    convenience init(id: String){
        self.init(n: "", id: id)
    }
}

var myInfo1 = MyInfo(n: "yoon", id: "abcd") // MyInfo.init() 과 동일한 형식

myInfo1.myId
myInfo1.name

var myInfo2 = MyInfo()
myInfo2.myId
myInfo2.name

var myInfo3 = MyInfo(id: "abcd")
myInfo3.myId
myInfo3.name


struct MyConfig { // structure 일때는 init을 만들지 않아도 자동으로 입력하게끔 할 수 있다.
    var conf: String
}

var myCon = MyConfig(conf: "test")
  • convenience initializer : init이 여러개인 상황에서 공통된 부분을 활용하여 깔끔하게 사용할 수 있게 만들어 준다 .

Deinitialization

  • 메모리 해제
import UIKit

var a: Int? = 10
a = nil // nil 을 주면 메모리가 없어진다.

class Game {
    var score = 0
    var name = ""
    var round: Round?
    
    init (){ // 메모리에 올라갈때 실행
        print("game init")
    }
    deinit { // 메모리에서 해제될때 실행
        print("game deinit")
    }
}

class Round {
    weak var gameInfo: Game?     /* 상호 참조 */ // game 의 정보가 없어지면 나도 없어질거야! <-- 이렇게 하면 상호 참조로 사용 가능하다
    var lastRound = 10
    var roundTime = 20
    deinit {
        print("round deinit")
    }
}

var game: Game? = Game()
//var game2: Game? = game

/* 참조하는 곳이 두곳이기 때문에 두곳을 모두 메모리 해제를 시켜주어야 game 메모리가 해제된다. */
//game = nil
//game2 = nil

var round: Round? = Round()
// game = nil // 메모리 해제
/* 이렇게 상호 참조를 하게 되면 nil을 해도 deinit이 되지 않는다. */
round?.gameInfo = game
game?.round = round

game = nil
round = nil
  • 주의: 상호 참조를 하게 되면 메모리 해제가 안된다. 이때 weak를 사용하자.

structure

  • 구조체
  • class와 기본적인 구조는 동일하다.
  • value type이다.
struct ImageType{
    var type = ""
}

var imageType = ImageType() // 아래 세개는 하나를 참조하는 것이 아닌 분리되어있는 변수이다.
var imageType2 = imageType
var imageType3 = imageType2
  • 상속이 불가능

extention

  • 기능을 확장할때 사용
  • struct, class, enum, protocol
import UIKit

// 숫자 (int) 짝수, 홀수
extension Int {
    var oddOrEven: String {
        if self % 2 == 0{
            return "짝수"
        }
        return "홀수"
    }
}

// UIColor
extension UIColor {
    class var mainColor1: UIColor {
        UIColor(red: 50/255, green: 70/255, blue: 120/255, alpha: 1)
    }
}

var button = UIButton()

button.titleLabel?.textColor = .mainColor1

protocol

  • 규격, 규약, 규칙, 뼈대
  • 여러 곳에서 사용하는 반드시 가져야 하는 것들을 선언하는 것
  • 값이 정하는, 구현되는 부분은 넣을 수 없다.
  • 놓치는 것 없이 구현할 수 있다.
import UIKit

protocol UserInfo {
    var name: String { get set }
    var age: Int { get set }    // set 을 안쓰면 써도 되고 안써도 되는 개념임. 하지만 변수가 let 이 있으면 set 을 사용할 수 없다.
    
    func isAdult() -> Bool
}

protocol UserScore {
    var score: Int { get set }
}

protocol UserDetailInfo: UserInfo, UserScore{ // <-- protocol 에서도 protocol 을 합성할 수 있음
    /* code */
}


extension UserInfo {        // UserInfo 에서 확장 기능으로 구현함으로 아래 클래스에서는 따로 구현할 필요가 없다.
    func isAdult() -> Bool {
        if age > 19 {
            return true
        }
        return false
    }
}

class Guest: UserInfo, UserScore { // <-- 여러개의 protocol을 받을 수 있다.
    var name: String = ""
    var age: Int = 0
    var score: Int = 90

}

class Member: UserInfo {
    var name: String
    var age: Int
    init (name: String, age: Int){
        self.name = name
        self.age = age
    }
}

class VIPMember: UserInfo {
    var name: String = ""
    var age: Int = 0
}

class UserInfoPresnter {
    func present() {
        let guest = Guest()
        let memver = Member(name: "jame", age: 25)
        let vip = VIPMember()
        
        let members: [UserInfo] = [guest, memver, vip] // any type 으로 하게 되면 내부에 어떤 값이 있는지 members 변수가 알 수 없다.
        
        for element in members{
            print(element.name)
        }
    }
}

let presenter = UserInfoPresnter()
presenter.present()

inheritance

  • 상속, 이거는 class 에서만 사용된다.
  • super. 를 통해서 부모 클래스에 접근 가능하다.
import UIKit

class UserInfo {
    var name = ""
    var age = 0
    func isAdult() -> Bool {
        if age > 19 {
            return true
        }
        return false
    }
}

class Guest: UserInfo {
    override func isAdult() -> Bool {
        return true
    }
    
    func present () {
        name = "yoon"
        print(name)
        print(super.name)   // super. 를 통해서 부모 클래스에 접근 가능하다.
        
        print(isAdult())
        print(super.isAdult())
    }
}

let guest = Guest()
guest.present()

generic

  • 타입이 여러가지를 사용하게 될때 사용한다.
import UIKit

// generic <내가 정한 임의의 타입>

// stack
// where 구문을 사용하여 제한을 할 수 있다.
// Equtable은 비교할 수 있는 것들. (dict 는 안됨)
struct IntStack<MyType> where MyType: Equatable{
    var items = [MyType]()
    mutating func push(item: MyType) { // struct 구조는 자기 스스로가 내부 값을 변경할 수 없다. 이를 실현시키려면 mutating을 사용하면 됨
        items.append(item)
    }
    
    mutating func pop() -> MyType? {
        if items.isEmpty {
            return nil
        }
        return items.removeLast()
    }
}

var myStack = IntStack<Int>()
myStack.push(item: 4)
var myStack2 = IntStack<String>()
myStack2.push(item: "a")

myStack.pop()
myStack2.pop()

// queue
  • 요즘 추세는 dictionary를 사용을 많이 안하는 추세

higher order function

  • 고차 함수
import UIKit

let names = ["yoon", "kim", "lee", "min"]

// map -> 원하는 스타일로 변경 (길이는 같다)
let names2 = names.map { $0 + "님"}

names2

let names3 = names.map { (name) in
    name.count
}

names3

let name4 = names.map { (name) in
    name.count > 3
}

name4

// filter -> 거른다.
let filterNames = names.filter { (name) -> Bool in
    name.count > 3
}

filterNames

// reduce 하나로 뭉친다. 통합. 합친다.
let sumName = names.reduce("") { (first, second) in
    first + " " + second
}
sumName


// compactMap

let numberArr = [1,2,3,4,5, nil, 6, nil, 8]
let numbers = numberArr.compactMap { (num) in
    return num
}
numbers


// flatmap
let numbers2 = [[1,2,3], [4,5,6]]
let numbers2_flatmap = numbers2.flatMap { $0}
numbers2_flatmap
  • 고차함수를 잘 사용하면 깔끔한 코드를 작성 가능하다.
profile
신기한건 다 해보는 사람

0개의 댓글