티스토리 뷰
출처
옵셔널 체이닝
강제 언래핑 대신 옵셔널 체이닝
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
}
let john = Person()
let roomCount = john.residence!.numberOfRooms
// this triggers a runtime error
위 코드는 residence 가 nil 일 때 강제 언래핑을 하려 시도하기 때문에
runtime error 가 발생한다.
옵셔널 체이닝은 numberOfRooms 에 접근하는 방법을 제공한다.
옵셔널 체이닝을 사용하기 위해선 ( ! ) 대신 ( ? ) 을 사용한다.
if let roomCount = john.residence?.numberOfRooms {
print("John's residence has \(roomCount) room(s).")
} else {
print("Unable to retrieve the number of rooms.")
}
residence 옵셔널 프로퍼티에서 "체인" 은 residence 가 존재하면
numberOfRooms 의 값을 가져오는 것을 말한다.
numberOfRooms 에 접근을 시도하는 것은 실패할 가능성이 있기 때문에
옵셔널 체이닝은 Int? 타입의 값이나 옵셔널 Int 값을 반환하려고 한다.
위 예제처럼 residence 가 nil 일 때 옵셔널 Int 는 nil 이 될 것이며
numberOfRooms 에 접근하는 것이 가능하지 않다는 사실을 알려준다.
옵셔널 Int 는 정수를 언래핑하기 위해 옵셔널 바인딩으로 접근되고
roomCount 변수에 옵셔널이 아닌 값을 할당한다.
numberOfRooms 는 옵셔널 값이 아닌 Int 로 정의되어 있지만
옵셔널 체인을 통해 조회되는 numberOfRooms 는 Int? 를 반환한다.
옵셔널 체이닝을 위한 모델 클래스 정의하기
class Person {
var residence: Residence?
}
class Room {
let name: String
init(name: String) {
self.name = name
}
}
class Address {
var buildingName: String?
var buildingNumber: String?
var street: String?
func buildingIdentifier() -> String? {
if let buildingNumber = buildingNumber, let street = street {
return "\(buildingNumber) \(street)"
} else if buildingName != nil {
return buildingName
} else {
return nil
}
}
}
class Residence {
var rooms = [Room]()
var numberOfRooms: Int {
return rooms.count
}
subscript(i: Int) -> Room {
get {
return rooms[i]
}
set {
rooms[i] = newValue
}
}
func printNumberOfRooms() {
print("The number of rooms is \(numberOfRooms)")
}
var address: Address?
}
옵셔널 체이닝을 이용하여 프로퍼티에 접근하기
옵셔널 체이닝을 이용해서 프로퍼티의 값을 설정하려는 것을 시도할 수 있다.
하지만, 옵셔널 값이 nil 이라면 시도조차 하지 않는다.
let someAddress = Address()
someAddress.buildingNumber = "29"
someAddress.street = "Acacia Road"
john.residence?.address = someAddress
func createAddress() -> Address {
print("Function was called.")
let someAddress = Address()
someAddress.buildingNumber = "29"
someAddress.street = "Acacia Road"
return someAddress
}
john.residence?.address = createAddress()
createAddress() 함수를 호출해도 "Function was called" 라는 메소드는
호출되지 않는다.
옵셔널 체이닝을 이용하여 메소드 호출
if john.residence?.printNumberOfRooms() != nil {
print("It was possible to print the number of rooms.")
} else {
print("It was not possible to print the number of rooms.")
}
// Prints "It was not possible to print the number of rooms."
옵셔널 체이닝으로 프로퍼티를 설정하는 경우에도 마찬가지이다.
if (john.residence?.address = someAddress) != nil {
print("It was possible to set the address.")
} else {
print("It was not possible to set the address.")
}
// Prints "It was not possible to set the address."
옵셔널 체이닝을 이용하여 서브스크립트 접근하기
if let firstRoomName = john.residence?[0].name {
print("The first room name is \(firstRoomName).")
} else {
print("Unable to retrieve the first room name.")
}
// Prints "Unable to retrieve the first room name."
john.residence?[0] = Room(name: "Bathroom")
let johnsHouse = Residence()
johnsHouse.rooms.append(Room(name: "Living Room"))
johnsHouse.rooms.append(Room(name: "Kitchen"))
john.residence = johnsHouse
if let firstRoomName = john.residence?[0].name {
print("The first room name is \(firstRoomName).")
} else {
print("Unable to retrieve the first room name.")
}
// Prints "The first room name is Living Room."
옵셔널 타입의 서브스크립트 접근
var testScores = ["Dave": [86, 82, 84],
"Bev": [79, 94, 81]]
testScores["Dave"]?[0] = 91 //[91, 82, 84]
testScores["Bev"]?[0] += 1 //[80, 94, 81]
testScores["Brian"]?[0] = 72 //nil
체이닝의 여러 단계 연결하기
if let johnsStreet = john.residence?.address?.street {
print("John's street name is \(johnsStreet).")
} else {
print("Unable to retrieve the address.")
}
// Prints "Unable to retrieve the address."
let johnsAddress = Address()
johnsAddress.buildingName = "The Larches"
johnsAddress.street = "Laurel Street"
john.residence?.address = johnsAddress
if let johnsStreet = john.residence?.address?.street {
print("John's street name is \(johnsStreet).")
} else {
print("Unable to retrieve the address.")
}
// Prints "John's street name is Laurel Street."
옵셔널 값을 반환하는 메소드 체이닝
if let buildingIdentifier = john.residence?.address?.buildingIdentifier() {
print("John's building identifier is \(buildingIdentifier).")
}
// Prints "John's building identifier is The Larches."
if let beginsWithThe =
john.residence?.address?.buildingIdentifier()?.hasPrefix("The") {
if beginsWithThe {
print("John's building identifier begins with \"The\".")
} else {
print("John's building identifier does not begin with \"The\".")
}
}
// Prints "John's building identifier begins with "The"."
'iOS 개발 > Swift' 카테고리의 다른 글
[Swift 3] 타입 변환 (Type Casting) (0) | 2017.04.20 |
---|---|
[Swift 3] 오류 처리 (Error Handling) (0) | 2017.04.19 |
[Swift 3] ARC (Automatic Reference Counting) (0) | 2017.04.18 |
[Swift 3] 제네릭 (Generics) (0) | 2017.04.16 |
[Swift 3] 프로토콜 (Protocols) (0) | 2017.04.16 |
- Total
- Today
- Yesterday
- EffectiveObjectiveC
- dictionary
- coredata
- 읽기 좋은 코드가 좋은 코드다
- Swfit
- Arc
- CGImage
- 꺼내먹어요
- ios
- Block
- optional
- CIImage
- docker
- NSManagedObject
- NSManagedObjectContext
- string
- set
- workerThread
- RunLoop
- thread
- HTTP
- delegate
- Swift 3
- Swift 3.0
- applicationWillResignActive
- AWS
- Swift3
- Swift
- UIView
- NSManagedObjectModel
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |