제목이 이게 뭐죠? 할 수 있는데 .. 왈 메인 화면을 만들 때 그리고 QA를 할 때 가장 .. 고민을 많이 한 부분이라 한번 기록을 해볼까 .. 한다 .. 절대로 니카내카하다가 토나와서 넘어온거 아니다.
왈 메인 화면에서 사용자가 선택한 왈소리 유형, 시간대에 해당하는 왈소리가 랜덤으로 오게 되는데, 사용자별로 받게 되는 왈소리 개수도 다르고, 날마다 변하며, 그 중에는 사용자가 본인에게 보내는 왈소리도 있다.
그리고 시간대에 따라서, 왈소리를 읽은 여부에 따라서 다른 왈뿡이 캐릭터 및 텍스트가 보여야 하므로 그 때마다 UI를 분기처리 해야 한다.
-> 여기까지가 메인에서 신경써야 하는 주요 로직이었다.
생각한 로직에 따라서 코드를 작성했고 나름 잘 로직을 분리했다고 생각했는데 .. 놓친 부분이 있었다. 바로 메인에 진입할 때가 아니라 사용자가 계속 메인에서 왈소리를 읽고 확인한 후에도 읽은 것에 대한 분기처리로 왈뿡이가 바뀌어야 한다는 것이었다. ⬇️
왈 메인 화면에서 왼쪽 이미지와 같이 왈소리가 오다가, 만약 왈소리를 모두 다 읽게 되면 오른쪽과 같이 도착 왈뿡이(그리고 도착 텍스트)로 바뀌어야 하는데 변하지 않는 이슈가 있었다.
그래서 생각한 로직은 다음과 같다.
✔️ 사용자가 현재 읽을 수 있는 왈소리인가 (시간대에 맞는지 확인)
✔️ 사용자가 봤던 왈소리인가 (현재 읽을 왈소리가 남아 있는지, 다 도착한 것인지 등을 확인)
를 확인하기 위해 canOpen / isShown 프로퍼티를 통해 각 상황에 따라 분기처리를 했다.
예를 들어서 오늘 도착해야 하는 왈소리가 아침/점심/저녁 왈소리 한개씩 총 3개일 때,
점심이 지나고 저녁 전에 앱에 진입한 경우,
확인할 수 있는 왈소리는 총 2개이고 아직 하나도 확인하지 않았기 때문에 '확인해보세요' 왈뿡이가 나와야 한다.
각 왈소리 타입에 대해서 다른 왈뿡이가 나온 뒤,
다시 메인으로 왔을 때, 아직 오늘 올 왈소리를 모두 확인하 것이 아니기에 아직까지는 '확인해보세요' 왈뿡이가 나온다.
그리고 저녁 시간대가 지나서 앱을 실행하고 마저 도착한 왈소리를 모두 읽으면
그 때는 읽고 나서 바로 '오늘 왈소리가 전부 도착했어요' 왈뿡이가 나와야 한다.
이런 상황을 모두 고려해서 데이터를 관리해야 한다.
이 때 나타날 수 있는 상황을 위에서 말한 세가지 고려사항을 바탕으로 분기처리하면 된다.
- 현재 확인할 수 있는 왈소리가 있는가
- 현재 시간이 언제인가
- 사용자가 본 왈소리의 개수는 몇개인가
서버에서 넘겨주는 응답 데이터를 바탕으로 볼 수 있는 데이터, 본 데이터, 그리고 현재 사용자가 앱을 사용하고 있는 시간대에 따라 분기처리를 하면 다음과 같다.
참고로, 왈뿡이의 상황에 따른 타입은 따로 열거형으로 관리했다.
WALStatus.swift
enum WALStatus {
case sleeping
case arrived
case checkedAvailable
case checkedAll
var subTitle: String {
switch self {
case .sleeping:
return "왈뿡이가 자는 시간이에요. 아침에 만나요!"
case .arrived, .checkedAvailable, .checkedAll:
return "다들 밥 잘 먹어! 난 뼈다구가 젤루 좋아"
}
}
var content: String {
switch self {
case .sleeping:
return ""
case .arrived:
return "왈소리가 도착했어요\n발바닥을 눌러 확인해주세요"
case .checkedAvailable:
return "왈소리가 열심히 달려오고 있어요"
case .checkedAll:
return "오늘의 왈소리가 전부 도착했어요"
}
}
var walImage: UIImage {
switch self {
case .sleeping:
return WALIcon.imgWalBBongSleeping.image
case .checkedAll, .checkedAvailable:
return WALIcon.imgWalBBongWaiting.image
case .arrived:
let walArrivedImageList: [UIImage] = [WALIcon.imgWalBBongArrive1.image,
WALIcon.imgWalBBongArrive2.image,
WALIcon.imgWalBBongArrive3.image]
return walArrivedImageList.randomElement() ?? WALIcon.imgWalBBongArrive1.image
}
}
}
✅ 왈뿡이가 자고 있는 상태 (오전 12시부터 오전 8시까지)
✅ 왈소리가 도착했고, 확인할 수 있는 왈소리가 없을 때
-> 시간을 확인해서 오전 12시부터 오전 8시 사이라면 -> 자고 있는 상태
-> 그 외의 시간이라면 -> 아직 오는 중 (= "왈소리가 오는 중이에요")
✅ 왈소리가 도착했고, 확인 할 수 있는 왈소리가 있을 때 아직 다 확인하지 않은 경우
-> "왈소리가 도착했어요 발바닥을 눌러 확인해주세요"
✅ 왈소리가 도착했고, 확인할 왈소리가 있을 때 모두 확인한 경우
-> 오늘 와야 하는 총 왈소리의 개수와 확인한 왈소리가 같다면, 오늘의 왈소리는 다 읽었으므로 -> "오늘의 왈소리가 전부 도착했어요"
-> 오늘 와야 하는 총 왈소리의 개수보다 적다면, 아직 남았으므로 -> "왈소리가 오는 중이에요"
메인에 진입할 때 전체 왈소리의 개수, 확인할 수 있는 왈소리의 개수, 확인한 왈소리의 개수, 현재 시간대 등을 고려하면 아래와 같다.
func getMainInfo() {
MainAPI.shared.getMainData { mainData, err in
guard let mainData = mainData else {
return
}
DispatchQueue.main.async {
guard let data = mainData.data else { return }
self.mainData = data
self.dataCount = data.count
self.walCollectionView.reloadData()
self.updateCollectionViewLayout()
// 현재 볼 수 있는 개수와 이미 확인한 개수를 변수로 관리 한다.
var isShownCount: Int = 0
var canOpenCount: Int = 0
// 메인 데이터의 아이템을 하나씩 꺼내서
for item in self.mainData {
// 이미 본 것과
if item.isShown {
isShownCount += 1
}
// 확인할 수 있는 왈소리의 개수를 센다.
if item.canOpen {
canOpenCount += 1
}
}
// 만약 현재 확인할 수 있는 왈소리가 없다면, 그것은 두 가지 경우를 의미한다.
if canOpenCount == 0 {
let stringDate = self.dateFormatter.string(from: self.date)
guard let intDate = Int(stringDate) else { return }
// 만약 사용자가 따로 설정한 시간대가 아니라면 오전 12시부터 오전 8시까지는
if intDate >= 0 && intDate <= 7 {
왈뿡이가 자고 있다.
self.walStatus = .sleeping
} else {
// 또는 점심,저녁을 신청한 사용자의 경우 아침에는 확인할 수 없다.
// 이런 경우에는 새로운 왈소리를 기다려야 하는 상황이므로 "왈소리가 열심히 달려오고 있어요"가 나와야 한다.
self.walStatus = .checkedAvailable
}
} else {
// 만약 확인할 수 있는 왈소리가 있을 경우,
// 사용자가 확인한 왈소리와 확인할 수 있는 왈소리가 같을 때 두가지 경우가 있다.
if isShownCount == canOpenCount {
// 만약 오늘 와야 하는 왈소리를 모두 읽은 경우라면
if isShownCount == self.dataCount {
// 다 읽은 상태로 처리하고
self.walStatus = .checkedAll
} else {
// 현재 점심 왈소리까지만 읽을 수 있을 때, 즉 저녁 왈소리는 아직 읽을 수 있는 상황이 아닐 경우,
// 점심 왈소리까지 읽었다면 아직 도착할 왈소리가 남아 있으므로 "왈소리가 열심히 달려오고 있어요"가 나와야 한다.
self.walStatus = .checkedAvailable
}
} else {
// 만약 사용자가 볼 수 있는 왈소리와 본 왈소리가 다르다는 것은 아직 덜 확인했다는 것이므로, 왈소리를 확인해보라는 문구가 나와야 한다.
self.walStatus = .arrived
}
}
}
}
}
🟢 그리고 이 때 주의할 점이 있다.
(-> 이 부분이 제목 QA에 대한 해결방법이다.)
왈소리를 확인하기 위해 발바닥을 탭하고 다시 탭하면 메인으로 돌아오는데, 이 때 ViewController가 전환되는 것이 아니므로 위의 getMainInfo() 메서드가 호출되지 않아, 확인한 것에 대해서 갱신이 되지 않는다.
즉, 오늘 총 왈소리가 3개이고, 저녁 시간대가 지나서 모두 확인이 가능한 상태일 때, 모든 왈소리를 읽고 나면 메인 화면에서도 바로 (따로 앱을 끄고 다시 실행하거나 다른 화면을 갔다가 들어오지 않아도) 도착 왈뿡이(= 새로운 왈소리를 기다려보세요)가 아니라 모두 확인 왈뿡이(=오늘 왈소리를 다 읽었어요)가 나타나야 한다.
그러므로 왈소리를 확인할 때,
즉 발바닥을 탭할 때마다 서버 통신을 해서 isShown을 false에서 true로 바꿔주도록 하고, 이 때 응답 데이터로 메시지만 받는 것이 아니라 데이터를 다시 받아서 위의 분기처리를 진행하고 상태를 업데이트 해주면 된다.
private func updateMainData(item: Int) {
MainAPI.shared.updateMainData(item: self.mainData[item].id) { mainData, error in
guard let mainData = mainData else { return }
guard let data = mainData.data else { return }
self.mainData = data
self.dataCount = data.count
DispatchQueue.main.async {
var isShownCount: Int = 0
var canOpenCount: Int = 0
for item in self.mainData {
if item.isShown {
isShownCount += 1
}
if item.canOpen {
canOpenCount += 1
}
}
if canOpenCount == 0 {
let stringDate = self.dateFormatter.string(from: self.date)
guard let intDate = Int(stringDate) else { return }
if intDate >= 0 && intDate <= 7 {
self.walStatus = .sleeping
} else {
self.walStatus = .checkedAvailable
}
} else {
if isShownCount == canOpenCount {
if isShownCount == self.dataCount {
self.walStatus = .checkedAll
} else {
self.walStatus = .checkedAvailable
}
} else {
self.walStatus = .arrived
}
}
}
}
}
... 흠 .. 중복되는 코드가 있어서 .. 수정을 좀 .. 해야 할 것 같네 ..
일단 로직은 이렇게 구현하면 문제없이 .. ? 아마도 .. 원하는 상태로 잘 나온다.
'iOS > 왈' 카테고리의 다른 글
[왈] Mal 어쩌구 오류 (0) | 2022.09.27 |
---|