Programming/Swift(iOS)

Swift Optional - 1

홍열 2021. 4. 2. 08:19
728x90

swift에서 Optional은 '값이 있을 수도 있고 없을 수도 있다.' 입니다. 

Optional은 nil을 안전하게 다루는 방법이라고 할 수 있습니다. 

 

간단한 String optional입니다.

var str1:String? = nil
var str2:Optional<String> = ""

print(str1)
print(str2)

print(str1?.isEmpty)
print(str2?.isEmpty)

/* 결과
nil
Optional("")
nil
Optional(true)
*/

코드에서도 보듯이 optional의 nil과 isEmply와는 다릅니다. 

str1과 str2의 isEmpty의 결과를 잘 보세요. nil과 true가 나옵니다. 

 

즉 optional에 nil이면 아예 값을 할당 조차 안했다는 얘기가 됩니다. 

 

Optional은  enum으로 구현되어 있습니다. 

@frozen public enum Optional<Wrapped> : ExpressibleByNilLiteral {
    case none

    case some(Wrapped)
}

값이 없으면 none이고, 있으면 some(Wrapped)형태로 저장이 됩니다. 

 

아래 예제를 하나 더 보죠

struct User {
    let id:Int
    let email:String
    let name:String? //optional<String> 형태이다.
    //let name:Optional<String>으로도 표현 가능
    let address:String?
}

let user:User = User(id: 0, email: "hello@gmail.com", name:"tom", address:nil)

switch user.name {
case .some(let value):
    print(value)
case .none:
    print("none - nil")
}

case에서 let은 앞으로 빼도 되겠네요. 

 

user를 아래와 같이 표시해서 사용할 수도 있습니다. 

//둘중 하나만 nil이어도 수행 안된다.
if let name = user.name {
    if let address = user.address {
        print("user \(name), address = \(address)")
    }
}

//optional binding
if let name = user.name, let address = user.address {
    print("user \(name), address = \(address)")
}

//optional binding을 사용할 때 다양한 조건을 걸 수 있다.
//nil과 ""은 다르다
if let name = user.name, !name.isEmpty {
    print("\(name)이 제대로 입력되어 있습니다.")
}

 

User를 extension을 통해 좀 더 확장 시켜봅니다.

extension User {
    //displayName은 name과 address로 결정된다
    #if false
    var displayName:String? {
        if let name = name, let address = address {
            return "\(name)/\(address)"
        }
        return nil
    }
    #endif
    
    //early exit, guard를 이용하면 가능하다.
    var displayName:String? {
        guard let name = name, let address = address else {
            return nil
        }
        return "\(name)/\(address)"
    }
}

 

func createWelcomeMessage(name:String) -> String {
    return "Welcome, \(name)"
}
if let displayName = user.displayName {
    let result = createWelcomeMessage(name: displayName)
    print(result)
} else {
    let result = createWelcomeMessage(name: "guest")
    print(result)
}

//위의 코드는 nil 병합 연산자를 이용해서 간결하게 표현할 수 있다.
//nil일때 기본값을 지정하기 위해 사용된다.

//nil일때는 guest를 넣어줘라
let displayName = user.displayName ?? "guest"
let result = createWelcomeMessage(name: displayName)
print(result)

displayName 변수를 추가하고, 이 변수는 user의 name과 address의 영향을 받습니다. 

그리고 createWelcomeMessage 함수를 통해서 현재 user가 누구냐에 따라서 어떤 메세지를 출력할 것인가 결정하는 것입니다. 

 

nil 병합연산을 통해서 코드를 좀 더 간결히 줄일 수도 있습니다.