'분류 전체보기'에 해당되는 글 235건

  1. 2021.02.06 코드로 오브젝트 추가
  2. 2021.02.05 Button Inset
  3. 2021.02.05 스크롤 뷰
  4. 2021.02.04 오토 레이아웃
  5. 2021.01.30 고차 함수(higher order function)
  6. 2021.01.30 오류 처리(error handling)
  7. 2021.01.30 익스텐션(extension)
  8. 2021.01.30 프로토콜(protocol)
  9. 2021.01.30 assert와 guard(assertion / early exit)
  10. 2021.01.30 타입 캐스팅(type casting)

ViewController.Swift에서 코드 작성

 

코드로 만들어진 객체는 기본적으로 constraint 설정이나 크기나 위치에 대한 개념이 없으면 실행해도 보이지 않음

 

크기나 위치에 대한 코드는 frame과 constraints가 있음

 

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let myButton = UIButton.init(type: .system) // 시스템에서 기본적으로 제공해주는 스타일 타입 적용
        myButton.setTitle("My Button", for: .normal) // 이름은 My Button이라는 기본 상태(.normal)의 버튼
        
        // 뷰 컨트롤러가 가진 뷰 위에 myButton을 올려놓음
        self.view.addSubview(myButton)
        
        // false는 오토 레이아웃을 설정하겠다는 뜻 / true로 하면 오토 레이아웃 설정 안함 그리고 frame 값을 먹음
        myButton.translatesAutoresizingMaskIntoConstraints = false
        
        // 부모 뷰는 self.view
        // constraint 설정은 코드에서는 비활성화 되어 있으므로 활성화를 시켜줘야 함
        // .isActive = true 활성화 코드
        myButton.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
        
        // +는 가운데 기준으로 우측 -는 가운데 기준으로 좌측으로 이동
        // 가운데 기준 우측으로 100만큼 이동
        myButton.centerXAnchor.constraint(equalTo: self.view.centerXAnchor, constant: 100).isActive = true
        
        
        // Label 추가
        let myLabel = UILabel.init()
        myLabel.text = "My Label" // Label에 텍스트 추가
        
        self.view.addSubview(myLabel)
        myLabel.translatesAutoresizingMaskIntoConstraints = false
        
        
        // safeAreaLayoutGuide를 사용하지 않으면 가이드 라인을 침범, 원하는 결과가 아닌 이상한 결과가 나옴
        // 위로 30만큼
        myLabel.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 30).isActive = true
        
        // 왼쪽으로 100만큼
        myLabel.leftAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leftAnchor, constant: 100).isActive = true
    }


}

'Swift' 카테고리의 다른 글

보안 키보드 만들기  (0) 2021.02.13
StackView  (0) 2021.02.06
Button Inset  (0) 2021.02.05
스크롤 뷰  (0) 2021.02.05
오토 레이아웃  (0) 2021.02.04
Posted by khon98
,

Button Inset

Swift 2021. 2. 5. 21:26

콘텐츠가 안에 있으면 그 콘텐츠 크기만큼 크기가 잡힘(텍스트의 크기만큼 콘텐츠가 잡힘 / Label과 비슷함)

Button은 위아래 여백이 조금 더 있음, Label은 텍스트 크기에 딱 맞춰서 여백이 없음

 

Button은 Inset 기능이 있어서 세부적인 조작이 가능

Title과 Image Insets의 값을 변경한 경우 Content Insents값도 바꾼 값만큼 같이 변경해줘야 함

 

content insets의 크기 조정 후 키보드 'command ='를 누르면 입력한 크기로 변경됨

 

실제 있어야 하는 위치와 버튼의 위치가 다를 경우 키보드 'option command ='을 누르면 있어야 하는 위치로 이동

 

 

Semantic으로 이미지와 타이틀의 위치를 바꿀 수 있음

'Swift' 카테고리의 다른 글

보안 키보드 만들기  (0) 2021.02.13
StackView  (0) 2021.02.06
코드로 오브젝트 추가  (0) 2021.02.06
스크롤 뷰  (0) 2021.02.05
오토 레이아웃  (0) 2021.02.04
Posted by khon98
,

스크롤 뷰

Swift 2021. 2. 5. 18:21

스크롤 뷰 생성

Constraint 모두 0

화면에 맞게 스크롤 뷰 드래그해서 크기 조정 

Bottom은 super view로 설정 > Constant 0으로 설정

uiview 생성(스크롤 가능한 영역, content layout guide에 크기를 맞춰야 함)

view 선택하고 control 누른 상태로 content layout guide로 드래그

 

4개의 View에 constant 값을 모두 0으로 설정 

 

view 선택 후 control 누른 상태에서 frame layout guide 드래그 후 equal widths

view.widths에 multiplier 값을 1로 변경

view 선택 후 height 값 설정(800)

equal height 제거

Label 생성 후 크기 지정(모든 값 10)

Label의 Lines 값 0

 

우측에 Relation Equal을 Greater Than of Equal로 변경

 

view에 heigher 값을 제거 후 1500으로 생성

'Swift' 카테고리의 다른 글

보안 키보드 만들기  (0) 2021.02.13
StackView  (0) 2021.02.06
코드로 오브젝트 추가  (0) 2021.02.06
Button Inset  (0) 2021.02.05
오토 레이아웃  (0) 2021.02.04
Posted by khon98
,

오토 레이아웃

Swift 2021. 2. 4. 21:26

프로젝트 생성

1. ios에서 App 선택

2. interface - storyborad로 선택

3. 언어는 스위프트

 

* 뷰 생성 커맨드 : 키보드 command shift L

* 뷰 복사 커맨드 : 키보드 option 누른 상태에서 복사하고 싶은 뷰 드래그

* 언어가 시작하는 부분 Leaing, 끝나는 부분 Tralling(몇몇 국가에선 반대로 쓰임)

* Horizontal 가로 / Vertical 세로

 

기본적인 속성에 대한 개념 설정들을 보는 메뉴는 오른쪽에 있음

 

 

constrain to Margins는 체크되어 있으면 상황에 따라 값이 달라지므로 내가 원하는 간격이 나오지 않을 수 있음, 사용 추천 안 함

Width / Height 크기 지정

Equal Width 같은 넓이를 뜻함

 

 

constraints 삭제는 삭제하고 싶은 constraints를 선택하고 키보드 delete

 

 

Horizontally / Vertically

- 현재 뷰에 상위 뷰(부모 뷰)를 기준으로 정렬

 

 

Multiplier

- 시스템에 입력된 값의 원하는 값을 넣어주면 그 값만큼 증가(곱하기 / Leading과 Top 해당)

- 시스템에 입력된 값의 원하는 값을 넣어주면 그 값만큼 감소(나누기 / Tralling과 Bottom 해당)

- 크기를 지정 한 값은 multiplier 사용 불가

 

 

 

 

Label

- 텍스트를 보여주는 오브젝트중에 대표적인 것

 

 

 

특수문자 / 이모티콘

xcode 상단 메뉴 Edit > Emoji & Symbol

 

 

 

Aspect Fill

- 이미지 비율이 망가지지 않고 화면을 꽉 채움(화면을 꽉 채우기 위해 이미지가 잘릴 수도 있음)

 

Aspect Fit

- 이미지 비율도 맞추고 잘리는 부분도 없어야 할 때 사용(화면에 빈 공간이 생김)

 

 

 

Hugging Priority(우선순위)

- 숫자가 높을수록 먼저 설정됨(1 ~ 1000까지)

 

 

 

Rotation

- 회전 관련은 Vary for Traits(상황에 따라 다르게 나옴)

 

 

 

ScrollView

- 갤러리 뷰 형태 이거나 이미지가 디바이스보다 클 경우, 콘텐츠가 많아서 스크롤을 해야 하는 상황일 때 주로 사용

 

ViewController에 Show the size Inspecter > Simulated Size를 freeform으로 바꾸면 사이즈를 바꿀 수 있음

 

 

 

Margin

Margin 설정 한 경우 / 안 한 경우

 

 

Image Resolution

기기마다 해상도가 다른 이미지를 사용

@2x / @3x 이런게 없다면 기본 크기 그대로 이미지를 사용

2x 3x는 해상도를 의미

1x는 이미지 그대로를 사용하지만 해상도가 낮아서 픽셀이 깨짐

이미지 뷰에 이미지를 정할 때 2x나 3x를 굳이 구분하지 않음, 디바이스가 2x나 3x를 기기에 맞게 이미지를 정함

'Swift' 카테고리의 다른 글

보안 키보드 만들기  (0) 2021.02.13
StackView  (0) 2021.02.06
코드로 오브젝트 추가  (0) 2021.02.06
Button Inset  (0) 2021.02.05
스크롤 뷰  (0) 2021.02.05
Posted by khon98
,

고차 함수

- 전달 인자로 함수를 전달받거나 함수 실행의 결과를 함수로 반환하는 함수

- map, filter, reduce가 있음

 

map

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

 

filter

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

 

reduce

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

 

let numbers: [Int] = [0, 1, 2, 3, 4]
var doubledNumbers: [Int]
var strings: [String]

// for 구문 사용
doubledNumbers = [Int]()
strings = [String]()

for number int 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) // [0, 2, 4, 6, 8])
print(strings) // ["0", "1", "2", "3", "4"]

// 매개 변수, 반환 타입, 반환 키워드(return) 생략, 후행 클로저
doubledNumbers = numbers.map { $0 * 2 }
print(doubledNumbers) // [0, 2, 4, 6, 8]

// filter
// for 구문
var filtered: [Int] = [Int]()

for number in numbers {
    if number % 2 == 0 {
        filtered.append(number)
    }
}

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

// filter 메서드 사용
// numbers의 요소 중 짝수를 걸러내어 새로운 배열로 반환
let evennumber: [Int] = numbers.filter {
    (number: Int) -> Bool in
    
    return number % 2== 0
}

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

// 매개 변수, 반환 타입, 반환 키워드 생략, 후행 클로저
let oddNumbers: [Int] = numbers.filter { $0 % 2 != 0 }

print(oddNumbers) // [1, 3]

// reduce
let someNubers: [Int] = [2, 8, 15]

// for 구문
var result: Int = 0

// someNubers의 모든 요소를 더함
for number in someNumbers {
    result += number
}

print(result) // 25

// reduce 메서드 사용
// 초기 값이 0이고 someNumbers 내부의 모든 값을 더함
let sum: Int = someNumber.reduce(0, {
    (first: Int, second: Int) -> Int in
    return first + second
})

print(sum) // 25

// 초기 값이 0이고 someNumbers 내부의 모든 값을 뺌
let sum: Int = someNumber.reduce(0, {
    (first: Int, second: Int) -> Int in
    return first - second
})

print(sum) // - 25

// 초기 값이 3이고 someNumbers 내부의 모든 값을 더함
let sumFromThree = someNumbers.reduce(3) { $0 + $1 }
print(sumFromThree) // 28

'Swift > 문법' 카테고리의 다른 글

While / if / Repeat / for / Switch  (0) 2021.02.26
Tuple / Bool / Scope  (0) 2021.02.25
오류 처리(error handling)  (0) 2021.01.30
익스텐션(extension)  (0) 2021.01.30
프로토콜(protocol)  (0) 2021.01.30
Posted by khon98
,

오류 표현

- Error 프로토콜과 열거형을 통해서 오류를 표현함

 

enum 오류 종류 이름: Error {

case 종류 1

case 종류 2

case 종류 3

}

 

 

함수에서 발생한 오류 던지기

- 오류 발생의 여지가 있는 메서드는 throws를 사용하여 오류를 내포하는 함수임을 표시

 

 

오류 처리

- 오류 발생의 여지가 있는 throws 함수(메서드)는 try를 사용하여 호출해야 함

- try, try?, try!

 

try?

- 별도의 오류 처리 결과를 통보받지 않고 오류가 발생했으면 결과 값을 nil로 돌려받을 수 있음

- 정삭 동작 후에는 옵셔널 타입으로 정상 반환 값을 돌려 받음

 

try!

- 오류가 발생하지 않을 것이라는 강력한 확신을 가질 때 try! 를 사용하면 정상 동작 후에 바로 결과 값을 돌려 받음

- 오류가 발생하면 런타임 오류가 발생하여 애플리케이션 동작이 중지됨

 

do catch

- 오류 발생의 여지가 있는 throws 함수(메서드)는 do catch 구문을 활용하여 오류 발생에 대비함

 

// 자판기 동작 오류의 종류를 표현한 VendingMachineError 열거형
enum VendingMachineError: Error {
    case invalidInput // 동전을 잘못 넣은 경우
    case insufficientFunds(moneyNeeded: Int) // 돈이 모자란 경우, 얼마가 모자라는지
    case outOfStock // 물건이 없는 경우
}

// 자판기 동작 도중 발생한 오류 던지기
class VendingMachine {
    let itemPrice: Int = 100
    var itemCount: Int = 5
    var deposited: Int = 0
    
    // 돈 받기 메서드
    func receiveMoney(_ mony: Int) throws {
        
        // 입력한 돈이 0 이하면 오류를 던짐
        guard money > 0 else {
            throw VendingMachineError.invalidInput
        }
        
        // 오류가 없으면 정상처리
        self.deposited += money
        print("\(money)원 받음")
    }
    
    // 물건 팔기 메서드
    func vend(numberOfItems numberOfItemsToVend: Int) throws -> String {
        
        // 원하는 아이템의 수량이 잘못 입력되었으면 오류를 던짐
        guard numberOfItemsToVend > 0 else {
            throw VendingMachineError.invalidInput
        }
        
        // 구매하려는 수량보다 미리 넣어둔 돈이 적으면 오류를 던짐
        guard numberOfItemsToVend * itemprice <= depsited else {
            let moneyNeeded: Int
            moneyNeeded = numberOfItemsToVend * itemprice - deposited
            
            throw VendingMachineError.insufficientFunds(moneyNeeded: money)
            }
            
            // 물건이 모자란 경우
            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?

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 {
    
    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? / try!
    result = try? machine.vend(numberOfItems: 2)
    result // optional("2개 제공함")

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

    result = try! machine.vend(numberOfItems: 1)
    result // 1개 제공함

    result = try! machine.vend(numberOfItems: 1)
    // 오류가 발생하면 코드가 죽음

'Swift > 문법' 카테고리의 다른 글

Tuple / Bool / Scope  (0) 2021.02.25
고차 함수(higher order function)  (0) 2021.01.30
익스텐션(extension)  (0) 2021.01.30
프로토콜(protocol)  (0) 2021.01.30
assert와 guard(assertion / early exit)  (0) 2021.01.30
Posted by khon98
,

익스텐션

- 구조체, 클래스, 열거형, 프로토콜 타입에 새로운 기능을 추가할 수 있는 기능

- 기능을 추가하려는 타입의 구현된 소스코드를 알지 못하거나 볼 수 없다 해도 타입만 알고 있다면 그 타입의 기능을 확장할 수도 있음

- 기존에 존재하는 타입이 추가적으로 다른 프로토콜을 채택할 수 있도록 확장할 수 있음

 

extension 확장할 타입 이름 {

타입에 추가될 새로운 기능 구현

}

 

extension 확장할 타입 이름: 프로토콜 1, 프로토콜 2, 프로토콜 3 {

프로토콜 요구사항 구현

}

 

익스텐션으로 추가할 수 있는 기능

- 연산 타입 프로퍼티, 연산 인스턴스 프로퍼티

- 타입 메서드, 인스턴스 메서드

- 이니셜 라이저

- 서브 스크립트

- 중첩 타입

- 특정 프로토콜을 준수할 수 있도록 기능 추가

 

* 기존에 존재하는 기능을 재정의할 수는 없음

 

extension Int { // int 타입의 연산 프로퍼티 추가
    var isEven: Bool {
        return self % 2 == 0
    }
    var isOdd: Bool {
        return self % 2 == 1
    }
}

print(1.isEven) // false
print(2.isEven) // true
print(1.isOdd) // true
print(1.isOdd) // false

var number: Int = 3
print(number.isEven) // false
print(number.isOdd) // true

nuber = 2
print(number.isEven) // true
print(number.isOdd) // false

// 메서드 추가
extension Int {
    func multiply(by n: Int) -> Int {
        return self * n
    }
}
print(3.mutiply(by: 2)) // 6
print(4.mutiply(by: 5)) // 20

number = 3
print(number.mutiply(by: 2)) // 6
print(number.mutiply(by: 3)) // 9

// 이니셜 라이저 추가
extension String {
    init(intTypeNumber: Int) {
        self = "\(intTypeNumber)"
    }
    init(doubleTypeNumber: Double) {
        slef = "\(doubleTypeNumber)"
    }
}

let stringFromInt: String = String(intTypeNumber: 100)
// 100

let stringFromDouble: String = String(doubleTypeNumber: 100.0)
// 100.0

'Swift > 문법' 카테고리의 다른 글

고차 함수(higher order function)  (0) 2021.01.30
오류 처리(error handling)  (0) 2021.01.30
프로토콜(protocol)  (0) 2021.01.30
assert와 guard(assertion / early exit)  (0) 2021.01.30
타입 캐스팅(type casting)  (0) 2021.01.30
Posted by khon98
,

프로토콜

- 특정 역할을 수행하기 위한 메서드, 프로퍼티, 이니셜 라이저 등의 요구사항을 정의

- 구조체, 클래스, 열거형은 프로토콜을 채택해서 프로토콜의 요구사항을 실제로 구현할 수 있음

- 어떤 프로토콜의 요구사항을 모두 따르는 타입은 '프로토콜을 준수한다'라고 표현함

- 프로토콜의 요구사항을 충족시키려면 프로토콜이 제시하는 기능을 모두 구현해야 함

 

protocol 프로토콜 이름 {

정의부

}

 

 

프로토콜 상속

- 프로토콜은 클래스와 다르게 다중 상속이 가능함

 

protocol 프로토콜 이름 : 부모 프로토콜 이름 목록 {

정의부

}

 

 

클래스 상속과 프로토콜

- 클래스에서 상속과 프로토콜 채택을 동시에 하려면 상속받으려는 클래스를 먼저 명시하고 그 뒤에 채택할 프로토콜 목록을 작성함

 

 

프로토콜 준수 확인

- 인스턴스가 특정 프로토콜을 준수하는지 확인할 수 있음

- is, as 연산자 사용

 

protocol Talkable {
    // 프로퍼티 요구
    // 프로퍼티 요구는 항상 var 키워드를 사용
    // get은 읽기만 가능해도 상관 없다는 뜻이며 get과 set을 모두 명시하면 읽기 쓰기 모두 가능
    var topic: String { get set }
    var language: String { get }
    
    // 메서드 요구
    func talk() // 타입에서 구현
    
    // 이니셜라이저 요구
    init(topic: String, language: String)
}

// 프로토콜 채택 및 준수
// Person 구조체는 Talkable 프로토콜을 채택
struct Person: Talkable {
    var topic: String // 읽기, 쓰기 모두 가능한 변수로 선언
    let language: String // 읽기 전용, 상수 / var로 바꿔도 상관 없음
    
    // 메서드 구현
    func talk() {
        print("\(topic)에 대해 \(language)로 말합니다")
    }
    
    // 이니셜라이저 구현
    init(topic: String, language: String) {
        self.topic = topic
        self.language = language
    }
}


protocol Readable {
    func read()
}

protocol Writealbe {
    func write
}

protocol ReadSpeakable: Readable {
    func speak()
}

protocol ReadWriteSpeakable: Readable, Writeable {
    func speak()
}

struct Sometype: ReadWriteSpeakable {
    func read() {
        print("Read")
    }
    
    func write() {
        print("Write")
    }
    
    func speak() {
        print("Speak")
    }
}

// 클래스 상속과 프로토콜
class SuperClass: Readable {
    func read() { print("read") }
}

class SubClass: SuperClass, Writeable, ReadSpeakable {
    func write() { print("write") }
    func speak() { print("speak") }
}

// 프로토콜 준수 확인
let sup: SuperClass = SuperClass()
let sub: SubClass = SubClass()

var someAny: Any = sup
someAny is Readable // true
someAny is ReadSpeakable // true

someAny = sub
someAny is Readable // true
someAny is ReadSpeakable // true

someAny = sup

if let someReadable: Readable = someAny as? Readable {
    someReadable.read()
} // read

if let someReadSpeakable: ReadSpeakable = someAny as? ReadSpeakable {
    someReadSpeakable.speak()
} // 동작하지 않음

if let someReadable: Readable = someAny as? Readable {
    someReadable.read()
} // read

'Swift > 문법' 카테고리의 다른 글

오류 처리(error handling)  (0) 2021.01.30
익스텐션(extension)  (0) 2021.01.30
assert와 guard(assertion / early exit)  (0) 2021.01.30
타입 캐스팅(type casting)  (0) 2021.01.30
옵셔널 체이닝 / nil 병합 연산자  (0) 2021.01.29
Posted by khon98
,

assert와 guard

- 애플리케이션이 동작 도중에 생성하는 다양한 결과 값을 동적으로 확인하고 안전하게 처리할 수 있도록 확인하고 빠르게 처리할 수 있음

 

 

Assertion

- assert(_:_:file:line:) 함수를 사용

- assert 함수는 디버깅 모드에서만 동작

- 배포하는 애플리케이션에서는 제외됨

- 주로 디버깅 중 조건의 검증을 위하여 사용함

 

Early Exit

- guard를 사용하여 잘못된 값의 전달 시 특정 실행 구문을 빠르게 종료

- 디버깅 모드뿐만 아니라 어떤 조건에서도 동작함

- guard의 else 블록 내부에는 특정 코드 블록을 종료하는 지시어(return, break 등)가 꼭 있어야 함

- 타입 캐스팅, 옵셔널과도 자주 사용됨

- 그 외 단순 조건 판단 후 빠르게 종료할 때도 용이함

 

var someInt: Int = 0

// 조건(someInt == 0)을 써주고 0이 맞으면 넘어가고 아니면 "someInt != 0" 나오고 동작 중지
// "someInt != 0"이런 식의 문구는 꼭 안써줘도 됨
assert(someInt == 0, "someInt != 0")

someInt = 1
assert(someInt == 0) // 동작 중지


func functionWithAssert(age: Int?) {
    
    assert(age != nil, "age == nil") // age가 nil이 아닐때 함수 진행, nil이면 오류 발생
    
    assert((age! >= 0) && (age! <= 130), "나이값 입력이 잘못되었습니다")
    print("당신의 나이는 \(age!)세 입니다")
}

functionWithAssert(age: 50) // 당신의 나이는 50세 입니다
functionWithAssert(age: -1) // 오류 발생
functionWithAssert(age: nil) // 오류 발생

// Early Exit
func functionWithGuard(age: Int?) {
    
    guard let unwrappedAge = age, // 옵셔널 바인딩 먼저 실행, age가 nil이라면 바로 returnd으로 넘어감
          unwrappedAge < 130,
          unwrappedAge >= 0 else { // guard에는 else가 꼭 따라 붙음, 조건들이 맞지 않으면 else 실행
        print("나이 값 입력이 잘못되었습니다")
        return
    }
    print("당신의 나이는 \(unwrappedAge)세 입니다")
}

var count = 1

// 반복문에서도 사용 가능
while true {
    guard count < 3 else {
        break
    }
    print(count)
    count += 1
}
// 1
// 2


// dictionary에서도 많이 사용
func someFunction(info: [String: Any]) {
    
    // 딕셔너리에서 나오는 값들은 모두 옵셔널 키에 해당되는 값이 없기 떄문
    guard let name = info["name"] as? String else {         return
    }
    
    guard let age = info["age"] as? Int, age >= 0 else {
        return
    }
    
    print("\(name): \(age)")
}

sumFunction(info: ["name": "khon", "age": "10"]) // 나이가 int 타입이 아닌 string 타입이므로 실행이 되지 않음
sumFunction(info: ["name": "khon01"]) // age가 없으므로 실행 되지 않음
sumFunction(info: ["name": "khon", "age": 10]) // khon: 10

'Swift > 문법' 카테고리의 다른 글

익스텐션(extension)  (0) 2021.01.30
프로토콜(protocol)  (0) 2021.01.30
타입 캐스팅(type casting)  (0) 2021.01.30
옵셔널 체이닝 / nil 병합 연산자  (0) 2021.01.29
인스턴스의 생성과 소멸(init / deinit)  (0) 2021.01.29
Posted by khon98
,

타입 캐스팅

- 인스턴스의 타입을 확인하는 용도 또는 클래스의 인스턴스를 부모 혹은 자식 클래스의 타입으로 사용할 수 있는지 확인하는 용도로 사용

- is, as를 사용함

 

 

업 캐스팅

- as를 사용하여 부모 클래스의 인스턴스로 사용할 수 있도록 컴파일러에게 타입 정보를 전환해줌

- Any 혹은 AnyObject로도 타입 정보를 변환할 수 있음

- 암시적으로 처리되므로 생략해도 무방함

 

 

다운 캐스팅

- as?(조건부 다운 캐스팅) 또는 as!(강제 다운 캐스팅)를 사용하여 자식 클래스의 인스턴스로 사용할 수 있도록 컴파일러에게 인스턴스의 타입 정보를 전환해줌

 

// 타입 캐스팅을 위한 클래스 정의
class Person {
    var name: String = ""
    func breath() {
        print("숨을 쉽니다")
    }
}

class Student: Person {
    var school: String = ""
    func goToSchool() {
        print("등교를 합니다")
    }
}

class UniversityStudent: Student {
    var major: String = ""
    func ptToMT() {
        print("멤버쉽 트레이닝을 갑니다")
    }
}

var khon: Person = Person()
var khon01: Student = Student()
var khon02: UniversityStudent = UniversityStudent()

// 타입 확인
// is를 사용하여 타입을 확인 함
// 연산의 결과는 true, false로 나옴
var result: Bool

// khon이라는 변수안에 인스턴스가 Person 타입이면 true 아니면 false
result = khon is Person // true
result = khon is Student // flase
result = khon is UniversityStudent // false

// Strudent 클래스의 khon01은 Person 클래스를 상속 받았기 때문에 Person도 true
result = khon01 is Person // true
result = khon01 is Student // true
result = khon01 is UniversityStudent // false

result = khon02 is Person // true
result = khon02 is Student // true
result = khon02 is UniversityStudent // true

if khon is UniversityStudent {
    print("khon은 대학생입니다") // khon은 사람이므로 이 문구는 넘어감
} else if khon is Student {
    print("khon은 학생입니다") // khon은 사람이므로 이 문구는 넘어감
} else if khon is Person {
    print("khon은 사람입니다")
}
// khon은 사람입니다

switch khon01 {
case is Person:
    print("khon01은 사람입니다")
case is Student:
    print("khon01은 학생입니다")
case is UniversityStudent:
    print("khon01은 대학생입니다")
}
// khon01은 사람입니다

switch khon02 {
case is UniversityStudent:
    print("khon02는 대학생입니다")
case is Student:
    print("khon02는 학생입니다")
case is Person:
    print("khon02는 사람입니다")
}
// khon02는 대학생입니다


// 업 캐스팅
var khon03: Person = UniversityStudent() as Person
var khon04: Studnet = Student()
var khon05: Any = Person() // Any 타입은 어떤 타입도 들어 올 수 있음, as Any 생략 가능

// 조건부 다운 캐스팅 / as?
var optionalCasted: Student?

// 사람 타입으로 지정되어 있는데 학생일 수 있느냐 이런것들을 물어봄
optionalCasted = khon03 as? UniversityStudent
optionalCasted = khon04 as? UniversityStudent // nil
optionalCasted = khon05 as? UniversityStudent // nil
optionalCasted = khon05 as? Student // nil


// 강제 다운 캐스팅 / as!
var forcedCasted: Student

optionalCasted = khon03 as! UniversityStudent
optionalCasted = khon04 as! UniversityStudent // 오류 발생


func doSomethingWithSwitch(someone: Person) { // 사람 타입으로 매개 변수를 통해 전달 받았을때
    switch someone {
    case is UniversityStudent:
        (someone as! UniversityStudent).goToMT()
    case is Student:
        (someone as! Student).goToSchool()
    case is Person:
        (someone as! Person).breath()
    }
}


// if let 구문을 사용하게 되면 캐스팅과 동시에 인스턴스를 반환 받아서 옵셔널을 추출해서 쓸 수 있음
func doSomething(someone: Person) {
    if let unversityStudent = someone as? UniversityStudent { // 옵셔널 결과 값을 받아와서
        unversityStudent.goToMT() // 인스턴스를 옵셔널 추출해서 사용하게 됨
    } else if let student = someone as? Student {
        student.goToSchool()
    } else if let person = someone as? Person {
        person.breath()
    }
}

doSomething(someone: khon03 as person)
// 멤버쉽 트레이닝을 갑니다

doSomething(someone: khon03)
// 멤버쉽 트레이닝을 갑니다

doSomething(someone: khon04)
// 등교를 합니다

doSomething(someone: khon)
// 숨을 쉽니다

'Swift > 문법' 카테고리의 다른 글

프로토콜(protocol)  (0) 2021.01.30
assert와 guard(assertion / early exit)  (0) 2021.01.30
옵셔널 체이닝 / nil 병합 연산자  (0) 2021.01.29
인스턴스의 생성과 소멸(init / deinit)  (0) 2021.01.29
상속(inheritance)  (0) 2021.01.28
Posted by khon98
,