Skip to content

Commit

Permalink
Merge pull request #11 from kyu-kim-kr/feature-Network
Browse files Browse the repository at this point in the history
Feature network
  • Loading branch information
youngminshim-de authored May 7, 2021
2 parents ddd3093 + 7efc2cd commit b158104
Show file tree
Hide file tree
Showing 100 changed files with 16,361 additions and 15 deletions.
262 changes: 252 additions & 10 deletions iOS/Baseball/Baseball.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions iOS/Baseball/Baseball.xcworkspace/contents.xcworkspacedata

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
4 changes: 2 additions & 2 deletions iOS/Baseball/Baseball/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<!--Main View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="Baseball" customModuleProvider="target" sceneMemberID="viewController">
<viewController id="BYZ-38-t0r" customClass="MainViewController" customModule="Baseball" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="390" height="844"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,39 @@
//

import UIKit
import Combine

class ViewController: UIViewController {
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 ViewController: UICollectionViewDataSource {
extension MainViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
Expand All @@ -27,12 +47,13 @@ extension ViewController: UICollectionViewDataSource {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: GameListCell.identifier, for: indexPath) as? GameListCell else {
return GameListCell()
}

return cell

}
}

extension ViewController: UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
extension MainViewController: UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.bounds.width - 10
let height = (collectionView.bounds.height) / 5 - 10
Expand Down
File renamed without changes.
File renamed without changes.
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)
}
}

11 changes: 11 additions & 0 deletions iOS/Baseball/Baseball/Model/Network/DTO.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@


import Foundation

struct GameDTO: Decodable {
private (set) var game: Game
}

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)
}
}
102 changes: 102 additions & 0 deletions iOS/Baseball/Baseball/Model/Network/Network.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@


import Foundation
import Combine

class Network {

func request<T: Decodable>(with endPoint: Requestable, dataType: T.Type)
-> AnyPublisher<T, NetworkError> {

guard let url = endPoint.url() else {
let error = NetworkError.network(description: "Couldn't Create URL")
return Fail(error: error).eraseToAnyPublisher()
}

var request = URLRequest(url: url)
request.httpBody = nil
request.httpMethod = endPoint.httpMethod.rawValue

return URLSession.shared.dataTaskPublisher(for: request)
.mapError { error in
.network(description: error.localizedDescription)
}
.flatMap(maxPublishers: .max(1)) { pair in
self.decode(data: pair.data, dataType: T.self)
}
.eraseToAnyPublisher()
}

func post<T: Encodable> (with endPoint: Requestable, dataType: T)
-> AnyPublisher<Int, NetworkError> {
guard let url = endPoint.url() else {
let error = NetworkError.network(description: "Couldn't Create URL")
return Fail(error: error).eraseToAnyPublisher()
}

let result = encode(anyData: dataType)
let json: Data
switch result {
case .failure(let error):
return Fail(error: error).eraseToAnyPublisher()
case .success(let data):
json = data
}

var request = URLRequest(url: url)
request.httpBody = json
request.httpMethod = endPoint.httpMethod.rawValue
request.addValue("application/json", forHTTPHeaderField: "Content-Type")

if json != nil {
request.setValue(String(json.count),
forHTTPHeaderField: "Content-Length")
}

return URLSession.shared.dataTaskPublisher(for: request)
.tryMap { data, response -> Int in
guard let httpResponse = response as? HTTPURLResponse else {
throw NetworkError.network(description: "Couldn't Create URL")
}
return httpResponse.statusCode
}
.mapError { error in
NetworkError.network(description: error.localizedDescription)
}
.eraseToAnyPublisher()
}

func decode<T: Decodable>(data: Data, dataType: T.Type) -> AnyPublisher<T, NetworkError> {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase

return Just(data)
.decode(type: T.self, decoder: decoder)
.mapError { error in
.parsing(description: error.localizedDescription)
}
.eraseToAnyPublisher()
}

func encode<T:Encodable>(anyData: T) -> Result<Data,NetworkError> {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted

guard let data = try? encoder.encode(anyData) else {
return Result.failure(NetworkError.encoding(description: "encoding Failure"))
}
return Result.success(data)
}
}


enum NetworkError: Error {
case encoding(description: String)
case parsing(description: String)
case network(description: String)
}

public enum HttpMethod: String {
case get = "GET"
case post = "POST"
}
25 changes: 25 additions & 0 deletions iOS/Baseball/Baseball/Model/ViewModel/GameListViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// GameListViewModel.swift
// Baseball
//
// Created by 심영민 on 2021/05/06.
//

import Foundation

class GameListViewModel {
@Published var gameList: GameList!
private var fetchGameList: FetchGameList

init(fetchGameList: FetchGameList) {
self.fetchGameList = FetchGameList()
fetchGameListViewModel()
}

func fetchGameListViewModel() {
fetchGameList.fetchGameList(completion: { result in
self.gameList = result.gameList
})
}

}
Loading

0 comments on commit b158104

Please sign in to comment.