15. 옵셔널 체이닝(Optional chaining)

옵셔널 체이닝은 현재 nil일 수 잇는 옵셔널인 프로퍼티, 메서드 및 서브스크립트를 조회하고 호출하기 위한 프로세스이다. 옵셔널에 값이 있는 경우엔 프로퍼티 및 메서드 등은 호출에 성공한다. 하지만 옵셔널이 nil인 경우엔 프로터피, 메서드 및 서브스크립트 호출은 nil을 반환한다. 여러 조회는 한 줄로 연결 가능하며, 체인에 어느 부분이라도 nil인 경우 전체 체인은 실패한다.

강제 언래핑의 대안으로서의 옵셔널 체이닝

  1. 옵셔널 체이닝은 nil값에 대해 호출될 수 있는 사실 반영을 위해 조회하는 프로퍼티, 메서드 및 서브 스크립트가 옵셔널 값이 아닌 값을 반환해도 항상 옵셔널로 래핑되어 반환된다.
class Person {
	var residence : Residence?
}

class Residence {
	var numberOfRooms = 1

}

let john = person()
//현재 존은 nil의 residence 프로퍼티 값을 가지고 있다.
//아래서는 이에 대해 강제 언래핑을 시도하는 코드를 작성한다
let roomCount = john.residence!.numberOfRooms
//다음과 같을 시 에러가 난다. 왜냐면 레지던스 값이 nil로 없는 상태이기 때문이다.

if let roomCount = john.residence?.numberOfRooms {
	print(roomCount)
} else {
	print("unable to retrieve roomCount")
}
//옵셔널 체이닝은 numberOfRoom에 접근하기 위한 대안으로 제공된다. 체이닝을 위해서 느낌표 위에 물음표를 사용해준다.
//이것은 옵셔널 residence 프로퍼티를 "체인" 하고 residence가 존재 시 numberOfRooms 값을 조회하도록 설정한 것이다.

옵셔널 체이닝에 대한 모델 클래스 정의와 하위 접근

  1. 타입에 호환되는 복잡한 모델 내에서 하위 프로퍼티로 내려가는 것이 가능하며, 해당 하위 프로퍼티, 메서드, 서브스크립트에 접근 가능한지도 확인이 가능하다.
class Person {
	var residence : Residence?
}

class Residence {
	var rooms : [Room] = []
    var numberOfRooms : Int {
    	return rooms.count
    }
    
    func printNumberOfRooms() {
    	print(numberOfRooms)
    }
    
    var address : Address?
}

class Room {
	let name : String
    init(name : String) {
    	self.name = name
    }
}

class Address {
	var building : String?
    var buildingNumber : String?
    var street : String?
    
    func buildingIdentifier() -> String? {
    	if let number = buildingNumber, let street = street {
        	return "\(number), \(street)"
        else {
        	return nil
        }
    }
}

//다음과 같이 각 옵셔널 인스턴스를 포함하는 4개의 클래스를 정의하였다.
//아래에서는 옵셔널 체이닝을 통해 프로퍼티에 접근해본다.

let john = Person()

if let roomCount = john.residence?.numberOfRooms {
	print("nice!")
} else {
	print("unable to do that")
}
//다음에서 john의 residence는 현재 nil로 초기화 되어있으므로 nil을 리턴하여 else를 수행하게 된다.

let someAddress = Address()
someAddress.buildingNumber = "29"
someAddress.street = "Acacia Road"
john.residence?.address = someAddress
//여기에서는 아직 john의 residence가 nil이기 때문에 address에 접근하기 위한 시도는 에러가 난다.


if john.residence?.printNumberOfRooms() != nil {
	print("possible to print")
} else {
	print("impossible to print")
}
//다음과 같이 옵셔널 체이닝을 통해서 메서드에도 접근이 가능하며, 체이닝 결과에 따라서 흐름제어가 가능하다.

if let firstRoomName = john.residence?[0].name {
	print(firstRoomName)
} else {
	print("no name!")
}
//다음과 같이 서브스크립트에도 접근이 가능하다. 지금은 residence 인스턴스가 가지는 배열의 값에 대해 
//index를 통해 접근하는 시도를 하고 있고, 
//이 또한 만약 residence가 nil인 경우 전체 nil을 반환하여 호출은 실패한다.

여러 단계의 옵셔널 체인 연결

  1. 여러 단계의 옵셔널 체이닝을 통해 모델 내에서 각 프로퍼티, 메서드, 서브스크립트로 깊게 접근할 수 있다. 이 때 조회하려는 타입이 옵셔널이 아니라면 옵셔널 체이닝으로 인해 옵셔널 값을 반환한다. 조회하려는 타입이 이미 옵셔널인 경우는 체이닝 때문에 더 많은 옵셔널이 되진 않는다. 그냥 하나의 옵셔널이 될 뿐이다.
if let johnStreet = john.residence?.address?.street {
	print(johnStreet)
} else {
	print("unable to do that")
}
//다음과 같이 2중 옵셔널 체이닝이 가능하며, 단계적으로 옵셔널 여부를 체크하며
//코드를 전개할 수 있다.

옵셔널 반환값에 대한 체이닝

  1. 옵셔널 체이닝은 또한 옵셔널 타입의 값을 반환하는 메서드를 호출하고 필요하다면 메서드 반환값도 연결이 가능하다.
if let buildingIdentifier` = john.residence?.address?.buildingIdentifier() {
	print(buildingIdentifier)
} else {
	print("can't")
}

좋은 웹페이지 즐겨찾기