[Swift] Array contains, insert, append
안녕하세요 아렉스입니다 !
1. Element가 존재하지않으면 append 혹은 insert를 하고싶어요
-> Set 쓰면 되는거아님 ?
2. 순서는 보장받고싶어요
-> Set 으로 중복 제거하고 Array 정렬하면 되는거 아님 ?
3. 그 말도 맞지만,, 일단 오늘 상황이랑은 조금 다른거같아요.
이런 의식의 흐름의 구조를 거치다가
순서가 있는 자료구조를 어지럽히고 다시 정렬하는 방법말고는 없는건가 싶어서 고민했어요.
extension으로 만드는 과정을 블로그에 공유하는 것도 좋겠다싶어서 글을 써봅니다.
네트워크 통신을 통해 섹션을 구성하는 의도로 작성된 코드입니다.
enum SectionType {
case giftBox
case history
}
private var sectionList: [SectionType] = [.history]
viewModel?
.resultTrUseInfo
.subscribe(onNext: { [weak self] response in
if response.isSuccess {
guard let self = self else { return }
if !sectionList.contains(.giftBox) && response.isTrUse {
sectionList.insert(.giftBox, at: 0)
collectionView.reloadData()
}
} else {
self?.view.makeToast(response.message, position: .bottom)
}
})
.disposed(by: bag)
처음에는 Element가 존재하지않으면 append 혹은 insert를 하고싶어요 ! 말 그대로 잘 구현했다고 생각했어요.
그런데 이러한 코드가 많아지다보니 불편한 점들이 보이게됐어요.
1. contains + (insert or append) 에 대한 코드가 1개의 세트 구성이 되면서 if 문 의 중괄호 실행 코드 부분이 깔끔해보이지않는다.
2. sectionList.contains 라는 if condition에 따른 실행코드를 사람에 따라 다르게 작성될 수 있다. (본래 의도가 훼손될 수 있다.)
그래서 Extension을 만들었습니다.
extension Array where Element : Equatable {
@discardableResult
mutating func predicateInsert(_ element: Element, at index: Int) -> Bool {
if !contains(element) {
insert(element, at: index)
return true
} else {
return false
}
}
@discardableResult
mutating func predicateAppend(_ element: Element) -> Bool{
if !contains(element) {
append(element)
return true
} else {
return false
}
}
}
// 사용 - Before
if !sectionList.contains(.giftBox) {
sectionList.insert(.giftBox, at: 0)
collectionView.reloadData()
}
// After
ectionList.predicateInsert(.giftBox, at: 0)
근데 extension을 만들고나니까 마음에 안드는 부분이 또 생겼어요...!
1. else에 대한 처리가 false를 단순히 return 해주는 비교적 작은 일을 하고있어요
2. 제가 if - else 문처럼 nested 한 코드를 별로 선호하지않아요 ! (가장 큰 이유 ..!)
3. 단순 return을 위해 nested + 3줄의 코드를 읽어해요
다른 언어는 잘 모르겠지만 guard 문이 있는 Swift에서는 충분히 개선점이 보였어요.
옵셔널 바인딩에서 많이 사용되지만, 옵셔널 바인딩이 아니어도 guard 문의 컨셉(early exit)을 이용하면 더욱 보기 편한 코드가 될거같은 .. 느낌이 들었어요 !
바꿔볼게요 !
extension Array where Element : Equatable {
@discardableResult
mutating func predicateInsert(_ element: Element, at index: Int) -> Bool {
guard !contains(element) else { return false }
insert(element, at: index)
return true
}
@discardableResult
mutating func predicateAppend(_ element: Element) -> Bool {
guard !contains(element) else { return false }
append(element)
return true
}
}
// 사용 방식은 전과 동일해요
// After
ectionList.predicateInsert(.giftBox, at: 0)
어떤가요 ? if - else 문을 사용했을 때보다 더 직관적인가요 ?
제가 처음 가졌던 의도를 메소드로 구현함으로서 의도치않은 사용을 조금이라도 막을 수 있을까요 ?
최대한 Swift의 특징을 살려서 코드를 작성해보고자 노력해봤어요 !
해당 코드에 대한 코멘트, 혹은 Swift 특징을 살린 다른 코드가 있다면 댓글에 남겨주세요 ! 저도 구경하고싶습니다 ㅎㅎ