본문 바로가기
아이폰 개발/Swift

swift 기초 - assert , guard , protocol

by 인생여희 2021. 3. 5.

swift 기초 - assert , guard , protocol

 

[1] assert 와 guard

 

 애플리케이션 동작 도중에 생성하는 다양한 결과값을 동적으로 확인하고

 안전하게 처리할 수 있도록 확인하고 빠르게 처리할 수 있다.

 

 assert(condition:Bool, message:String)

 assert 함수는 디버깅 모드에서만 동작한다.

 배포하는 애플리케이션에서는 제외 된다.

 주로 디버깅 중 조건의 검정을 위하여 사용한다.

 

 

[1-1] 기본 예제

var someInt : Int = 0

//조건에 부합하므로 지나간다.
assert(someInt == 0, "someInt != 0")

someInt = 1


//조건에 부합하지 않으므로 지나가지 않는다.
//assert(someInt == 0, "someInt != 0")
//Assertion failed: someInt != 0: file test2/main.swift, line 28

 

 

[1-2] 예제 2

//옵셔널 파라미터를 매개변수로 받는다.
func functionWithAssert(age:Int?) {
    
    print(age)  //Optional(50)
    
    //age 가 nil이면 여기서 걸린다.
    assert(age != nil, "age == nil")
    
    assert((age! >= 0) && (age! <= 130), "나이값 입력이 잘못되었습니다.")
    
    print("당신의 나이는 \(age!)세 입니다.")
    
}

functionWithAssert(age: 50)    //당신의 나이는 50세 입니다.
//functionWithAssert(age: nil)        //Assertion failed: age == nil: file test2/main.swift, line 43
//functionWithAssert(age: -1)    //Assertion failed: 나이값 입력이 잘못되었습니다.: file test2/main.swift, line 45

 

 

[2] Early Exit    (guard let)

 

 guard를 사용하여 잘못된 값의 전달 시

 특정 실행구문을 빠르게 종료한다.

 디버깅 모드 뿐만 아니라 어떤 조건에서도 동작한다.

 guard의 else 블럭 내부에는 특정 코드블럭을 종료하는 지시어 (return, break 등)가 필수

 

 타입 캐스팅, 옵셔널과도 자주 사용된다.

 그 외 단순 조건 판단 후, 빠르게 종료할 때도 용이하다.

 

 

 

[2-1] guard 예제

func funcWithGuard(age:Int?){
    
    //옵셔널 age 값이 nil 이 아니면 unwrappedAge 변수에 할당한다.
    //옵셔널 age 값이 130 보다 작고, 0보다 크면 unwrappedAge 변수에 할당한다.
    guard let unwrappedAge = age,
           unwrappedAge < 130,
           unwrappedAge >= 0 else {
        
            print("나이값 입력이 잘못되었습니다.")
            return
    }
    
    print("당신의 나이는 \(unwrappedAge) 입니다.")
}

var count = 1
while true {
    guard count < 3
    else {
        break
    }
    print(count)
    count += 1
    //1
    //2
}

 

 

[2-2] guard 예제

//매개 변수는 딕셔너리 타입이다
func someFunction(info : [String:Any]) {
        
    //딕셔너리의 key의 name 타입이 String 일때, 옵셔널값을 name에 할당
    guard let name = info["name"] as? String else {
        return
    }
    
    //딕셔너리 key age 타입이 Int 일때, 또 age 가 0 보다 클때만 옵셔널값을 age에 할당
    guard let age = info["age"] as? Int , age >= 0 else {
        return
    }
    
    print("\(name) : \(age)")
}


someFunction(info: ["name" : "jenny" , "age" : "10"]) //guard 를 통과 못한다. - 타입이 안맞음
someFunction(info: ["name" : "kyo"])              //guard 를 통과 못한다. - 타입 안맞음
someFunction(info: ["name" : "hong" , "age" : 10])   //hong : 10

 

 

[3] 프로토콜

 

구조체, 클래스, 열거형은 프로토콜을 채택해서

프로토콜의 요구사항을 실제로 구현할 수 있다.

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

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

 

 

 정의

 

 protocol <프로토콜이름>

{

 //정의부

 }

 

 

[3-1] 프로토콜 정의

 

protocol Talkable {
    /*
     <프로퍼티 요구>
     프로퍼티 요구는 항상 var 키워드를 사용한다.
     get은 읽기만 가능해도 상관없다는 뜻이며
     get과 set을 모두 명시하면 읽기 쓰기 모두 가능한 프로퍼티여야 한다.
     */
    
    var topic : String {get set}
    var language : String {get}
    
    //<메서드 요구>
    func talk()
    
    
    //초기화 메소드 요구
    init(topic:String , language: String)
    
}

 

 

[3-2] 프로토콜 채택 및 준수

//Person 구조체는 Talkable 프로토콜을 채택했습니다.
struct Person:Talkable {
    
    //[1] 프로퍼티 요구 수준
    var topic: String
    let language: String
    

    //[2] 메서드 요구 준수
    func talk() {
        print("\(topic)에 대해 \(language)로 말합니다.")
    }
    
    
    //[3] 초기화 요구 준수
    init(topic:String , language: String){
        self.topic = topic
        self.language = language
    }
    
}

 

 

[3-3] 프로토콜 상속

 

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

 

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

 

 }

 

//부모 프로토콜
protocol Readable {
    func read()
}

//부모 프로토콜
protocol Writeable {
    func write()
}

//자식 프로토콜
protocol ReadSpeakable : Readable {
    //func read()
    func speak()
}


//자식 프로토콜
protocol ReadWriteSpeakable : Readable, Writeable {
    //func read()
    //func write()
    func speak()
}

//자식 프로토콜 준수
struct SomeType: ReadWriteSpeakable {
    
    //프로토콜 메소드 구현
    func speak() {}
    
    func read() {}
    
    func write() {}
}

 

[3-4] 클래스 상속과 프로토콜

 클래스에서 상속과 프로토콜 채택을 동시에 하려면

 상속받으려는 클래스를 먼저 명시하고

 그 뒤에 채택할 프로토콜 목록을 작성한다.

 

//부모 클래스 : 프로토콜
class SuperClass : Readable{
    func read(){}
}

//자식 클래스 : 부모클래스, 프로토콜s...
class SubClass: SuperClass , Writeable, ReadSpeakable {
    func write() {}
    
    func speak() {}
}

 

 

[3-5] 프로토콜 준수 확인

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

is as 연산자 사용

 

let sup: SuperClass = SuperClass()
let sub: SubClass = SubClass()

var someAny: Any = sup
someAny is Readable // true
someAny is ReadSpeakable // false
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()
} // 동작하지 않음
someAny = sub

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

 

 

test2.zip
0.02MB

 

 

 

참고

blog.yagom.net/562/