안녕하세요!! 후르륵짭짭 입니다!
이번에는 Method Chaining 이라는 것에 대해 알아보려고 합니다!
옵셔널 체이닝에 대해서 공부하다가 같이 알게 된 것인데, 정말 유용하게 사용 할 수 있을 겁니다!
** Chainning **
일단 Chaining이 무엇이냐 하면!
말 그대로 연결성을 가진 겁니다.
예를 들어 아래 처럼 사용 하는 것을 말 합니다 ㅎㅎ
let result = Array("name").map({String($0)}).filter({$0 == "n"})
전 이런 코드를 직접 만들어 보고 싶었습니다 ㅎㅎㅎ
저렇게 하나씩 쭉 연결해서 결과를 반환해주고 그걸 받아서 다시 결과를 반환하고,,,, 이런 코드가 멋있다고 생각 했었습니다.
** 전체 코드 **
//MARK : Optional Chaning
class Room{
var number : Int
init(number : Int){
self.number = number
}
enum Kind{
case negative
case positive
case zero
}
func kindOfnumber() -> Kind{
switch number {
case 0 :
return .zero
case let x where x % 2 == 0:
print(x)
return .negative
default:
return .positive
}
}
}
extension Room.Kind{
var isRoomEmpty : Bool {
switch self {
case .negative:
return false
default:
return true
}
}
}
class Building{
var name : String
var detail : String?
var room : Room?
init(name : String, detail : String?){
self.name = name
self.detail = detail
}
private func isRoomExist() -> Bool {
return room == nil ? false : true
}
func resetRoom(number : Int) -> Room {
let newRoom = Room(number: number)
self.room = newRoom
return self.room!
}
func makeRoom(number : Int) -> Room {
if isRoomExist() {
return self.room!
}
let newRoom = Room(number: number)
self.room = newRoom
return self.room!
}
}
struct Address{
var province : String
var city : String
var building : Building?
init(province : String , city : String){
self.province = province
self.city = city
}
//이렇게 반환형을 특정 타입으로 해주면 연결형으로 사용 할 수 있다.! 개꿀!
mutating func makeBuilding(name : String, detail : String?) -> Building{
if self.building != nil {
return self.building!
}
let newBuilding = Building(name: name, detail: detail)
self.building = newBuilding
return self.building!
}
func fullAddress() -> String? {
//이 부분이 옶셔널 체이닝이다.
//꾸준히 확인해서 존재하면 패스하고 그게 아니면 멈추게 된다.
guard let buildingExist = building?.room else {return nil}
return "\(province) + \(city) + \(building!.name) + \(buildingExist.number)"
}
}
class Infomation{
var name : String
//이렇게 해서 연결형 구조를 만들 수 있다.
var address : Address?
init(name : String){
self.name = name
}
}
let chapchap : Infomation = Infomation(name: "ChapChap")
chapchap.address = Address(province: "대한민국", city: "서울")
chapchap.address?.makeBuilding(name: "은평뉴타운", detail: "629").makeRoom(number: 1202).number
chapchap.address?.makeBuilding(name: "청구아파트", detail: "420").resetRoom(number: 629).kindOfnumber().isRoomEmpty
chapchap.address?.fullAddress()
chapchap.address?.fullAddress()?.isEmpty
** 하나씩 분석하기 **
일단 결과 부터 보도록 하겠습니다.
//Infomation 인스턴스인 ChapChap 생성
let chapchap : Infomation = Infomation(name: "ChapChap")
//chapchap의 주소 인스턴스 생성
chapchap.address = Address(province: "대한민국", city: "서울")
//Chain 적용
chapchap.address?.makeBuilding(name: "은평뉴타운", detail: "629").makeRoom(number: 1202).number
//결과 : 1202
chapchap.address?.makeBuilding(name: "청구아파트", detail: "420").resetRoom(number: 629).kindOfnumber().isRoomEmpty
//결과 : true
chapchap.address?.fullAddress()
//결과 : "대한민국 + 서울 + 은평뉴타운 + 629"
chapchap.address?.fullAddress()?.isEmpty
//결과 : false
우리가 위에서 해보고 싶었던 체이닝을 만들 었습니다.
방법은 간단합니다.
인스턴스가 클래스던지 구조체인지 상관 없이, 그 인스턴스에 다른 인스턴스의 프로터티나 메소드가 있으면 됩니다.
말을 잘 설명 못 한 것 같은데,,, 아래 처럼 해주는 것을 의미합니다.
struct Address{
var province : String
var city : String
var building : Building?
init(province : String , city : String){
self.province = province
self.city = city
}
//이렇게 반환형을 특정 타입으로 해주면 연결형으로 사용 할 수 있다.! 개꿀!
mutating func makeBuilding(name : String, detail : String?) -> Building{
if self.building != nil {
return self.building!
}
let newBuilding = Building(name: name, detail: detail)
self.building = newBuilding
return self.building!
}
func fullAddress() -> String? {
//이 부분이 옶셔널 체이닝이다.
//꾸준히 확인해서 존재하면 패스하고 그게 아니면 멈추게 된다.
guard let buildingExist = building?.room else {return nil}
return "\(province) + \(city) + \(building!.name) + \(buildingExist.number)"
}
}
이 Address 구조체에 Building 인스턴스를 가지는 building 프로퍼티가 있고
Building을 반환하는 makeBuilding() 메소드와 String을 반환하는 fullAddress()가 있습니다.
이렇게 특정 타입으로 반환하거나 프로퍼티에 접근하면
그 타입으로 이동하게 되고 거기에 있는 기능을 모두 사용 할 수 있게 됩니다.
class Infomation{
var name : String
//이렇게 해서 연결형 구조를 만들 수 있다.
var address : Address?
init(name : String){
self.name = name
}
}
이렇게 Infomation이 있을 때, 아래 처럼 Infomation을 생성하고 Address도 생성해줍니다.
let chapchap : Infomation = Infomation(name: "ChapChap")
chapchap.address = Address(province: "대한민국", city: "서울")
그러면 이제 Infomation => Address로 접근이 가능해 집니다.
결국 이런 방법으로 Chain을 연결 시키면 Chain형 구조를 만들 수 있게 됩니다.
** 중첩 구조와 체이닝**
class Room{
var number : Int
init(number : Int){
self.number = number
}
enum Kind{
case negative
case positive
case zero
}
func kindOfnumber() -> Kind{
switch number {
case 0 :
return .zero
case let x where x % 2 == 0:
print(x)
return .negative
default:
return .positive
}
}
}
extension Room.Kind{
var isRoomEmpty : Bool {
switch self {
case .negative:
return false
default:
return true
}
}
}
이렇게 Room 클래스에 Enum이 들어 있는 것을 알 수 있습니다.
이런 것을 중첩구조라고 부릅니다.
그런데 여기서 중첩 구조일 뿐만 아니라 채이닝 구조로 작성 되어
kindOfNumber() 함수가 Enum인 Kind를 반환하기 때문에
우리는 Kind Enum이 가지는 기능들에 접근이 가능해 집니다.
그리고 Extension을 이용해서 Room 클래스 내부에 Kind Enum을 확장 해줍니다.
extension Room.Kind{
var isRoomEmpty : Bool {
switch self {
case .negative:
return false
default:
return true
}
}
}
이렇게 해주면 중첩 구조면서 채이닝 구조를 가지도록 만들 수 있게 됩니다.
chapchap.address?.makeBuilding(name: "청구아파트", detail: "420").resetRoom(number: 629).kindOfnumber().isRoomEmpty
이렇게 사용 할 수 있게 되는 겁니다.
** 옵셔널 채이닝 **
옵셔널 채이닝이란, 하나씩 옵셔널을 바인딩 해주는 것이 아니라 한번에 바인딩해서 목표 지점 까지 가는 것을 의미합니다.
struct Address{
var province : String
var city : String
var building : Building?
... 생략 ...
func fullAddress() -> String? {
//이 부분이 옶셔널 체이닝이다.
//꾸준히 확인해서 존재하면 패스하고 그게 아니면 멈추게 된다.
guard let buildingExist = building?.room else {return nil}
return "\(province) + \(city) + \(building!.name) + \(buildingExist.number)"
}
}
이렇게 building이 존재하고 거기에 room도 모두 존재하니??? 의미를 가지는 것을 옵셔널 채이닝이라 합니다.
중간에 값이 없을 경우에는 nil을 반환하게 됩니다.
- 중간에 값이 없을 경우
let chapchap : Infomation = Infomation(name: "ChapChap")
chapchap.address = Address(province: "대한민국", city: "서울")
if let exist = chapchap.address?.building?.room {
print(exist)
}
else{
print("중간에 값이 없는 것이 있습니다.")
}
//결과 : 중간에 값이 없는 것이 있습니다.
- 모두 값이 존재 할 경우
let chapchap : Infomation = Infomation(name: "ChapChap")
chapchap.address = Address(province: "대한민국", city: "서울")
chapchap.address?.makeBuilding(name: "은평뉴타운", detail: "629")
if let exist = chapchap.address?.building{
print(exist.name)
}
else{
print("중간에 값이 없는 것이 있습니다.")
}
참고 사이트 :
- Method Chaning :
minsone.github.io/mac/ios/method-chaining-in-swift
- 중첩 구조를 enum을 사용해서 :
stackoverflow.com/questions/45502698/how-to-declare-enums-in-swift-of-a-particular-class-type
'Xcode > Swift - PlayGround' 카테고리의 다른 글
PlayGround) 제너릭에 대해 알아보자 (0) | 2021.03.27 |
---|---|
PlayGround) Protocol에 대해서 좀 더 깊게 알아가기 (0) | 2021.02.14 |
PlayGround) TypeCasting과 Meta Type이 멀까요? (0) | 2021.02.11 |
PlayGround) Required Init()이 무엇일까? (0) | 2021.02.09 |
PlayGround) Class func 와 Static func의 차이가 머지? (0) | 2021.01.24 |
댓글