Any + Optional

이원희·2021년 2월 7일
1

 🐧 Swift

목록 보기
20/32
post-thumbnail

오늘은 AnyOptional에 대해서 포스팅하려 한다.

Any

Swift 공식 문서에서 Any는 함수타입을 포함하여 모든 타입의 인스턴스를 나타낼 수 있다고 한다.

Any는 평소에 잘 안 쓰지만, 보통 서버와 통신을 위해 parameter를 [String : Any]로 하는 경우가 많다.


Optional

Optional에 대해서는 여기에서 한 번 다뤘었다.

Optional은 어떠한 변수에 값이 있을 수도 없을 수도 있는 경우를 위해 사용한다.

Optional의 구성

Optional제네릭과 enum의 조합으로 이뤄져 있다.

Optional은 아래와 같은 2가지 케이스로 이뤄져 있다.

  • 데이터가 있을때 case some
  • 데이터가 nil일때 case none
public enum Optional<Wrapped> : ExpressibleByNilLiteral {
    case none
    case some(Wrapped)

    print init(_ some: Wrapped)

    ...
}

Any + Optional

(Jake🙇‍♂️)

이 포스팅을 쓰게된 이유는 아래와 같다.

  • 프로젝트를 진행하며 서버에 넘겨줄 [String : Any] 타입의 parameter를 구성했다.
  • 이 때, Any 타입인 value에 Optional 값이 들어가는 필드가 있었다.
  • URLBody를 구성할때 value가 nil인 경우와 아닌 경우를 분기를 태워야 했다.

example

위의 상황을 아래 코드 예시로 확인해보자.

struct TestParameter {
    let a: Int
    let b: Bool
    let c: Int?
}

let testParameter = TestParameter(a: 1, b: true, c: nil)

let test: [String : Any] = [
    "a" : testParameter.a,
    "b" : testParameter.b,
    "c" : testParameter.c
]

Optional 프로퍼티를 갖도록 struct를 선언했다.
[String : Any] 타입을 갖는 test 프로퍼티를 선언했다.


value가 nil인 필드를 확인하기 위해서 어떻게 해야할까?

  • 첫번째
for (key, value) in test {
    if value == nil {
        print("this is nil")
    } else {
        print("\(key) : \(value)")
    }
}

if문을 이용해 value가 nil인 값을 확인했다.

c : nil
a : 1
b : true

내 생각과 다르게 if문을 거치지 않고 위와 같이 출력되었다.


Optional 인스턴스는 어떻게 생겼을까?

한 번 확인해보자!

let testInt: Int? = nil
let testAny: Any = testInt as Any
print(type(of: testAny))

// 출력
Optional<Int>

Optional은 아래와 같이 제네릭과 enum으로 이뤄져 있다.

public enum Optional<Wrapped> : {}

Optional<Int>로 출력된 이유는 testAny 프로퍼티는 Int 타입을 받는 Optional이라는 enum 타입이라는 얘기이다.

그렇다면 왜 첫번째 코드에서 nil인 value를 확인할 수 없었을까?

Optional은 데이터가 있을때는 case some을 갖고, nil일때는 case none을 갖는다.
Any 타입은 모든 타입의 인스턴스를 나타낼 수 있다.

let testIntNone = Optional<Int>.none
let testIntNil: Int? = nil

print(testIntNone)
print(testIntNil)

// 출력
nil
nil

즉, testIntNone, testIntNil이 같은 의미이다.

let testIntSome = Optional<Int>.some(1)
let testIntOptionalValue: Int? = 1

print(testIntSome)
print(testIntOptionalValue)

// 출력
Optional(1)
Optional(1)

즉, testIntSome, testIntOptionalValue가 같은 의미이다.

위의 TestParameter로 돌아가보자.
그렇다면 let test: [String : Any]의 c의 value에는 nil이 아닌 Optional<Int>.none이 저장되었음을 알 수 있다.


  • 두번째
for (key, value) in test {
    if case Optional<Any>.none = value {
        print("this is nil")
    } else {
        print("\(key) : \(value)")
    }
}

value가 Optional의 enum case 인스턴스인지 확인했다.

this is nil
a : 1
b : true

마무리

나는 [String : Any]로 변환하기 전에 nil인지 아닌지 확인한 후 변환을 선호해서 위와 같은 상황을 이번에 처음 봤다ㅋㅋㅋ
그래도 왜 그랬는지 알고 나니 전에 다뤘던 내용과 관련도 있고, 재밌어서 글로 남겨봤다.
그럼 이만👋

0개의 댓글