-
Notifications
You must be signed in to change notification settings - Fork 50
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
[Team 6 iOS๐ฅ ์ญ & ์ญ์จ] MVVM ๊ตฌ์กฐ๋ฅผ ์ด์ฉํ MainPage ๊ตฌํ #38
Changes from 61 commits
aa3f6c1
d41ef21
156f287
0203357
762729f
ca95da9
31d8959
e1bdd0a
55848a2
060ee02
ec2592b
49b453b
910990e
921f2cc
ad1af83
aefe7b1
8e88fd3
f497cf0
4230819
b45787f
7c8bb4d
9d4ef05
3c30484
1ac7f86
a18b1f4
241051a
f3c7ecb
fc680ab
cc57906
9c067c4
7b922a2
224772d
3268b1f
ba252f2
77f8e26
f3b4722
9541b3f
4749253
61b3575
d36f63d
305a946
c78a8e6
a22cadb
50d24cc
dc57c13
47fde0f
460f06e
bb2a597
cd289fd
71b7e95
4c0178d
c457185
04610f6
d3bc8a4
82dec71
b9c2309
86a4f58
3481f90
5a5ad22
b6b87af
8e3dec1
9f0df66
381315b
db36088
ddbf449
f821230
7c81402
2e981ce
48f2619
4b51f52
ef8fb9d
1319881
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 |
---|---|---|
@@ -0,0 +1,92 @@ | ||
# Xcode | ||
# | ||
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore | ||
|
||
## User settings | ||
xcuserdata/ | ||
|
||
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) | ||
*.xcscmblueprint | ||
*.xccheckout | ||
|
||
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) | ||
build/ | ||
DerivedData/ | ||
*.moved-aside | ||
*.pbxuser | ||
!default.pbxuser | ||
*.mode1v3 | ||
!default.mode1v3 | ||
*.mode2v3 | ||
!default.mode2v3 | ||
*.perspectivev3 | ||
!default.perspectivev3 | ||
|
||
## Obj-C/Swift specific | ||
*.hmap | ||
|
||
## App packaging | ||
*.ipa | ||
*.dSYM.zip | ||
*.dSYM | ||
|
||
## Playgrounds | ||
timeline.xctimeline | ||
playground.xcworkspace | ||
|
||
# Swift Package Manager | ||
# | ||
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. | ||
# Packages/ | ||
# Package.pins | ||
# Package.resolved | ||
# *.xcodeproj | ||
# | ||
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata | ||
# hence it is not needed unless you have added a package configuration file to your project | ||
# .swiftpm | ||
|
||
.build/ | ||
|
||
# CocoaPods | ||
# | ||
# We recommend against adding the Pods directory to your .gitignore. However | ||
# you should judge for yourself, the pros and cons are mentioned at: | ||
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control | ||
# | ||
# Pods/ | ||
# | ||
# Add this line if you want to avoid checking in source code from the Xcode workspace | ||
# *.xcworkspace | ||
|
||
# Carthage | ||
# | ||
# Add this line if you want to avoid checking in source code from Carthage dependencies. | ||
# Carthage/Checkouts | ||
|
||
Carthage/Build/ | ||
|
||
# Accio dependency management | ||
Dependencies/ | ||
.accio/ | ||
|
||
# fastlane | ||
# | ||
# It is recommended to not store the screenshots in the git repo. | ||
# Instead, use fastlane to re-generate the screenshots whenever they are needed. | ||
# For more information about the recommended setup visit: | ||
# https://docs.fastlane.tools/best-practices/source-control/#source-control | ||
|
||
fastlane/report.xml | ||
fastlane/Preview.html | ||
fastlane/screenshots/**/*.png | ||
fastlane/test_output | ||
|
||
# Code Injection | ||
# | ||
# After new code Injection tools there's a generated folder /iOSInjectionProject | ||
# https://github.com/johnno1962/injectionforxcode | ||
|
||
iOSInjectionProject/ | ||
|
||
**/.DS_Store |
Large diffs are not rendered by default.
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> |
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> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// | ||
// AppDelegate.swift | ||
// BanchanCode | ||
// | ||
// Created by jinseo park on 4/20/21. | ||
// | ||
|
||
import UIKit | ||
|
||
@main | ||
class AppDelegate: UIResponder, UIApplicationDelegate { | ||
|
||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// | ||
// SceneDelegate.swift | ||
// BanchanCode | ||
// | ||
// Created by jinseo park on 4/20/21. | ||
// | ||
|
||
import UIKit | ||
|
||
class SceneDelegate: UIResponder, UIWindowSceneDelegate { | ||
|
||
var window: UIWindow? | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// | ||
// DishesResponseDTO+Mapping.swift | ||
// BanchanCode | ||
// | ||
// Created by Song on 2021/04/22. | ||
// | ||
|
||
import Foundation | ||
|
||
struct DishesResponseDTO: Decodable { | ||
private enum CodingKeys: String, CodingKey { | ||
case dishes | ||
} | ||
let dishes: [DishDTO] | ||
} | ||
|
||
extension DishesResponseDTO { | ||
struct DishDTO: Decodable { | ||
private enum CodingKeys: String, CodingKey { | ||
case id | ||
case name | ||
case description | ||
case topImage = "top_image" | ||
case prices | ||
case badges | ||
} | ||
let id: Int | ||
let name: String | ||
let description: String | ||
let topImage: String | ||
let prices: [Int] | ||
let badges: [String] | ||
} | ||
} | ||
|
||
extension DishesResponseDTO { | ||
func toDomain() -> DishList { | ||
return .init(dishes: dishes.map { $0.toDomain() }) | ||
} | ||
} | ||
|
||
extension DishesResponseDTO.DishDTO { | ||
func toDomain() -> Dish { | ||
return .init(id: id, | ||
name: name, | ||
description: description, | ||
imageURL: topImage, | ||
prices: prices, | ||
badges: badges) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// | ||
// CollectionViewDataSource.swift | ||
// BanchanCode | ||
// | ||
// Created by Song on 2021/04/20. | ||
// | ||
|
||
import UIKit | ||
|
||
class MainPageCollectionViewDataSource: NSObject, UICollectionViewDataSource { | ||
var viewModels: [DishesListViewModel]! | ||
|
||
func numberOfSections(in collectionView: UICollectionView) -> Int { | ||
return viewModels.count | ||
} | ||
|
||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { | ||
return viewModels[section].items.value.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. ๋ต viewModelย ๋ด๋ถ์์ item count๋ฅผ ๋ฐํํ๋ ๋ฉ์๋๋ฅผ ๋ง๋ค์ด ๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค! |
||
} | ||
|
||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { | ||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: DishCell.reuseIdentifier, for: indexPath) as! DishCell | ||
cell.fill(with: viewModels[indexPath.section].items.value[indexPath.row]) | ||
return cell | ||
} | ||
|
||
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { | ||
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: SectionHeaderView.reuseIdentifier, for: indexPath) as! SectionHeaderView | ||
headerView.fill(with: viewModels[indexPath.section]) | ||
headerView.countOfMenus = viewModels[indexPath.section].items.value.count | ||
|
||
return headerView | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// | ||
// CollectionViewDelegate.swift | ||
// BanchanCode | ||
// | ||
// Created by Song on 2021/04/20. | ||
// | ||
|
||
import UIKit | ||
|
||
class MainPageCollectionViewDelegate: NSObject, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout { | ||
|
||
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { | ||
return CGSize(width: collectionView.frame.size.width - 32.0, height: 130.0) | ||
} | ||
|
||
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { | ||
let width: CGFloat = collectionView.frame.width | ||
let height: CGFloat = 32.0 | ||
return CGSize(width: width, height: height) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// | ||
// Dish.swift | ||
// BanchanCode | ||
// | ||
// Created by Song on 2021/04/21. | ||
// | ||
|
||
import Foundation | ||
|
||
struct Dish { | ||
let id: Int | ||
let name: String | ||
let description: String | ||
let imageURL: String | ||
let prices: [Int] | ||
let badges: [String] | ||
} | ||
|
||
struct DishList { | ||
var dishes: [Dish] | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// | ||
// FetchDishesUseCase.swift | ||
// BanchanCode | ||
// | ||
// Created by Song on 2021/04/25. | ||
// | ||
|
||
import Foundation | ||
|
||
protocol FetchDishesUseCase { | ||
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. (1๋ฒ ํผ๋๋ฐฑ) ์ค UseCase๋ ๊ฐ๊ฐ์ ์๋๋ฆฌ์ค๋ฅผ ๋ํ๋ด๋ ์ญํ ์ด๋ผ (์ด๊ธฐ๊ฐ ์ธํ
, ์์ดํ
์ถ๊ฐ ๋ฑ...) ๋์ฌ์ ํํ์ด ์ด๋ฆ์ ํฌํจ๋์ง ์์์ผ ํ ๊น ์๊ฐํ๋๋ฐ ์คํ๋ ค ๋ฉ์๋ ๊ฐ์ ๋๋์ ์ฃผ๋๊ตฐ์. MVVM์ด๋ ํด๋ฆฐ ์ํคํ
์ฒ ์์ ์ฝ๋๋ฅผ ๋ง์ด ๋ณด์ง ๋ชปํ์ง๋ง ์ด๋ฐ ์์ผ๋ก ๋์ฌ๋ฅผ ๋ฃ์ด ๋ค์ด๋ฐ ํ๋ ๊ฒฝ์ฐ๋ฅผ ๋ณด๊ธด ํ๋๋ฐ, ๊ทธ๋ฆฌ ์ผ๋ฐ์ ์ธ ์ปจ๋ฒค์
์ ์๋๊ฑธ๊น์? (4๋ฒ ํผ๋๋ฐฑ) 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. (4๋ฒํผ๋๋ฐฑ) ๋ค๋ค ๋ง์ต๋๋ค. ์๋ฒ์ชฝ์ผ๋ก requestํ๋๊ฑฐ๋ผ๋ฉด url์ด๋ Request๋ง ํ์ํ์ง, category ์์ฒด๊ฐ ํ์ํ ๊ฒ ๊ฐ์ง ์์์์! 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. (4๋ฒ ํผ๋๋ฐฑ) ํ์ฌ url ๊ตฌ์กฐ๊ฐ 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. (1๋ฒ ํผ๋๋ฐฑ) ์ ๋ต, ์ด๊ฑด ์ ๋ ์ด ๋ ํฌ๋ฅผ ๋ณด๋ ๊ทธ๋๋ก ๋ฌ๋ ๋ ๊ฒ ๊ฐ๋ค๊ณ ์๊ฐ๋๋ค์ฌ. 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. (2๋ฒ, 3๋ฒ ํผ๋๋ฐฑ) ๋ค ์ต๋ํ ๋ฒ์ฉ์ ์ผ๋ก ๋ง๋๋ ๊ฑฐ ์ถ์ฒ๋๋ฆฝ๋๋ค. ๊ทธ๋์ผ ์ protocol์ ์ฌ์ฉํ๋์ง ์๋ฟ์ผ์ค ๊ฒ ๊ฐ์์! 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. ์ค ๋ต! ๋งํฌ๋ก ๋ฌ์์ฃผ์ ๋ ํฌ๋ฅผ ๋ง์ด ์ฐธ๊ณ ํ์ฌ MVVM์ ๊ตฌํํ์์ต๋๋คใ
ใ
|
||
func execute(requestValue: FetchDishesUseCaseRequestValue, | ||
completion: @escaping (Result<DishList, Error>) -> Void) | ||
} | ||
|
||
final class DefaultFetchDishesUseCase: FetchDishesUseCase { | ||
func execute(requestValue: FetchDishesUseCaseRequestValue, | ||
completion: @escaping (Result<DishList, Error>) -> Void) { | ||
return fetchDishes(category: requestValue.category, completion: { result in | ||
completion(result) | ||
}) | ||
} | ||
|
||
func fetchDishes(category: Categorizable, | ||
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. ๋ค์ ์ฝ๋๋ฅผ ๋ณด๋ ํ์คํ ํ์ฌ |
||
completion: @escaping (Result<DishList, Error>) -> Void) { | ||
let url = "https://79129275-12cd-405a-80a6-677b968b1977.mock.pstmn.io/banchan-code/\(category.name)" | ||
NetworkManager.performRequest(urlString: url) { (responseDTO) in | ||
completion(.success(responseDTO.toDomain())) | ||
} | ||
} | ||
} | ||
|
||
struct FetchDishesUseCaseRequestValue { | ||
let category: Categorizable | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// | ||
// NetworkManager.swift | ||
// BanchanCode | ||
// | ||
// Created by Song on 2021/04/22. | ||
// | ||
|
||
import Foundation | ||
import Alamofire | ||
|
||
class NetworkManager { | ||
static func performRequest(urlString: String, completionHandler: @escaping (DishesResponseDTO) -> ()) { | ||
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. static์ด ํ
์คํธ๊ฐ ์ด๋ ต๋ค๋ ๊ฒ์ ์์ ์ ๋ค์์๋๋ฐ ๊น๋นก ์๊ฐ์ ๋ชปํ๋ค์! |
||
AF.request(urlString, method: .get) | ||
.validate(statusCode: 200..<300) | ||
.responseDecodable(of: DishesResponseDTO.self) { (response) in | ||
switch response.result { | ||
Comment on lines
+13
to
+16
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. Alamofire๋ฅผ ์ฌ์ฉํด request ์์ฒญํ๋ ๋ถ๋ถ์ ๋ฐ๋ก protocol๋ก ๊ตฌํํด 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.
=> ์ ์ง๊ธ ๋ณด๋, AF๊ฐ Networkmanager ์์ฒด์ ์ญํ ์ ํด๋ ๋ ๊ฒ ๊ฐ์ต๋๋ค.
=> ์์๋๋ก ์์ ํ๋ฉด ๊ฐ Usecase ๊ฐ networkmanager๋ฅผ ์์ฑ์๋ฅผ ํตํ ์์กด์ฑ ์ฃผ์
๋ฐ ์์กด์ฑ ์ญ์ ์์น์ ํ๋ฉด ๋๊ฒ ๋ค์! 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 .success(let dishes): | ||
completionHandler(dishes) | ||
case .failure(let error): | ||
print(error.localizedDescription) | ||
} | ||
} | ||
} | ||
} |
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.
List
๋ผ๋ ํํ์ ํ๋ก๊ทธ๋๋จธ์๊ฒ ํน์ํ ์๋ฏธ์ ๋๋ค. ๋ฐ๋ผ์ ์๋ฃ๊ตฌ์กฐ ์ค ํ๋์ธ List ๊ฐ ์๋๋ผ๋ฉด ๋ค๋ฅธ ์ด๋ฆ์ผ๋ก ์ง๋ ๊ฒ์ด ์ด๋จ๊น์?(์ค์ ์ปจํ ์ด๋๊ฐ List์ธ ๊ฒฝ์ฐ๋ผ๋ ์ปจํ ์ด๋ ์ ํ์ ์ด๋ฆ์ ๋ฃ์ง ์๋ ํธ์ด ๋ฐ๋์งํฉ๋๋ค)ํด๋ฆฐ์ฝ๋ 2์ฅ ์๋ฏธ์๋ ์ด๋ฆ ์ค ๊ทธ๋ฆ๋ ์ ๋ณด๋ฅผ ํผํ๋ผ๋ ๊ฐ์ ๋ด์ฉ์ด๋ ์ฐธ๊ณ ํ์ ๋ ๋ฉ๋๋ค!
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.
์ค ์์ง List ํ์ ์ ๋ง์ด ์ฌ์ฉํด๋ณธ ์ ์ด ์์ด์ ๊ทธ๋ฐ ์๋ฏธ๊ฐ ์์๋์ง ๋ชฐ๋๋ค์. ์๋ ค์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค!
ํด๋ฆฐ์ฝ๋๋ ์ฝ์ด๋ณด๊ฒ ์ต๋๋ค :)