배열을 Index로 접근하는 방식은 성능상에 있어 엄청난 이점을 준다. 약 0.2 ~ 0.3초마다 계속 뷰가 빠르게 Refresh되어야 하는 우리 회사 앱에서 성능을 위해 배열에 Index 접근을 더 적극적이고 과감하게 쓸 수 밖에 없었다.
배열을 과감하게 다루고 그러다보니 Index Out Range의 위험이 커질 수 밖에 없었다.
사실 이 방법은 이미 있음.
if index < array.count {
data = array[index]
} else {
data = nil
}
이런식으로 접근하면 문제가 되지 않겠다.
하지만 이 방법은 꽤나 귀찮고 if문을 최소화 시켜야 한다는 나의 철학에 따라 내 맘에 안드는 코드가 되어버림. data가 nil인지 아닌지로 View를 나누기가 제일 쉽기 때문에 그런 부분이 필요한 부분은 전부 옵셔널 프로퍼티로 선언하는데, 위의 코드로 처리하면 코드도 더러워질 뿐더러 else문을 까먹고 작성 안하면 nil이 되어도 프로퍼티가 업데이트가 되지 않는 대참사가 일어남 (경험담)
그러니, 내가 해결해야하는 문제는 다음과 같다.
extension Collection {
subscript(safe index: Index?) -> Element? {
get {
guard let index else { return nil }
return indices.contains(index) ? self[index] : nil
}
}
}
extension MutableCollection {
subscript(safe index: Index?) -> Element? {
get {
guard let index else { return nil }
return indices.contains(index) ? self[index] : nil
}
set {
guard let index = index,
let newValue = newValue,
indices.contains(index) else { return }
self[index] = newValue
}
}
}
인터넷의 다른 코드를 보면 set을 구현해두지 않았던데, Set이 가능한건 MutableCollection밖에 없다. MutalbleCollection에도 같은 Extension을 구현하여 get은 물론 set도 가능하도록 만들었다.
data = array[safe: index]
이 한줄 하나로 세상을 평정 할 수 있게 되었다.