Skip to content

Commit 4a71872

Browse files
authored
[Refactor] #520 - DateFormatter() 인스턴스 메모리 최적화
2 parents 57d2f1f + 502d79d commit 4a71872

File tree

17 files changed

+180
-154
lines changed

17 files changed

+180
-154
lines changed
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
//
2+
// DateFormatType.swift
3+
// Core
4+
//
5+
// Created by 강윤서 on 3/27/25.
6+
// Copyright © 2025 SOPT-iOS. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
public enum DateFormatType: String {
12+
case iso = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
13+
case isoWithoutMillis = "yyyy-MM-dd'T'HH:mm:ss"
14+
case dateTimeDash = "yyyy-MM-dd HH:mm:ss"
15+
case dateWithDot = "yyyy.MM.dd"
16+
case dateWithDash = "yyyy-MM-dd"
17+
case dateWithSlash = "yy/MM/dd"
18+
case monthDayWeek = "M월 d일 EEEE"
19+
case monthDayWeekTime = "M월 d일 EEEE H:mm"
20+
case monthDayWeekFullTime = "M월 d일 EEEE HH:mm"
21+
case monthDayWithDot = "MM.dd"
22+
case monthDayWIthDash = "MM-dd"
23+
case time = "HH:mm"
24+
case networkLogger = "dd/MM/yyyy HH:mm:ss"
25+
}

Diff for: SOPT-iOS/Projects/Core/Sources/Extension/Foundation+/String+.swift

+4-7
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,8 @@ public extension String {
1919

2020
/// 서버에서 들어온 Date String을 Date 타입으로 반환하는 메서드
2121
func toDate() -> Date {
22-
let dateFormatter = DateFormatter()
23-
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
24-
dateFormatter.timeZone = TimeZone(identifier: "KST")
25-
if let date = dateFormatter.date(from: self) {
22+
DateFormatManager.shared.setFormat(.iso)
23+
if let date = DateFormatManager.shared.stringToDate(self) {
2624
return date
2725
} else {
2826
print("toDate() convert error")
@@ -38,8 +36,7 @@ public extension String {
3836

3937
/// 서버에서 들어온 Date String을 UI에 적용 가능한 String 타입으로 반환하는 메서드
4038
func serverTimeToString(forUse: TimeStringCase) -> String {
41-
let dateFormatter = DateFormatter()
42-
dateFormatter.dateFormat = "yy/MM/dd"
39+
DateFormatManager.shared.setFormat(.dateWithSlash)
4340

4441
let currentTime = Int(Date().timeIntervalSince1970)
4542

@@ -61,7 +58,7 @@ public extension String {
6158
return "방금"
6259
}
6360
case .forDefault:
64-
return dateFormatter.string(from: self.toDate())
61+
return DateFormatManager.shared.dateToString(self.toDate())
6562
}
6663
}
6764

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//
2+
// DateFormatterManager.swift
3+
// Core
4+
//
5+
// Created by 강윤서 on 3/27/25.
6+
// Copyright © 2025 SOPT-iOS. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
public final class DateFormatManager {
12+
public static let shared = DateFormatManager()
13+
14+
private init() {
15+
formatter.locale = Locale(identifier: "ko_KR")
16+
formatter.timeZone = TimeZone(identifier: "Asia/Seoul")
17+
}
18+
19+
private var formatter = DateFormatter()
20+
}
21+
22+
public extension DateFormatManager {
23+
func setFormat(_ format: DateFormatType) {
24+
formatter.dateFormat = format.rawValue
25+
}
26+
27+
/// 문자열을 원하는 포맷의 Date타입으로 변환
28+
func stringToDate(_ value: String) -> Date? {
29+
return formatter.date(from: value)
30+
}
31+
32+
/// date타입을 원하는 포맷의 문자열로 변환
33+
func dateToString(_ date: Date) -> String {
34+
return formatter.string(from: date)
35+
}
36+
37+
/// 문자열 날짜를 원하는 포맷의 String타입으로 변환
38+
/// 변경할 값이 비어있다면 오늘 날짜를 반환
39+
func transformDateFormat(_ target: String? = nil, from before: DateFormatType? = nil, to after: DateFormatType) -> String {
40+
guard let target, let before
41+
else {
42+
setFormat(after)
43+
return dateToString(Date())
44+
}
45+
46+
setFormat(before)
47+
guard let date = stringToDate(target) else { return "00:00" }
48+
49+
setFormat(after)
50+
return formatter.string(from: date)
51+
}
52+
53+
/// 서버에서 내려주는 iSO 포맷 타입을 원하는 타입으로 변환
54+
func serverTimeToString(_ target: String, from format: DateFormatType, to serverFormat: DateFormatType = .iso) -> String {
55+
setFormat(serverFormat)
56+
guard let date = stringToDate(target) else { return "" }
57+
58+
setFormat(format)
59+
return dateToString(date)
60+
}
61+
62+
/// 시작 날짜와 종료 날짜 입력 받아 원하는 포맷으로 변경 후 문자열로 반환
63+
func formatTimeInterval(start: String, end: String) -> String {
64+
setFormat(.monthDayWeekFullTime)
65+
66+
guard let startDate = stringToDate(start),
67+
let endDate = stringToDate(end)
68+
else { return "" }
69+
70+
let startString = dateToString(startDate)
71+
72+
setFormat(.time)
73+
let endString = dateToString(endDate)
74+
75+
return "\(startString) ~ \(endString)"
76+
}
77+
}

Diff for: SOPT-iOS/Projects/Core/Sources/Utils/setDateFormat.swift

-40
This file was deleted.

Diff for: SOPT-iOS/Projects/Data/Sources/Transform/AttendanceScheduleTransform.swift

+3-4
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,8 @@ extension TodayAttendance {
3030

3131
public func toDomain() -> TodayAttendanceModel {
3232
return .init(status: self.status,
33-
attendedAt: setDateFormat(
34-
date: self.attendedAt,
35-
from: "yyyy-MM-dd'T'HH:mm:ss",
36-
to: "HH:mm"))
33+
attendedAt: DateFormatManager.shared.transformDateFormat(self.attendedAt,
34+
from: .dateTimeDash,
35+
to: .time))
3736
}
3837
}

Diff for: SOPT-iOS/Projects/Data/Sources/Transform/ListDetailTransform.swift

+1-5
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,11 @@ extension ListDetailEntity {
1616
return ListDetailModel(
1717
image: self.images.first ?? "",
1818
content: self.contents,
19-
date: changeDateformat(self.updatedAt ?? self.createdAt),
19+
date: self.updatedAt ?? self.createdAt,
2020
stampId: self.id,
2121
activityDate: self.activityDate
2222
)
2323
}
24-
25-
private func changeDateformat(_ date: String) -> String {
26-
return date.split(separator: "-").joined(separator: ".")
27-
}
2824
}
2925

3026
extension StampEntity {

Diff for: SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/VC/ShowAttendanceVC.swift

+1-2
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,7 @@ extension ShowAttendanceVC {
286286
private func setScheduledData(_ model: AttendanceScheduleModel) {
287287

288288
if self.sceneType == .scheduledDay {
289-
let date = viewModel.formatTimeInterval(startDate: model.startDate,
290-
endDate: model.endDate)
289+
let date = DateFormatManager.shared.formatTimeInterval(start: model.startDate, end: model.endDate)
291290
headerScheduleView.setData(date: date,
292291
place: model.location,
293292
todaySchedule: model.name,

Diff for: SOPT-iOS/Projects/Features/AttendanceFeature/Sources/ShowAttendanceScene/ViewModel/ShowAttendanceViewModel.swift

+6-32
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,12 @@ extension ShowAttendanceViewModel {
9191
if model.type != SessionType.noSession.rawValue {
9292
self.sceneType = .scheduledDay
9393

94-
let convertedStartDate = self.convertDateString(model.startDate)
95-
let convertedEndDate = self.convertDateString(model.endDate)
96-
94+
let convertedStartDate = DateFormatManager.shared.serverTimeToString(model.startDate,
95+
from: .isoWithoutMillis,
96+
to: .monthDayWeekTime)
97+
let convertedEndDate = DateFormatManager.shared.serverTimeToString(model.endDate,
98+
from: .isoWithoutMillis,
99+
to: .monthDayWeekTime)
97100
let newModel = AttendanceScheduleModel(type: model.type,
98101
id: model.id,
99102
location: model.location,
@@ -154,33 +157,4 @@ extension ShowAttendanceViewModel {
154157
}
155158
.store(in: self.cancelBag)
156159
}
157-
158-
private func convertDateString(_ dateString: String) -> String {
159-
let dateFormatter = DateFormatter()
160-
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
161-
dateFormatter.locale = Locale(identifier: "ko_KR")
162-
dateFormatter.timeZone = TimeZone(identifier: "Asia/Seoul")
163-
164-
guard let date = dateFormatter.date(from: dateString) else { return "" }
165-
166-
dateFormatter.dateFormat = "M월 d일 EEEE H:mm"
167-
return dateFormatter.string(from: date)
168-
}
169-
170-
func formatTimeInterval(startDate: String, endDate: String) -> String {
171-
let dateFormatter = DateFormatter()
172-
dateFormatter.dateFormat = "M월 d일 EEEE HH:mm"
173-
dateFormatter.locale = Locale(identifier: "ko_KR")
174-
dateFormatter.timeZone = TimeZone(identifier: "Asia/Seoul")
175-
176-
guard let startDateObject = dateFormatter.date(from: startDate),
177-
let endDateObject = dateFormatter.date(from: endDate) else { return "" }
178-
179-
let formattedStartDate = dateFormatter.string(from: startDateObject)
180-
181-
dateFormatter.dateFormat = "HH:mm"
182-
let formattedEndDate = dateFormatter.string(from: endDateObject)
183-
184-
return "\(formattedStartDate) ~ \(formattedEndDate)"
185-
}
186160
}

Diff for: SOPT-iOS/Projects/Features/DailySoptuneFeature/Sources/DailySoptuneScene/VC/DailySoptuneMainVC.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public final class DailySoptuneMainVC: UIViewController, DailySoptuneMainViewCon
4141
private let dateLabel = UILabel().then {
4242
$0.textColor = DSKitAsset.Colors.gray100.color
4343
$0.font = DSKitFontFamily.Suit.medium.font(size: 16)
44-
$0.text = setDateFormat(to: "M월 d일 EEEE")
44+
$0.text = DateFormatManager.shared.transformDateFormat(to: .monthDayWeek)
4545
}
4646

4747
private let recieveFortune = UILabel().then {

Diff for: SOPT-iOS/Projects/Features/DailySoptuneFeature/Sources/DailySoptuneScene/ViewModel/DailySoptuneMainViewModel.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ extension DailySoptuneMainViewModel {
6565
input.receiveTodayFortuneButtonTap
6666
.withUnretained(self)
6767
.sink { owner, _ in
68-
owner.useCase.getDailySoptuneResult(date: setDateFormat(to: "yyyy-MM-dd"))
68+
owner.useCase.getDailySoptuneResult(date: DateFormatManager.shared.transformDateFormat(to: .dateWithDash))
6969
AmplitudeInstance.shared.track(eventType: .clickCheckTodaySoptune)
7070
}.store(in: cancelBag)
7171

Diff for: SOPT-iOS/Projects/Features/DailySoptuneFeature/Sources/DailySoptuneScene/Views/DailySoptuneResultContentView.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ extension DailySoptuneResultContentView {
9696

9797
extension DailySoptuneResultContentView {
9898
public func setData(model: DailySoptuneResultModel) {
99-
self.dateLabel.text = setDateFormat(to: "MM월 d일 EEEE")
99+
self.dateLabel.text = DateFormatManager.shared.transformDateFormat(to: .monthDayWeek)
100100
self.contentLabel.text = "\(model.userName)님,\n\(model.title.setLineBreakAtMiddle())"
101101
self.contentLabel.setLineSpacing(lineSpacing: 5)
102102
self.contentLabel.textAlignment = .center

Diff for: SOPT-iOS/Projects/Features/HomeFeature/Sources/HomeScene/Cells/Calendar/CalendarCardCVC.swift

+1-2
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,7 @@ extension CalendarCardCVC {
128128
extension CalendarCardCVC {
129129
func configureCell(model: HomePresentationModel.RecentSchedule,
130130
userType: UserType) {
131-
// TODO: 서버 - 날짜 포맷 변경 후 반영
132-
self.dateLabel.text = setDateFormat(date: model.date, to: "MM.dd")
131+
self.dateLabel.text = model.date
133132
self.scheduleTitleLabel.text = model.title
134133
if let tagType = CalenderCategoryTagType(rawValue: model.type) {
135134
self.scheduleCategoryTagView.setData(title: tagType.text,

Diff for: SOPT-iOS/Projects/Features/HomeFeature/Sources/HomeScene/Models/HomePresentationModel.swift

+5-1
Original file line numberDiff line numberDiff line change
@@ -221,11 +221,15 @@ extension HomeDescriptionModel {
221221
extension HomeRecentScheduleModel {
222222
func toPresentation() -> HomePresentationModel.RecentSchedule {
223223
return HomePresentationModel.RecentSchedule(
224-
date: self.date,
224+
date: changeFormat(self.date),
225225
type: self.type,
226226
title: self.title
227227
)
228228
}
229+
230+
private func changeFormat(_ dateString: String) -> String {
231+
return dateString.split(separator: "-").joined(separator: ".")
232+
}
229233
}
230234

231235
extension HomeAppServicesModel {

Diff for: SOPT-iOS/Projects/Features/SoptlogFeature/Sources/SoptlogScene/Model/SoptlogPresentationModel.swift

+46
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88

99
import Foundation
1010

11+
import Core
12+
import Domain
13+
1114
struct SoptlogPresentationModel {
1215
let profile: Profile
1316
let introduce: Introduce
@@ -35,3 +38,46 @@ struct SoptlogPresentationModel {
3538
let todayFortuneText: String
3639
}
3740
}
41+
42+
extension SoptlogModel {
43+
func toPresentation() -> SoptlogPresentationModel {
44+
var appService: [SoptlogPresentationModel.AppService] = []
45+
appService.append(SoptlogPresentationModel.AppService(
46+
serviceName: I18N.Soptlog.soptlevel,
47+
serviceImageURL: self.icons[0],
48+
serviceValue: self.soptLevel))
49+
appService.append(SoptlogPresentationModel.AppService(
50+
serviceName: I18N.Soptlog.poke,
51+
serviceImageURL: self.icons[1],
52+
serviceValue: self.pokeCount))
53+
54+
if self.isActive {
55+
appService.append(SoptlogPresentationModel.AppService(
56+
serviceName: I18N.Soptlog.soptamp,
57+
serviceImageURL: self.icons[2],
58+
serviceValue: self.soptampRank))
59+
} else {
60+
appService.append(SoptlogPresentationModel.AppService(
61+
serviceName: I18N.Soptlog.withSopt,
62+
serviceImageURL: self.icons[2],
63+
serviceValue: self.during))
64+
}
65+
66+
67+
return SoptlogPresentationModel(
68+
profile: SoptlogPresentationModel.Profile(
69+
userName: self.userName,
70+
profileImage: self.profileImage,
71+
part: self.part
72+
),
73+
introduce: SoptlogPresentationModel.Introduce(
74+
profileMessage: self.profileMessage
75+
),
76+
appService: appService,
77+
alarm: SoptlogPresentationModel.Alarm(
78+
isFortuneChecked: self.isFortuneChecked,
79+
todayFortuneText: self.todayFortuneText
80+
)
81+
)
82+
}
83+
}

0 commit comments

Comments
 (0)