Skip to content

Commit

Permalink
[#6] feat: Add ViewModel & Network
Browse files Browse the repository at this point in the history
GameViewModel & GameListViewModel 작성 및 Network 추가
  • Loading branch information
youngminshim-de committed May 7, 2021
1 parent 73a75dd commit 7efc2cd
Show file tree
Hide file tree
Showing 11 changed files with 379 additions and 43 deletions.
43 changes: 41 additions & 2 deletions iOS/Baseball/Baseball.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objectVersion = 51;
objects = {

/* Begin PBXBuildFile section */
Expand All @@ -21,6 +21,12 @@
D4A2CB9C2640E5E60019AFB6 /* GameListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4A2CB9A2640E5E60019AFB6 /* GameListCell.swift */; };
D4A2CB9D2640E5E60019AFB6 /* GameListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = D4A2CB9B2640E5E60019AFB6 /* GameListCell.xib */; };
D4A2CBA8264382B00019AFB6 /* ScoresViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4A2CBA7264382B00019AFB6 /* ScoresViewController.swift */; };
D4A2CBBE2643DA410019AFB6 /* GameEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4A2CBBD2643DA410019AFB6 /* GameEntity.swift */; };
D4A2CBC32643DDD00019AFB6 /* EndPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4A2CBC22643DDD00019AFB6 /* EndPoint.swift */; };
D4A2CBC8264405400019AFB6 /* FetchGame.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4A2CBC7264405400019AFB6 /* FetchGame.swift */; };
D4A2CBCE26440FCA0019AFB6 /* GameViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4A2CBCD26440FCA0019AFB6 /* GameViewModel.swift */; };
D4A2CBD3264412B40019AFB6 /* GameListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4A2CBD2264412B40019AFB6 /* GameListViewModel.swift */; };
D4A2CBD8264414B30019AFB6 /* FetchGameList.swift in Sources */ = {isa = PBXBuildFile; fileRef = D4A2CBD7264414B30019AFB6 /* FetchGameList.swift */; };
E021C1CF5AE375C2F9300D39 /* Pods_Baseball_BaseballUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50D46EADD93F895BD0D709A0 /* Pods_Baseball_BaseballUITests.framework */; };
E251DC6CD0176A2C568BC3AD /* Pods_Baseball.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D159143F731D8C2D8DDBDE86 /* Pods_Baseball.framework */; };
/* End PBXBuildFile section */
Expand Down Expand Up @@ -70,6 +76,12 @@
D4A2CB9A2640E5E60019AFB6 /* GameListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameListCell.swift; sourceTree = "<group>"; };
D4A2CB9B2640E5E60019AFB6 /* GameListCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = GameListCell.xib; sourceTree = "<group>"; };
D4A2CBA7264382B00019AFB6 /* ScoresViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScoresViewController.swift; sourceTree = "<group>"; };
D4A2CBBD2643DA410019AFB6 /* GameEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameEntity.swift; sourceTree = "<group>"; };
D4A2CBC22643DDD00019AFB6 /* EndPoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndPoint.swift; sourceTree = "<group>"; };
D4A2CBC7264405400019AFB6 /* FetchGame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchGame.swift; sourceTree = "<group>"; };
D4A2CBCD26440FCA0019AFB6 /* GameViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameViewModel.swift; sourceTree = "<group>"; };
D4A2CBD2264412B40019AFB6 /* GameListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameListViewModel.swift; sourceTree = "<group>"; };
D4A2CBD7264414B30019AFB6 /* FetchGameList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchGameList.swift; sourceTree = "<group>"; };
F745F685E4AD5287ABA0F515 /* Pods-Baseball-BaseballUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Baseball-BaseballUITests.release.xcconfig"; path = "Target Support Files/Pods-Baseball-BaseballUITests/Pods-Baseball-BaseballUITests.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -121,7 +133,6 @@
367A893B7C3818AE03AE1029 /* Pods-BaseballTests.debug.xcconfig */,
9F92A719088DE201B3531AAD /* Pods-BaseballTests.release.xcconfig */,
);
name = Pods;
path = Pods;
sourceTree = "<group>";
};
Expand All @@ -146,7 +157,11 @@
BD8A23712643C47C00828432 /* Model */ = {
isa = PBXGroup;
children = (
D4A2CBCC26440FBE0019AFB6 /* ViewModel */,
D4A2CBBC2643DA300019AFB6 /* Entity */,
BD8A23752643C5F300828432 /* Network */,
D4A2CBC7264405400019AFB6 /* FetchGame.swift */,
D4A2CBD7264414B30019AFB6 /* FetchGameList.swift */,
);
path = Model;
sourceTree = "<group>";
Expand All @@ -165,6 +180,7 @@
children = (
BD8A23732643C4E400828432 /* DTO.swift */,
BD8A23762643C73A00828432 /* Network.swift */,
D4A2CBC22643DDD00019AFB6 /* EndPoint.swift */,
);
path = Network;
sourceTree = "<group>";
Expand Down Expand Up @@ -224,6 +240,23 @@
path = BaseballUITests;
sourceTree = "<group>";
};
D4A2CBBC2643DA300019AFB6 /* Entity */ = {
isa = PBXGroup;
children = (
D4A2CBBD2643DA410019AFB6 /* GameEntity.swift */,
);
path = Entity;
sourceTree = "<group>";
};
D4A2CBCC26440FBE0019AFB6 /* ViewModel */ = {
isa = PBXGroup;
children = (
D4A2CBCD26440FCA0019AFB6 /* GameViewModel.swift */,
D4A2CBD2264412B40019AFB6 /* GameListViewModel.swift */,
);
path = ViewModel;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -465,8 +498,14 @@
files = (
D4A2CB6C2640E4FD0019AFB6 /* MainViewController.swift in Sources */,
D4A2CBA8264382B00019AFB6 /* ScoresViewController.swift in Sources */,
D4A2CBBE2643DA410019AFB6 /* GameEntity.swift in Sources */,
D4A2CBCE26440FCA0019AFB6 /* GameViewModel.swift in Sources */,
D4A2CBC32643DDD00019AFB6 /* EndPoint.swift in Sources */,
D4A2CBD8264414B30019AFB6 /* FetchGameList.swift in Sources */,
D4A2CBC8264405400019AFB6 /* FetchGame.swift in Sources */,
D4A2CB682640E4FD0019AFB6 /* AppDelegate.swift in Sources */,
BD8A23742643C4E400828432 /* DTO.swift in Sources */,
D4A2CBD3264412B40019AFB6 /* GameListViewModel.swift in Sources */,
D4A2CB6A2640E4FD0019AFB6 /* SceneDelegate.swift in Sources */,
BD8A23772643C73A00828432 /* Network.swift in Sources */,
D4A2CB9C2640E5E60019AFB6 /* GameListCell.swift in Sources */,
Expand Down
21 changes: 21 additions & 0 deletions iOS/Baseball/Baseball/Controller/MainViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,36 @@
//

import UIKit
import Combine

class MainViewController: UIViewController {
@IBOutlet weak var gameListCollectionView: UICollectionView!
private var gameListViewModel: GameListViewModel!
private var subscriptions = Set<AnyCancellable>()

override func viewDidLoad() {
super.viewDidLoad()
self.gameListCollectionView.delegate = self
self.gameListCollectionView.dataSource = self
self.gameListCollectionView.register(GameListCell.nib, forCellWithReuseIdentifier: GameListCell.identifier)
}

func bind() {
// nil을 넣는다?
gameListViewModel.$gameList
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { (result) in
switch result {
case .failure(let error):
print(error)
case .finished:
break
}
}, receiveValue: { [unowned self] _ in
gameListCollectionView.reloadData()
})
.store(in: &subscriptions)
}
}

extension MainViewController: UICollectionViewDataSource {
Expand All @@ -27,6 +47,7 @@ extension MainViewController: UICollectionViewDataSource {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: GameListCell.identifier, for: indexPath) as? GameListCell else {
return GameListCell()
}

return cell

}
Expand Down
54 changes: 54 additions & 0 deletions iOS/Baseball/Baseball/Model/Entity/GameEntity.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// GameEntity.swift
// Baseball
//
// Created by 심영민 on 2021/05/06.
//

import Foundation

struct GameList: Decodable {
var gameNumber: Int
var home: String
var away: String
}

struct Game: Decodable {
var home: Team
var away: Team
var homeScore: Int
var awayScore: Int
var inning: Int // 몇회
var status: String // 초, 말
var ballCount: [BallCount]
}

struct Team: Decodable {
var name: String
var players: [Player]
}

struct Player: Decodable {
var name: String
var position: String // 포지션
var atBat: String // 타석
var hits: Int // 안타
var out: Int // 아웃
var battingAverage: Double // 타율
var numberOfPitches: Int // 투구수
}

struct BallCount: Decodable {
enum ball: Int, Decodable {
case strike = 0
case ball = 1
case hit = 2
}
var ballCount: [ball]
var hit: Bool
}

struct Score {
var home: [Int]
var away: [Int]
}
36 changes: 36 additions & 0 deletions iOS/Baseball/Baseball/Model/FetchGame.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// FetchGame.swift
// Baseball
//
// Created by 심영민 on 2021/05/06.
//

import Foundation
import Combine

class FetchGame {

private var network: Network
private var requestable: Requestable
private var subscriptions = Set<AnyCancellable>()

init() {
self.network = Network()
self.requestable = GameAPIEndpoint(path: "", httpMethod: .get)
}

func fetchGame(completion: @escaping (GameDTO)->Void) {
network.request(with: requestable, dataType: GameDTO.self)
.sink { (result) in
switch result {
case .failure(let error):
print(error)
case .finished:
break
}
} receiveValue: { (game) in
completion(game)
}
.store(in: &subscriptions)
}
}
37 changes: 37 additions & 0 deletions iOS/Baseball/Baseball/Model/FetchGameList.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// FetchGameList.swift
// Baseball
//
// Created by 심영민 on 2021/05/06.
//

import Foundation
import Combine

class FetchGameList {

private var network: Network
private var requestable: Requestable
private var subscriptions = Set<AnyCancellable>()

init() {
self.network = Network()
self.requestable = GameAPIEndpoint(path: "", httpMethod: .get)
}

func fetchGameList(completion: @escaping (GameListDTO)->Void) {
network.request(with: requestable, dataType: GameListDTO.self)
.sink { (result) in
switch result {
case .failure(let error):
print(error)
case .finished:
break
}
} receiveValue: { (gameList) in
completion(gameList)
}
.store(in: &subscriptions)
}
}

44 changes: 4 additions & 40 deletions iOS/Baseball/Baseball/Model/Network/DTO.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,10 @@

import Foundation

struct GameList {
var games: [Game]
struct GameDTO: Decodable {
private (set) var game: Game
}

struct Game {
var home: Team
var away: Team
var homeScore: Int
var awayScore: Int
var inning: Int // 몇회
var status: String // 초, 말
var ballCount: [BallCount]
}

struct Team {
var name: String
var players: [Player]
}

struct Player {
var name: String
var position: String // 포지션
var atBat: String // 타석
var hits: Int // 안타
var out: Int // 아웃
var battingAverage: Double // 타율
var numberOfPitches: Int // 투구수
}

struct BallCount {
enum ball: Int {
case strike = 0
case ball = 1
case hit = 2
}
var ballCount: [ball]
var hit: Bool
}

struct Score {
var home: [Int]
var away: [Int]
struct GameListDTO: Decodable {
private (set) var gameList: GameList
}
31 changes: 31 additions & 0 deletions iOS/Baseball/Baseball/Model/Network/EndPoint.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// EndPoint.swift
// Baseball
//
// Created by 심영민 on 2021/05/06.
//

import Foundation

protocol Requestable {
var baseURL: String { get }
var path: String { get }
var httpMethod: HttpMethod { get }
func url() -> URL?
}

public struct GameAPIEndpoint: Requestable {

public let baseURL = ""
public let path: String
public let httpMethod: HttpMethod

init(path: String, httpMethod: HttpMethod) {
self.path = path
self.httpMethod = httpMethod
}

public func url() -> URL? {
return URL(string: baseURL + path)
}
}
Loading

0 comments on commit 7efc2cd

Please sign in to comment.