🔥 강제 언래핑의 대안, 옵셔널 체이닝

551자
8분

Swift에서 옵셔널 체이닝(Optional Chaining)을 강제 언래핑(Forced Unwrapping)의 대안으로 사용하는 방법에 대해 알아보도록 하겠습니다.

옵셔널 체이닝은 옵셔널 값에 속성, 메서드 또는 서브스크립트를 호출하고 싶을 때 옵셔널 값 뒤에 물음표(?)를 붙여 지정합니다. 이는 옵셔널 값을 강제로 언래핑하기 위해 느낌표(!)를 붙이는 것과 매우 유사하죠. 주요 차이점은 옵셔널 체이닝은 옵셔널이 nil일 때 우아하게 실패하는 반면, 강제 언래핑은 옵셔널이 nil일 때 런타임 오류를 발생시킨다는 것입니다.

옵셔널 체이닝은 nil 값에서 호출될 수 있다는 사실을 반영하기 위해, 옵셔널 체이닝 호출의 결과는 항상 옵셔널 값입니다. 이는 쿼리하는 속성, 메서드 또는 서브스크립트가 비옵셔널 값을 반환하더라도 마찬가지입니다. 이 옵셔널 반환 값을 사용하여 옵셔널 체이닝 호출이 성공했는지(반환된 옵셔널에 값이 포함됨) 또는 체인 내의 nil 값으로 인해 성공하지 못했는지(반환된 옵셔널 값이 nil임) 확인할 수 있습니다.

구체적으로, 옵셔널 체이닝 호출의 결과는 예상되는 반환 값과 동일한 타입이지만 옵셔널로 래핑됩니다. 보통 Int를 반환하는 속성은 옵셔널 체이닝을 통해 접근할 때 Int?를 반환하게 됩니다.

다음 몇 가지 코드 예제를 통해 옵셔널 체이닝이 강제 언래핑과 어떻게 다른지, 그리고 성공 여부를 확인할 수 있는 방법에 대해 살펴보겠습니다.

먼저, PersonResidence라는 두 개의 클래스를 정의해 보겠습니다:

class Person {
    var residence: Residence?
}
 
class Residence {
    var numberOfRooms = 1
}
swift

Residence 인스턴스에는 기본값이 1numberOfRooms라는 단일 Int 속성이 있습니다. Person 인스턴스에는 Residence? 타입의 옵셔널 residence 속성이 있습니다.

새로운 Person 인스턴스를 생성하면 옵셔널이기 때문에 residence 속성은 기본적으로 nil로 초기화됩니다. 아래 코드에서 johnnilresidence 속성 값을 가지고 있습니다:

let john = Person()
swift

이 사람의 residence에서 numberOfRooms 속성에 접근하려고 할 때, residence 뒤에 느낌표를 붙여 그 값을 강제로 언래핑하면 언래핑할 residence 값이 없기 때문에 런타임 오류가 발생합니다:

let roomCount = john.residence!.numberOfRooms
// 이는 런타임 오류를 발생시킵니다.
swift

위의 코드는 john.residencenil이 아닌 값을 가질 때 성공하며, roomCount를 적절한 수의 방이 포함된 Int 값으로 설정할 것입니다. 그러나 위에서 설명한 것처럼 residencenil일 때는 항상 런타임 오류를 발생시킵니다.

옵셔널 체이닝은 numberOfRooms의 값에 접근하는 대체 방법을 제공합니다. 옵셔널 체이닝을 사용하려면 느낌표 대신 물음표를 사용하세요:

if let roomCount = john.residence?.numberOfRooms {
    print("John's residence has \(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}
// "Unable to retrieve the number of rooms."를 출력합니다.
swift

이는 Swift에게 옵셔널 residence 속성에 "체이닝"하고, residence가 존재하면 numberOfRooms의 값을 가져오라고 지시합니다.

numberOfRooms에 접근하려는 시도는 실패할 가능성이 있기 때문에, 옵셔널 체이닝 시도는 Int? 또는 "옵셔널 Int" 타입의 값을 반환합니다. 위의 예시처럼 residencenil일 때, 이 옵셔널 IntnumberOfRooms에 접근할 수 없었다는 사실을 반영하여 nil이 됩니다. 옵셔널 Int는 정수를 언래핑하고 비옵셔널 값을 roomCount 상수에 할당하기 위해 옵셔널 바인딩을 통해 접근됩니다.

numberOfRooms가 비옵셔널 Int임에도 불구하고 이것이 사실이라는 점에 주목하세요. 옵셔널 체인을 통해 쿼리된다는 사실은 numberOfRooms에 대한 호출이 Int 대신 항상 Int?를 반환한다는 것을 의미합니다.

john.residenceResidence 인스턴스를 할당하여 더 이상 nil 값을 갖지 않도록 할 수 있습니다:

john.residence = Residence()
swift

이제 john.residencenil이 아니라 실제 Residence 인스턴스를 포함합니다. 이전과 동일한 옵셔널 체이닝으로 numberOfRooms에 접근하려고 하면, 이제 기본 numberOfRooms 값인 1을 포함하는 Int?를 반환할 것입니다:

if let roomCount = john.residence?.numberOfRooms {
    print("John's residence has \(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}
// "John's residence has 1 room(s)."를 출력합니다.
swift

이렇게 옵셔널 체이닝을 사용하면 nil 값을 안전하게 처리할 수 있으며, 코드의 가독성과 안정성을 높일 수 있습니다. 옵셔널 체이닝은 Swift에서 매우 강력하고 유용한 기능 중 하나이니, 꼭 익혀두시는 것이 좋겠네요!

이번 글에서는 옵셔널 체이닝의 기본 개념과 사용 방법에 대해 살펴보았습니다. 코드 예제와 함께 옵셔널 체이닝이 강제 언래핑과 어떻게 다른지, 그리고 nil 값을 우아하게 처리하는 방법에 대해 알아보았습니다.