-
Notifications
You must be signed in to change notification settings - Fork 46
[Team09 - 쑤 & 쏭] 게임 진행 화면 구현 (Data binding & CALayer 추가) #16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: team9
Are you sure you want to change the base?
Changes from all commits
cc90088
c5c26b7
d11463e
9131a6f
ce5d06d
9afac52
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,11 +18,11 @@ class PlayViewController: UIViewController { | |
| @IBOutlet weak var playInformationStackView: UIStackView! | ||
| @IBOutlet weak var scoreHeaderView: ScoreHeaderView! | ||
|
|
||
| var cancelBag = Set<AnyCancellable>() | ||
| var currentPlayerView: CurrentPlayerView! | ||
| var count: Int = 0 | ||
| var viewModel: GameViewModel? { | ||
| var viewModel: GameViewModel! { | ||
| didSet { | ||
| count = viewModel?.game?.pitcherHistory.count ?? 0 | ||
| count = viewModel?.game?.data.pitchHistories.count ?? 0 | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -40,17 +40,16 @@ class PlayViewController: UIViewController { | |
|
|
||
| viewModel = GameViewModel() | ||
| configureUI() | ||
| } | ||
|
|
||
| // MARK: - Private Functions | ||
| private func bind() { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. bind가 사라졌군요😭 |
||
| viewModel?.$game | ||
| .receive(on: DispatchQueue.main) | ||
| .sink(receiveValue: { [weak self] game in | ||
| self?.scoreHeaderView.configureAway(score: game?.away.score ?? 0) | ||
| self?.scoreHeaderView.configureHome(score: game?.home.score ?? 0) | ||
| }) | ||
| .store(in: &self.cancelBag) | ||
| viewModel.load { game in | ||
| DispatchQueue.main.async { [weak self] in | ||
| self?.scoreHeaderView.configureAway(score: game.awayTeam.score) | ||
| self?.scoreHeaderView.configureHome(score: game.homeTeam.score) | ||
| self?.currentPlayerView.configure(batter: game.batter, status: game.batterStatus) | ||
| self?.currentPlayerView.configure(pitcher: game.pitcher, status: game.pitcherStatus) | ||
| self?.currentPlayerView.configure(playerRole: game.myRole) | ||
| self?.pitcherHistoryTableView.reloadData() | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private func configureUI() { | ||
|
|
@@ -62,7 +61,7 @@ class PlayViewController: UIViewController { | |
| options: nil)?.first as? CurrentPlayerView else { | ||
| return | ||
| } | ||
|
|
||
| self.currentPlayerView = currentPlayerView | ||
| playInformationStackView.addArrangedSubview(groundView) | ||
| playInformationStackView.addArrangedSubview(currentPlayerView) | ||
| playInformationStackView.addArrangedSubview(pitcherHistoryTableView) | ||
|
|
@@ -79,12 +78,15 @@ class PlayViewController: UIViewController { | |
|
|
||
| extension PlayViewController: UITableViewDataSource { | ||
| func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | ||
| return viewModel?.game?.pitcherHistory.count ?? 0 | ||
| return viewModel?.game?.data.pitchHistories.count ?? 0 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분도 위 코멘트와 동일한 부분입니다! |
||
| } | ||
|
|
||
| func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { | ||
| let cell = tableView.dequeueReusableCell(withIdentifier: PitcherRecordTableViewCell.identifier, for: indexPath) as! PitcherRecordTableViewCell | ||
| cell.backgroundColor = .systemRed | ||
| guard let cell = tableView.dequeueReusableCell(withIdentifier: PitcherRecordTableViewCell.identifier, for: indexPath) as? PitcherRecordTableViewCell, | ||
| let record = viewModel.game?.data.pitchHistories[indexPath.row] else { | ||
| return UITableViewCell() | ||
| } | ||
| cell.configure(record: record) | ||
| return cell | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,36 +7,69 @@ | |
|
|
||
| import Foundation | ||
|
|
||
| struct GameResponse: Decodable { | ||
| let data: Game | ||
| } | ||
|
|
||
| struct Game: Decodable { | ||
| let home: Team | ||
| let away: Team | ||
| let strike: Int | ||
| let ball: Int | ||
| let out: Int | ||
| let awayTeam: Team | ||
| let homeTeam: Team | ||
| let inning: String | ||
| let myRole: String | ||
| let halves: String | ||
| let pitcher: Player | ||
| let pitcherStatus: String | ||
| let batter: Player | ||
| let batterStatus: String | ||
| let base1: String? | ||
| let base2: String? | ||
| let base3: String? | ||
| let pitcherHistory: [Record] | ||
| let pitchHistories: [Record] | ||
| let myRole: String | ||
|
|
||
| enum CodingKeys: String, CodingKey { | ||
| case strike, ball, out, inning, halves, pitcher, batter, base1, base2, base3 | ||
| case awayTeam = "away_team" | ||
| case homeTeam = "home_team" | ||
| case pitcherStatus = "pitcher_status" | ||
| case batterStatus = "batter_status" | ||
| case pitchHistories = "pitch_histories" | ||
| case myRole = "my_role" | ||
| } | ||
| } | ||
|
|
||
| struct Player: Decodable { | ||
| let teamId: Int | ||
| let uniformNumber: Int | ||
| let name: String | ||
|
|
||
| enum CodingKeys: String, CodingKey { | ||
| case name | ||
| case teamId = "team_id" | ||
| case uniformNumber = "uniform_number" | ||
| } | ||
| } | ||
|
|
||
| struct Record: Decodable { | ||
| let pitcher: Player | ||
| let batter: Player | ||
| let result: String | ||
| let pitchStrikeCount: String | ||
| let strikeCount: Int | ||
| let ballCount: Int | ||
|
|
||
| enum CodingKeys: String, CodingKey { | ||
| case result | ||
| case pitchStrikeCount = "log" | ||
| case pitcher, batter, result | ||
| case strikeCount = "strike_count" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 오! 참고해서 수정해보겠습니다.😉 감사합니다. |
||
| case ballCount = "ball_count" | ||
| } | ||
| } | ||
|
|
||
| struct Team: Decodable { | ||
| let name: String | ||
| let score: Int | ||
| let position: String | ||
| let player: String | ||
| let playerStatus: String | ||
| let role: String | ||
| } | ||
|
|
||
| struct Scoreboard: Decodable { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,11 +6,12 @@ | |
| // | ||
|
|
||
| import Foundation | ||
| import Combine | ||
|
|
||
| class GameUseCase { | ||
| let apiRequestManager = APIRequestManager() | ||
|
|
||
| func start(url: URL) { | ||
| apiRequestManager.fetchGame(url: url, method: .get) | ||
| func start(url: URL) -> AnyPublisher<GameResponse, Error> { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네트워킹 관련 로직을 고치니 한결 나아졌네요. 잘 수정하였습니다👏 |
||
| return apiRequestManager.fetch(url: url, method: .get) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,22 +6,27 @@ | |
| // | ||
|
|
||
| import Foundation | ||
| import Combine | ||
|
|
||
| class GameViewModel { | ||
| @Published var game: Game? | ||
|
|
||
| @Published var game: GameResponse? | ||
| let gameUseCase = GameUseCase() | ||
| var cancelBag = Set<AnyCancellable>() | ||
|
|
||
| func load() { | ||
| guard let url = Endpoint.url(path: "/room/playInfo") else { return } | ||
| gameUseCase.start(url: url) | ||
| } | ||
|
|
||
| func getAwayScore() -> Int { | ||
| return game?.away.score ?? 0 | ||
| } | ||
|
|
||
| func getHomeScore() -> Int { | ||
| return game?.home.score ?? 0 | ||
| func load(completionHandler: @escaping (Game) -> Void) { | ||
| guard let url = Endpoint.url(path: Endpoint.Path.gameStatus) else { return } | ||
| let publisher = gameUseCase.start(url: url) | ||
| publisher.sink { (completion) in | ||
| switch completion { | ||
| case .finished: | ||
| break | ||
| case .failure(let error): | ||
| print(error.localizedDescription) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 당장 수정해야 할 부분은 아니지만 에러에 대해서 print로 처리해서 추가적으로 코멘트 남깁니다. 추후, 지금 프로젝트를 개선하거나 앱을 만들 때 고려해야 할 부분입니다.
실제 앱 다운 받아서 네트워크 OFF 일 때나 화면 로딩이 어떻게 처리되어 있는지 한번 확인해보세요! |
||
| } | ||
| } receiveValue: { (response) in | ||
| self.game = response | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 클로저 self 참조로 인해 순환 참조가 되서 메모리 릭 발생할 여지가 있습니다. 단순한 방법으로 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| completionHandler(response.data) | ||
| } | ||
| .store(in: &cancelBag) | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이렇게 가져오게 되면 PlayerViewController에서 모델과 관계가 생깁니다. 이러면 GameViewModel 만든 의미가 없습니다. Model 정보(
viewModel?.game?.data.pitchHistories.count)를 ViewModel(viewModel.numbersOfGame 이나 viewModel.gameCount)에서 View 표시할 정보로 가공하고 ViewController에서 ViewModel 정보 가져와서 사용하는 것이 좋습니다.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아하 그렇군요! 수정해보도록 하겠습니다!😉