Skip to content
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

일기장 [Step3] RedMango, Minsup #141

Open
wants to merge 2 commits into
base: ic_9_redmango
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 76 additions & 10 deletions Diary.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,21 @@
objects = {

/* Begin PBXBuildFile section */
1F38B51E2AB4223D0010EB00 /* NetworkError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F38B51D2AB4223D0010EB00 /* NetworkError.swift */; };
1F38B5202AB424D00010EB00 /* WeatherDecodingError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F38B51F2AB424D00010EB00 /* WeatherDecodingError.swift */; };
1F38B5232AB427090010EB00 /* WeatherFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F38B5222AB427090010EB00 /* WeatherFetcher.swift */; };
1F5CEE8D2A9D97AF00521AB3 /* DiaryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F5CEE8C2A9D97AF00521AB3 /* DiaryCell.swift */; };
1F5F22922AAA043400CB920D /* DiaryContentComposable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F5F22912AAA043400CB920D /* DiaryContentComposable.swift */; };
1F5F22942AAA049500CB920D /* DiaryContentCompositor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F5F22932AAA049500CB920D /* DiaryContentCompositor.swift */; };
1F5F22972AAA04E500CB920D /* DiaryContentSegregatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F5F22962AAA04E500CB920D /* DiaryContentSegregatable.swift */; };
1F5F229A2AAA051200CB920D /* DiaryContentSegregator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F5F22992AAA051200CB920D /* DiaryContentSegregator.swift */; };
1F5F229F2AAA07C400CB920D /* DateFormattable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F5F229E2AAA07C400CB920D /* DateFormattable.swift */; };
1F5F22A22AAA087A00CB920D /* CurrentDateFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F5F22A12AAA087A00CB920D /* CurrentDateFormatter.swift */; };
1F99E86C2AB2E68400DA0038 /* Model.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = 1F99E86B2AB2E68400DA0038 /* Model.xcmappingmodel */; };
1F99E86F2AB2E83A00DA0038 /* LocationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F99E86E2AB2E83A00DA0038 /* LocationManager.swift */; };
1F99E8722AB2F62200DA0038 /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F99E8712AB2F62200DA0038 /* NetworkManager.swift */; };
1F99E8752AB2F85300DA0038 /* Weather.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F99E8742AB2F85300DA0038 /* Weather.swift */; };
1F99E8782AB2F9CA00DA0038 /* WeatherDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1F99E8772AB2F9CA00DA0038 /* WeatherDecoder.swift */; };
1FDFB3B22AA607FE005128C3 /* DataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FDFB3B12AA607FE005128C3 /* DataManager.swift */; };
5D2CF6FF2A9CBB4A009EECB3 /* .swiftlint.yml in Resources */ = {isa = PBXBuildFile; fileRef = 5D2CF6FE2A9CBB4A009EECB3 /* .swiftlint.yml */; };
5D2CF70D2A9F0520009EECB3 /* DiaryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D2CF70C2A9F0520009EECB3 /* DiaryViewController.swift */; };
Expand All @@ -26,13 +34,22 @@
/* End PBXBuildFile section */

/* Begin PBXFileReference section */
1F38B51D2AB4223D0010EB00 /* NetworkError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkError.swift; sourceTree = "<group>"; };
1F38B51F2AB424D00010EB00 /* WeatherDecodingError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherDecodingError.swift; sourceTree = "<group>"; };
1F38B5222AB427090010EB00 /* WeatherFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherFetcher.swift; sourceTree = "<group>"; };
1F5CEE8C2A9D97AF00521AB3 /* DiaryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiaryCell.swift; sourceTree = "<group>"; };
1F5F22912AAA043400CB920D /* DiaryContentComposable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiaryContentComposable.swift; sourceTree = "<group>"; };
1F5F22932AAA049500CB920D /* DiaryContentCompositor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiaryContentCompositor.swift; sourceTree = "<group>"; };
1F5F22962AAA04E500CB920D /* DiaryContentSegregatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiaryContentSegregatable.swift; sourceTree = "<group>"; };
1F5F22992AAA051200CB920D /* DiaryContentSegregator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiaryContentSegregator.swift; sourceTree = "<group>"; };
1F5F229E2AAA07C400CB920D /* DateFormattable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateFormattable.swift; sourceTree = "<group>"; };
1F5F22A12AAA087A00CB920D /* CurrentDateFormatter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentDateFormatter.swift; sourceTree = "<group>"; };
1F99E86A2AB2DEE300DA0038 /* Diary v2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Diary v2.xcdatamodel"; sourceTree = "<group>"; };
1F99E86B2AB2E68400DA0038 /* Model.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = Model.xcmappingmodel; sourceTree = "<group>"; };
1F99E86E2AB2E83A00DA0038 /* LocationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationManager.swift; sourceTree = "<group>"; };
1F99E8712AB2F62200DA0038 /* NetworkManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = "<group>"; };
1F99E8742AB2F85300DA0038 /* Weather.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Weather.swift; sourceTree = "<group>"; };
1F99E8772AB2F9CA00DA0038 /* WeatherDecoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherDecoder.swift; sourceTree = "<group>"; };
1FDFB3B12AA607FE005128C3 /* DataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataManager.swift; sourceTree = "<group>"; };
1FDFB3B42AA63E65005128C3 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/LaunchScreen.strings; sourceTree = "<group>"; };
5D2CF6FE2A9CBB4A009EECB3 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftlint.yml; sourceTree = "<group>"; };
Expand All @@ -58,6 +75,23 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
1F38B51C2AB41EDB0010EB00 /* Utils */ = {
isa = PBXGroup;
children = (
1F99E8772AB2F9CA00DA0038 /* WeatherDecoder.swift */,
1F38B51F2AB424D00010EB00 /* WeatherDecodingError.swift */,
);
path = Utils;
sourceTree = "<group>";
};
1F38B5212AB426B80010EB00 /* WeatherFetcher */ = {
isa = PBXGroup;
children = (
1F38B5222AB427090010EB00 /* WeatherFetcher.swift */,
);
path = WeatherFetcher;
sourceTree = "<group>";
};
1F5CEE882A9CC44A00521AB3 /* Application */ = {
isa = PBXGroup;
children = (
Expand All @@ -78,6 +112,7 @@
1F5CEE8A2A9CC45800521AB3 /* Controller */ = {
isa = PBXGroup;
children = (
1F5F229B2AAA076D00CB920D /* Utils */,
C739AE28284DF28600741E8F /* MainViewController.swift */,
5D2CF70C2A9F0520009EECB3 /* DiaryViewController.swift */,
);
Expand All @@ -90,7 +125,6 @@
C739AE32284DF28600741E8F /* LaunchScreen.storyboard */,
C739AE30284DF28600741E8F /* Assets.xcassets */,
C739AE35284DF28600741E8F /* Info.plist */,
C739AE2D284DF28600741E8F /* Diary.xcdatamodeld */,
);
path = Resource;
sourceTree = "<group>";
Expand Down Expand Up @@ -157,6 +191,8 @@
1F5F229B2AAA076D00CB920D /* Utils */ = {
isa = PBXGroup;
children = (
1F38B5212AB426B80010EB00 /* WeatherFetcher */,
1F5F228C2AAA03D000CB920D /* ContentHelper */,
1F5F229C2AAA078400CB920D /* DateFormat */,
);
path = Utils;
Expand Down Expand Up @@ -187,28 +223,46 @@
path = Implementation;
sourceTree = "<group>";
};
1FDFB3AF2AA60764005128C3 /* Diary */ = {
1F99E86D2AB2E81800DA0038 /* Location */ = {
isa = PBXGroup;
children = (
1F5F228C2AAA03D000CB920D /* ContentHelper */,
1F99E86E2AB2E83A00DA0038 /* LocationManager.swift */,
);
path = Diary;
path = Location;
sourceTree = "<group>";
};
1F99E8702AB2F61600DA0038 /* Network */ = {
isa = PBXGroup;
children = (
1F99E8712AB2F62200DA0038 /* NetworkManager.swift */,
1F38B51D2AB4223D0010EB00 /* NetworkError.swift */,
);
path = Network;
sourceTree = "<group>";
};
1FDFB3B02AA607EE005128C3 /* Persistance */ = {
1F99E8732AB2F82C00DA0038 /* Weather */ = {
isa = PBXGroup;
children = (
1F38B51C2AB41EDB0010EB00 /* Utils */,
1F99E8742AB2F85300DA0038 /* Weather.swift */,
);
path = Weather;
sourceTree = "<group>";
};
1FDFB3B02AA607EE005128C3 /* CoreData */ = {
isa = PBXGroup;
children = (
C739AE2D284DF28600741E8F /* Diary.xcdatamodeld */,
1F99E86B2AB2E68400DA0038 /* Model.xcmappingmodel */,
1FDFB3B12AA607FE005128C3 /* DataManager.swift */,
);
path = Persistance;
path = CoreData;
sourceTree = "<group>";
};
5D2CF7062A9CC7C8009EECB3 /* Model */ = {
isa = PBXGroup;
children = (
1F5F229B2AAA076D00CB920D /* Utils */,
1FDFB3B02AA607EE005128C3 /* Persistance */,
1FDFB3AF2AA60764005128C3 /* Diary */,
1F99E8732AB2F82C00DA0038 /* Weather */,
);
path = Model;
sourceTree = "<group>";
Expand All @@ -233,6 +287,9 @@
C739AE23284DF28600741E8F /* Diary */ = {
isa = PBXGroup;
children = (
1FDFB3B02AA607EE005128C3 /* CoreData */,
1F99E86D2AB2E81800DA0038 /* Location */,
1F99E8702AB2F61600DA0038 /* Network */,
5D2CF7062A9CC7C8009EECB3 /* Model */,
1F5CEE8B2A9CC45D00521AB3 /* Resource */,
1F5CEE8A2A9CC45800521AB3 /* Controller */,
Expand Down Expand Up @@ -336,19 +393,27 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
1F38B5232AB427090010EB00 /* WeatherFetcher.swift in Sources */,
1F5F22942AAA049500CB920D /* DiaryContentCompositor.swift in Sources */,
1F99E8752AB2F85300DA0038 /* Weather.swift in Sources */,
1F5F229F2AAA07C400CB920D /* DateFormattable.swift in Sources */,
1F99E86F2AB2E83A00DA0038 /* LocationManager.swift in Sources */,
1F5F229A2AAA051200CB920D /* DiaryContentSegregator.swift in Sources */,
1F99E8722AB2F62200DA0038 /* NetworkManager.swift in Sources */,
C739AE29284DF28600741E8F /* MainViewController.swift in Sources */,
1F5F22972AAA04E500CB920D /* DiaryContentSegregatable.swift in Sources */,
1F38B5202AB424D00010EB00 /* WeatherDecodingError.swift in Sources */,
C739AE25284DF28600741E8F /* AppDelegate.swift in Sources */,
1F99E8782AB2F9CA00DA0038 /* WeatherDecoder.swift in Sources */,
5D2CF70D2A9F0520009EECB3 /* DiaryViewController.swift in Sources */,
1F5CEE8D2A9D97AF00521AB3 /* DiaryCell.swift in Sources */,
C739AE27284DF28600741E8F /* SceneDelegate.swift in Sources */,
1F5F22922AAA043400CB920D /* DiaryContentComposable.swift in Sources */,
1F5F22A22AAA087A00CB920D /* CurrentDateFormatter.swift in Sources */,
1FDFB3B22AA607FE005128C3 /* DataManager.swift in Sources */,
C739AE2F284DF28600741E8F /* Diary.xcdatamodeld in Sources */,
1F99E86C2AB2E68400DA0038 /* Model.xcmappingmodel in Sources */,
1F38B51E2AB4223D0010EB00 /* NetworkError.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -568,9 +633,10 @@
C739AE2D284DF28600741E8F /* Diary.xcdatamodeld */ = {
isa = XCVersionGroup;
children = (
1F99E86A2AB2DEE300DA0038 /* Diary v2.xcdatamodel */,
C739AE2E284DF28600741E8F /* Diary.xcdatamodel */,
);
currentVersion = C739AE2E284DF28600741E8F /* Diary.xcdatamodel */;
currentVersion = 1F99E86A2AB2DEE300DA0038 /* Diary v2.xcdatamodel */;
path = Diary.xcdatamodeld;
sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel;
Expand Down
2 changes: 1 addition & 1 deletion Diary/Application/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {

var window: UIWindow?
let dataManager: DataManager = DataManager()

func scene(
_ scene: UIScene,
willConnectTo session: UISceneSession,
Expand Down
16 changes: 9 additions & 7 deletions Diary/Controller/DiaryViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ final class DiaryViewController: UIViewController {
private let compositor: DiaryContentComposable
private let segregator: DiaryContentSegregatable
private let currentFormatter: DateFormattable
private let weatherFetcher: WeatherFetcher

// MARK: - Lifecycle

Expand All @@ -26,16 +27,15 @@ final class DiaryViewController: UIViewController {
) {
self.dataManager = dataManager
self.currentFormatter = formatter
self.compositor = DiaryContentCompositor()
self.segregator = DiaryContentSegregator()
self.weatherFetcher = WeatherFetcher()

if let diary = diary {
self.diary = diary
} else {
self.diary = Diary(context: dataManager.container.viewContext)
}

self.compositor = DiaryContentCompositor()
self.segregator = DiaryContentSegregator()

super.init(nibName: nil, bundle: nil)
}

Expand All @@ -60,6 +60,9 @@ final class DiaryViewController: UIViewController {
super.viewDidAppear(animated)
if self.textView.text.isEmpty {
textView.becomeFirstResponder()
self.weatherFetcher.fetch { pngData in
self.diary.weatherImage = pngData
}
}
}

Expand All @@ -69,7 +72,7 @@ final class DiaryViewController: UIViewController {
let trimmedText = self.textView.text.trimmingCharacters(in: .whitespacesAndNewlines)

if trimmedText.isEmpty {
self.dataManager.container.viewContext.delete(self.diary)
self.dataManager.delete(self.diary)
return
}

Expand Down Expand Up @@ -169,8 +172,7 @@ final class DiaryViewController: UIViewController {
)

let delete = UIAlertAction(title: "삭제", style: .destructive) { [weak self] _ in
self?.dataManager.container.viewContext.delete(diary)
self?.dataManager.saveContext()
self?.dataManager.delete(diary)
self?.navigationController?.popViewController(animated: true)
}

Expand Down
3 changes: 1 addition & 2 deletions Diary/Controller/MainViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,7 @@ final class MainViewController: UIViewController {
let deleteAlert = UIAlertController(title: "진짜요?", message: "정말로 삭제하시겠어요?", preferredStyle: .alert)

let delete = UIAlertAction(title: "삭제", style: .destructive) { [weak self] _ in
self?.dataManager.container.viewContext.delete(diary)
self?.dataManager.saveContext()
self?.dataManager.delete(diary)
self?.readDiaries()
}

Expand Down
32 changes: 32 additions & 0 deletions Diary/Controller/Utils/WeatherFetcher/WeatherFetcher.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// WeatherFetcher.swift
// Diary
//
// Created by 김민성 on 2023/09/15.
//

import Foundation
import UIKit

struct WeatherFetcher {
let locationManager: LocationManager

init(locationManager: LocationManager = LocationManager()) {
self.locationManager = locationManager
}

Comment on lines +11 to +17
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WeatherFetcher 내에서 현재의 경,위도 정보만 필요한거라면
해당 값만 주입받는 방법은 어떨까요?
LocationManager 객체 자체를 들고있기엔 현재 구조체의 기능이나 책임이 조금 모호하게 비대한 느낌이 들어요

func fetch(_ completion: @escaping (Data?) -> Void) {
locationManager.fetchSingleLocation { location in
Task {
Comment on lines +18 to +20
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

location을 전달받을 때 꼭 클로저로 전달받아야 하나요?

do {
let weather = try await NetworkManager.fetchCurrentWeather(coordinate: location.coordinate)

let icon = try await NetworkManager.fetchWeatherIcon(icon: weather?.icon)
completion(icon)
} catch {
completion(nil)
}
Comment on lines +21 to +28
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NetworkManager 내의 fetch~ 메서드들은 throws로 에러를 던지고있는데,
여기선 관련한 처리는 없고 실패하면 그냥 nil을 전달할 뿐이네요.
실패했을 때 어떻게 핸들링하면 좋을까요?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그리고 해당 객체는 WeatherFetcher인데, 정작 날씨 관련 정보를 가지고 오는 건 NetworkManager 내부의 메서드가 하는 것 같아요.
어떤 기준으로 해당 객체들의 책임을 나누셨나요?

}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import CoreData
final class DataManager {
lazy var container: NSPersistentContainer = {
let container = NSPersistentContainer(name: "Diary")

container.loadPersistentStores(completionHandler: { ( _, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
Expand All @@ -18,6 +19,11 @@ final class DataManager {
return container
}()

func delete(_ diary: Diary) {
container.viewContext.delete(diary)
saveContext()
}

func saveContext () {
let context = container.viewContext
if context.hasChanges {
Expand All @@ -32,8 +38,11 @@ final class DataManager {

func fetch() -> [Diary] {
let context = container.viewContext
let request = Diary.fetchRequest()
let createdDateSort = NSSortDescriptor(keyPath: \Diary.createdDate, ascending: false)
request.sortDescriptors = [createdDateSort]
do {
return try context.fetch(Diary.fetchRequest())
return try context.fetch(request)
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
<plist version="1.0">
<dict>
<key>_XCCurrentVersionName</key>
<string>Diary.xcdatamodel</string>
<string>Diary v2.xcdatamodel</string>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="21513" systemVersion="21G651" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="Diary" representedClassName="Diary" syncable="YES" codeGenerationType="class">
<attribute name="content" optional="YES" attributeType="String"/>
<attribute name="createdDate" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="title" optional="YES" attributeType="String"/>
<attribute name="weatherImage" optional="YES" attributeType="Binary"/>
</entity>
</model>
Loading