diff --git a/geunwoong/WeekAssign02/README.md b/geunwoong/WeekAssign02/README.md
new file mode 100644
index 0000000..a35cc57
--- /dev/null
+++ b/geunwoong/WeekAssign02/README.md
@@ -0,0 +1,135 @@
+
+# 주간과제 - CLI 회고 시스템
+
+## 프로젝트 설명
+What : CLI 기반의 회고시스템(Reflection System)을 개발
+
+Why : Swift 학습자가 실습을 통해 기초 문법을 익히고 프로젝트 개발 경험을 쌓음
+
+## 파일 분석
+각 파일의 헤드에 주석추가
+```swift
+/*
+ File: 파일명.swift
+ Purpose: 해당 파일의 목적
+
+ Data
+ - 파일에서 사용하는 data에 대한 설명
+
+ etc
+ - 추가적인 설명, 나중에 바꾸면 좋겠는것 등을 작성
+*/
+```
+
+## 데이터 구조
+### Reflection 구조체를 사용
+
+|속성|타입|설명|
+|---|---|---|
+|date|String|회고 작성 날짜|
+|content|String|회고 내용|
+```swift
+struct Reflection {
+ var date: String
+ var content: String
+}
+```
+### ReflectionSystem 클래스를 싱글톤으로 전체 프로그램으로 사용
+```swift
+class ReflectionSystem {
+ static let shared = ReflectionSystem()
+ private init() { }
+ func run() { }
+}
+```
+### ReflectionSystemDB 클래스를 싱글톤으로 DB로 사용
+|속성|Value|KEY|설명|
+|---|---|---|---|
+|DB|Reflection|Date-String|회고 정보를 담은 DB|
+```swift
+class ReflectionSystemDB {
+ static let shared = ReflectionSystemDB()
+ private var DB: [String:Reflection] = [:]
+ private init() { }
+}
+```
+
+## 기능 목록 및 설명 (CRUD)
+
+|기능|설명|입력|출력|함수|
+|---|---|---|---|---|
+|회고 추가|특정 날짜에 회고 내용을 추가|날짜: 2025-02-09
내용: 오늘은 Swift를 공부했다.|회고가 추가되었습니다.|AddReflection|
+|회고 조회|특정 날짜의 회고 내용을 검색|날짜: 2025-02-09|날짜: 2025-02-09
내용: 오늘은 Swift를 공부했다.|SearchReflection|
+|회고 수정|특정 날짜의 회고 내용을 수정|날짜: 2025-02-09
새로운 내용: Swift 프로젝트를 진행했다.|회고가 수정되었습니다.|EditReflection|
+|회고 삭제|특정 날짜의 회고 내용을 삭제|날짜: 2025-02-09|회고가 삭제되었습니다.|DeleteReflection|
+|전체 회고 목록|날짜별 회고 목록을 출력||날짜별 회고 목록을 출력|PrintAllReflection|
+|프로그램 종료|프로그램 종료||||
+
+## 프로그램 흐름도
+```
+메뉴출력
+┗ 사용자 입력
+ ┣ 회고 추가
+ ┃ ┗ 날짜 입력 → 회고 내용 입력 → DB에 저장 → 성공 메시지 출력
+ ┣ 회고 조회
+ ┃ ┗ 날짜 입력 → DB에서 검색 → 결과 출력
+ ┃ ┣ 회고 있음: 회고 내용 출력
+ ┃ ┗ 회고 없음: "해당 날짜의 회고가 없습니다." 메시지 출력
+ ┣ 회고 수정
+ ┃ ┗ 날짜 입력 → DB에서 검색
+ ┃ ┣ 회고 있음: 새로운 내용 입력 → 수정 → 성공 메시지 출력
+ ┃ ┗ 회고 없음: "해당 날짜의 회고가 없습니다." 메시지 출력
+ ┣ 회고 삭제
+ ┃ ┗ 날짜 입력 → DB에서 삭제
+ ┃ ┣ 회고 있음: 삭제 → 성공 메시지 출력
+ ┃ ┗ 회고 없음: "해당 날짜의 회고가 없습니다." 메시지 출력
+ ┣ 전체 회고 목록 출력
+ ┃ ┗ DB에 저장된 모든 회고 검색 → 결과 출력
+ ┃ ┣ 회고 있음: 날짜별 회고 출력
+ ┃ ┗ 회고 없음: "저장된 회고가 없습니다." 메시지 출력
+ ┗ 종료
+ ┗ 프로그램 종료 메시지 출력
+```
+
+
+
+
+## 파일 구조
+
+
+```
+📦 WeekAssign02
+ ┣ 📂 BasicFunction
+ ┃ ┣ 📜 AddReflection.swift
+ ┃ ┣ 📜 DeleteReflection.swift
+ ┃ ┣ 📜 EditReflection.swift
+ ┃ ┣ 📜 ExitProgram.swift
+ ┃ ┣ 📜 PrintAllReflection.swift
+ ┃ ┣ 📜 PrintMenu.swift
+ ┃ ┗ 📜 SearchReflection.swift
+ ┣ 📂 Data
+ ┃ ┗ 📜 Reflection.swift
+ ┣ 📂 System
+ ┃ ┣ 📜 ReflectionSystem.swift
+ ┃ ┗ 📜 ReflectionSystemDB.swift
+ ┣ 📂 UserInput
+ ┃ ┣ 📜 UserContentInput.swift
+ ┃ ┣ 📜 UserDateInput.swift
+ ┃ ┗ 📜 UserMenuInput.swift
+ ┣ 📂 UtilFunction
+ ┃ ┣ 📜 ExecuteMenu.swift
+ ┃ ┗ 📜 ValidateDate.swift
+ ┣ 📜 main.swift
+ ┗ 📜 Templete.swift
+```
+## 추가되면 좋은 기능
+1. 파일 저장 시스템
+2. 로그인 시스템 - 자신의 회고만 관리
+3. 회고 공유 시스템
+4.
+5.
+6.
+7. ...
+8. UI로 개발
diff --git a/geunwoong/WeekAssign02/WeekAssign02.xcodeproj/project.pbxproj b/geunwoong/WeekAssign02/WeekAssign02.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..a272ffa
--- /dev/null
+++ b/geunwoong/WeekAssign02/WeekAssign02.xcodeproj/project.pbxproj
@@ -0,0 +1,294 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 77;
+ objects = {
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 5E16570D2D58B95000F4325A /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 5E16570F2D58B95000F4325A /* WeekAssign02 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = WeekAssign02; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFileSystemSynchronizedRootGroup section */
+ 5E1657112D58B95000F4325A /* WeekAssign02 */ = {
+ isa = PBXFileSystemSynchronizedRootGroup;
+ path = WeekAssign02;
+ sourceTree = "";
+ };
+/* End PBXFileSystemSynchronizedRootGroup section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 5E16570C2D58B95000F4325A /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 5E1657062D58B95000F4325A = {
+ isa = PBXGroup;
+ children = (
+ 5E1657112D58B95000F4325A /* WeekAssign02 */,
+ 5E1657102D58B95000F4325A /* Products */,
+ );
+ sourceTree = "";
+ };
+ 5E1657102D58B95000F4325A /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 5E16570F2D58B95000F4325A /* WeekAssign02 */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 5E16570E2D58B95000F4325A /* WeekAssign02 */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 5E1657162D58B95000F4325A /* Build configuration list for PBXNativeTarget "WeekAssign02" */;
+ buildPhases = (
+ 5E16570B2D58B95000F4325A /* Sources */,
+ 5E16570C2D58B95000F4325A /* Frameworks */,
+ 5E16570D2D58B95000F4325A /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ fileSystemSynchronizedGroups = (
+ 5E1657112D58B95000F4325A /* WeekAssign02 */,
+ );
+ name = WeekAssign02;
+ packageProductDependencies = (
+ );
+ productName = WeekAssign02;
+ productReference = 5E16570F2D58B95000F4325A /* WeekAssign02 */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 5E1657072D58B95000F4325A /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ BuildIndependentTargetsInParallel = 1;
+ LastSwiftUpdateCheck = 1620;
+ LastUpgradeCheck = 1620;
+ TargetAttributes = {
+ 5E16570E2D58B95000F4325A = {
+ CreatedOnToolsVersion = 16.2;
+ };
+ };
+ };
+ buildConfigurationList = 5E16570A2D58B95000F4325A /* Build configuration list for PBXProject "WeekAssign02" */;
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 5E1657062D58B95000F4325A;
+ minimizedProjectReferenceProxies = 1;
+ preferredProjectObjectVersion = 77;
+ productRefGroup = 5E1657102D58B95000F4325A /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 5E16570E2D58B95000F4325A /* WeekAssign02 */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 5E16570B2D58B95000F4325A /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 5E1657142D58B95000F4325A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MACOSX_DEPLOYMENT_TARGET = 15.2;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = macosx;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ 5E1657152D58B95000F4325A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MACOSX_DEPLOYMENT_TARGET = 15.2;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ MTL_FAST_MATH = YES;
+ SDKROOT = macosx;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ };
+ name = Release;
+ };
+ 5E1657172D58B95000F4325A /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Automatic;
+ DEVELOPMENT_TEAM = C5K6DF875Z;
+ ENABLE_HARDENED_RUNTIME = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ };
+ name = Debug;
+ };
+ 5E1657182D58B95000F4325A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CODE_SIGN_STYLE = Automatic;
+ DEVELOPMENT_TEAM = C5K6DF875Z;
+ ENABLE_HARDENED_RUNTIME = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_VERSION = 5.0;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 5E16570A2D58B95000F4325A /* Build configuration list for PBXProject "WeekAssign02" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 5E1657142D58B95000F4325A /* Debug */,
+ 5E1657152D58B95000F4325A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 5E1657162D58B95000F4325A /* Build configuration list for PBXNativeTarget "WeekAssign02" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 5E1657172D58B95000F4325A /* Debug */,
+ 5E1657182D58B95000F4325A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 5E1657072D58B95000F4325A /* Project object */;
+}
diff --git a/geunwoong/WeekAssign02/WeekAssign02.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/geunwoong/WeekAssign02/WeekAssign02.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/geunwoong/WeekAssign02/WeekAssign02.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/AddReflection.swift b/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/AddReflection.swift
new file mode 100644
index 0000000..aa62fce
--- /dev/null
+++ b/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/AddReflection.swift
@@ -0,0 +1,33 @@
+/*
+ File: AddReflection.swift
+ Purpose: 특정 날짜에 회고 내용을 추가
+
+ Data (사용하는 자료)
+ - date: String
+ - reflection: Reflection
+ - searchResult: Reflection? // 회고가 존재하지 않으면 nil
+
+ etc
+ - searchResult의 경우 추가한 회고에 대한 정보를 이용할만한게 있을까하여 남겨놓음
+*/
+extension ReflectionSystem {
+ func addReflection() {
+ // 날짜를 입력
+ guard let date = userDateInput(how: "추가") else { return }
+ // 입력 받은 날짜에 회고가 없는지 확인
+ guard let searchResult = db.dbSearch(date: date) else {
+ // 입력 받은 날짜에 회고가 없음
+ guard let content = userContentInput() else { return }
+ let reflection = Reflection(date: date, content: content)
+ if db.dbInsert(date: date, content: reflection) {
+ print("회고가 추가되었습니다.\n")
+ }else {
+ print("회고를 추가하지 못했습니다. 잠시후 다시 시도해주세요.\n")
+ }
+ return
+ }
+ // searchResult에 접근하면 이미 존재하는 정보를 받아올 수 있음
+ print("회고가 이미 존재합니다.\n")
+ }
+
+}
diff --git a/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/DeleteReflection.swift b/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/DeleteReflection.swift
new file mode 100644
index 0000000..347b102
--- /dev/null
+++ b/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/DeleteReflection.swift
@@ -0,0 +1,22 @@
+/*
+ File: DeleteReflection.swift
+ Purpose: 특정 날짜의 회고 내용을 삭제
+
+ Data
+ - date: String
+ - deleteResult: Reflection? // 회고가 존재하지 않으면 nil
+
+ etc
+ - deleteResult의 경우 삭제한 회고에 대한 정보를 이용할만한게 있을까하여 남겨놓음
+*/
+extension ReflectionSystem {
+ func deleteReflection() {
+ guard let date = userDateInput(how: "삭제") else { return }
+ guard let deleteResult = db.dbDelete(date: date) else {
+ print("회고가 존재하지 않습니다.\n")
+ return
+ }
+ print("회고가 삭제되었습니다.\n")
+ // deleteResult에 접근하면 삭제한 정보를 받아올 수 있음
+ }
+}
diff --git a/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/EditReflection.swift b/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/EditReflection.swift
new file mode 100644
index 0000000..1cebd26
--- /dev/null
+++ b/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/EditReflection.swift
@@ -0,0 +1,30 @@
+/*
+ File: EditReflection.swift
+ Purpose: 특정 날짜의 회고 내용을 수정
+
+ Data
+ - date: String
+ - searchResult: Reflection? // 회고가 존재하지 않으면 nil
+
+ etc
+ -
+ */
+extension ReflectionSystem {
+ func editReflection() {
+ guard let date = userDateInput(how: "수정") else { return }
+ guard let searchResult = db.dbSearch(date: date) else {
+ print("회고가 존재하지 않습니다.\n")
+ return
+ }
+ print("====수정전 회고 내용=====")
+ print("내용: \(searchResult.content)")
+ print("=====================")
+ guard let content = userContentInput() else { return }
+ let reflection = Reflection(date: date, content: content)
+ if db.dbInsert(date: date, content: reflection) {
+ print("회고가 수정되었습니다.\n")
+ }else {
+ print("회고를 추가하지 못했습니다. 잠시후 다시 시도해주세요.\n")
+ }
+ }
+}
diff --git a/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/ExitProgram.swift b/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/ExitProgram.swift
new file mode 100644
index 0000000..32e5dc6
--- /dev/null
+++ b/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/ExitProgram.swift
@@ -0,0 +1,22 @@
+/*
+ File: ExitProgram.swift
+ Purpose: 프로그램을 종료하기 위한 파일
+
+ Data
+ - power: Bool // 처음 System이 가능되면 true가 되고 exit를 작동하면 false가 되어 반복문 종료
+
+ etc
+ -
+*/
+extension ReflectionSystem {
+ func exitProgram() {
+ power.toggle()
+ print("================")
+ print("================")
+ print("****************")
+ print("프로그램을 종료합니다")
+ print("****************")
+ print("================")
+ print("================")
+ }
+}
diff --git a/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/PrintAllReflection.swift b/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/PrintAllReflection.swift
new file mode 100644
index 0000000..1a90f8d
--- /dev/null
+++ b/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/PrintAllReflection.swift
@@ -0,0 +1,40 @@
+/*
+ File: PrintAllReflection.swift
+ Purpose: 날짜별 회고 목록을 출력
+
+ Input Data
+ - 파일에서 처리하는 기능에 대한 입력, 전달 값
+ Output Data
+ - 파일에서 처리한 내용에 대한 출력, 반환 값
+
+ Warning
+ -
+*/
+/*
+ File: PrintAllReflection.swift
+ Purpose: 저장된 모든 회고를 출력
+
+ Data
+ - reflections: Reflection // db에 저장된 회고목록을 전부 불러옴, 없으면 nil이 아닌 []이 반환
+
+ etc
+ - 보여주기 식으로 print가 많을뿐..
+ - 나중에 UI로 다시 짜봐도 괜찮을듯?
+*/
+extension ReflectionSystem {
+ func printAllReflection() {
+ let reflections: [Reflection] = db.dbSearchAll()
+ print("=== 저장된 회고 목록 ===")
+ if reflections.isEmpty { print("저장된 회고가 없습니다.") }
+ else {
+ for (idx, reflection) in reflections.enumerated() {
+ print("날짜: \(reflection.date)")
+ print("내용: \(reflection.content)")
+ if idx != reflections.count - 1 {
+ print("--------------------")
+ }
+ }
+ }
+ print("====================\n")
+ }
+}
diff --git a/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/PrintMenu.swift b/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/PrintMenu.swift
new file mode 100644
index 0000000..d7745ee
--- /dev/null
+++ b/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/PrintMenu.swift
@@ -0,0 +1,21 @@
+/*
+ File: PrintMenu.swift
+ Purpose: 회고 시스템의 메뉴 출력
+
+ Data
+ -
+
+ etc
+ -
+*/
+extension ReflectionSystem {
+ func printMenuBoard() {
+ print("==== 회고 시스템 ====")
+ print("1. 회고 추가")
+ print("2. 회고 조회")
+ print("3. 회고 수정")
+ print("4. 회고 삭제")
+ print("5. 전체 회고 목록 출력")
+ print("6. 종료\n")
+ }
+}
diff --git a/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/SearchReflection.swift b/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/SearchReflection.swift
new file mode 100644
index 0000000..7045f4e
--- /dev/null
+++ b/geunwoong/WeekAssign02/WeekAssign02/BasicFunction/SearchReflection.swift
@@ -0,0 +1,22 @@
+/*
+ File: SearchReflection.swift
+ Purpose: 특정 날짜의 회고 내용을 검색
+
+ Data
+ - date: String
+ - searchResult: Reflection? // 회고가 존재하지 않으면 nil
+
+ etc
+ - 추가적인 설명, 나중에 바꾸면 좋겠는것 등을 작성
+*/
+extension ReflectionSystem {
+ func searchReflection() {
+ guard let date = userDateInput(how: "조회") else { return }
+ guard let searchResult = db.dbSearch(date: date) else {
+ print("회고가 존재하지 않습니다.\n")
+ return
+ }
+ print("날짜: \(searchResult.date)")
+ print("내용: \(searchResult.content)\n")
+ }
+}
diff --git a/geunwoong/WeekAssign02/WeekAssign02/Data/Reflection.swift b/geunwoong/WeekAssign02/WeekAssign02/Data/Reflection.swift
new file mode 100644
index 0000000..beb0bc6
--- /dev/null
+++ b/geunwoong/WeekAssign02/WeekAssign02/Data/Reflection.swift
@@ -0,0 +1,15 @@
+/*
+ File: Reflection.swift
+ Purpose: Reflection 데이터 타입 작성
+
+ Data
+ - date: String // 작성된 날짜
+ - content: String // 작성된 내용
+
+ etc
+ -
+*/
+struct Reflection {
+ var date: String
+ var content: String
+}
diff --git a/geunwoong/WeekAssign02/WeekAssign02/System/ReflectionSystem.swift b/geunwoong/WeekAssign02/WeekAssign02/System/ReflectionSystem.swift
new file mode 100644
index 0000000..f126b0f
--- /dev/null
+++ b/geunwoong/WeekAssign02/WeekAssign02/System/ReflectionSystem.swift
@@ -0,0 +1,27 @@
+/*
+ File: ReflectionSystem.swift
+ Purpose: 회고 시스템의 바디 프로그램
+
+ Data
+ - shared // 회고 시스템의 호출용 싱글톤
+ - db: ReflectionSystemDB // 회고 시스템 DB의 외부 호출용 싱글톤
+ - power: Bool // 회고 시스템을 작동(run)하면 true되며, 종료(exit)하면 false로 바뀜
+
+ etc
+ - 여기선 회고 시스템의 작동만 담당하고 실제 작동은 executeMenu에서 실행
+ - class이니까 protocol 사용도 좋을듯
+*/
+class ReflectionSystem {
+ static let shared = ReflectionSystem() // 외부 호출용 싱글톤
+ let db = ReflectionSystemDB.shared
+ var power: Bool = false
+ private init() { }
+ //프로그램 작동
+ func run() {
+ self.power.toggle()
+ printMenuBoard() // 메뉴판 출력
+ while power {
+ executeMenu(menu: userMenuInput())
+ }
+ }
+}
diff --git a/geunwoong/WeekAssign02/WeekAssign02/System/ReflectionSystemDB.swift b/geunwoong/WeekAssign02/WeekAssign02/System/ReflectionSystemDB.swift
new file mode 100644
index 0000000..435a786
--- /dev/null
+++ b/geunwoong/WeekAssign02/WeekAssign02/System/ReflectionSystemDB.swift
@@ -0,0 +1,31 @@
+/*
+ File: ReflectionSystemDB.swift
+ Purpose: 회고 시스템의 DB
+
+ Data
+ - shared // DB의 호출용 싱글톤
+ - DB: [String:Reflection] // Key: date(String), Value: Reflection인 회고를 저장하는 DB 역할
+
+ etc
+ - 간단한 내용으로 작성되어 있어 한 파일로 사용
+ - class이니까 protocol 사용도 좋을듯
+*/
+class ReflectionSystemDB {
+ static let shared = ReflectionSystemDB()
+ private var DB: [String:Reflection] = [:]
+ private init() { }
+
+ func dbInsert(date: String, content: Reflection) -> Bool { // db에 회고를 저장 후 결과 반환
+ DB[date] = content
+ return DB[date] != nil ? true : false
+ }
+ func dbSearch(date: String) -> Reflection? { // db에 회고를 찾아서 반환
+ return DB[date]
+ }
+ func dbSearchAll() -> [Reflection] { // db의 내용을 반환
+ return DB.values.sorted{ $0.date < $1.date ? true : false }
+ }
+ func dbDelete(date: String) -> Reflection? { // db에서 회고를 삭제 후 반환
+ return DB.removeValue(forKey: date)
+ }
+}
diff --git a/geunwoong/WeekAssign02/WeekAssign02/Templete.swift b/geunwoong/WeekAssign02/WeekAssign02/Templete.swift
new file mode 100644
index 0000000..4987b7f
--- /dev/null
+++ b/geunwoong/WeekAssign02/WeekAssign02/Templete.swift
@@ -0,0 +1,10 @@
+/*
+ File: Templete.swift
+ Purpose: 파일 헤드에 작성할 주석의 템플릿
+
+ Data
+ - 파일에서 사용하는 data에 대한 설명
+
+ etc
+ - 추가적인 설명, 나중에 바꾸면 좋겠는것 등을 작성
+*/
diff --git a/geunwoong/WeekAssign02/WeekAssign02/UserInput/UserContentInput.swift b/geunwoong/WeekAssign02/WeekAssign02/UserInput/UserContentInput.swift
new file mode 100644
index 0000000..6e0c340
--- /dev/null
+++ b/geunwoong/WeekAssign02/WeekAssign02/UserInput/UserContentInput.swift
@@ -0,0 +1,25 @@
+/*
+ File: UserContentInput.swift
+ Purpose: 회고의 내용을 입력했을때 이상한 입력인지 판단하고 빈 값인지 확인
+
+ Data
+ - content: String // content가 nil이거나 ""이면 nil을 반환, 아니면 정상적인 content를 반환
+
+ etc
+ - 지금 대부분 guard 구문으로 nil을 반환하고 끝나는데 이 부분들을 에러로 해서 throw Error처리 해보고 싶다
+*/
+extension ReflectionSystem {
+ func userContentInput() -> String? {
+ print("회고 내용을 입력하세요: ", terminator: "")
+ guard let content = readLine() else {
+ print("잘못된 입력입니다.")
+ return nil
+ }
+ if content == "" {
+ print("작성된 내용이 없습니다.\n")
+ return nil
+ }
+
+ return content
+ }
+}
diff --git a/geunwoong/WeekAssign02/WeekAssign02/UserInput/UserDateInput.swift b/geunwoong/WeekAssign02/WeekAssign02/UserInput/UserDateInput.swift
new file mode 100644
index 0000000..9e67bc2
--- /dev/null
+++ b/geunwoong/WeekAssign02/WeekAssign02/UserInput/UserDateInput.swift
@@ -0,0 +1,21 @@
+/*
+ File: UserDateInput.swift
+ Purpose: 유저가 날짜를 입력
+
+ Data
+ - date: String // 이상한 입력이 들어와 nil이 되는것만 확인 나머지 유효성은 validateDate로 위임
+
+ etc
+ -
+*/
+extension ReflectionSystem {
+ func userDateInput(how: String) -> String? {
+ print("\(how)할 날짜를 입력하세요 (예: 2024-12-25): ", terminator: "")
+ guard let date = readLine() else {
+ print("잘못된 입력입니다.")
+ return nil
+ }
+ // 유효성 검사 후 괜찮으면 date를 반환 아니면 nil
+ return validateDate(date: date) ? date : nil
+ }
+}
diff --git a/geunwoong/WeekAssign02/WeekAssign02/UserInput/UserMenuInput.swift b/geunwoong/WeekAssign02/WeekAssign02/UserInput/UserMenuInput.swift
new file mode 100644
index 0000000..8896fc3
--- /dev/null
+++ b/geunwoong/WeekAssign02/WeekAssign02/UserInput/UserMenuInput.swift
@@ -0,0 +1,21 @@
+/*
+ File: UserMenuInput.swift
+ Purpose: 유저의 메뉴 입력을 받는 함수
+
+ Data
+ - input: String // 입력받은 메뉴의 String값
+ - menu: Int // String값을 Int로 캐스팅, 이때 1~6이 아니면 잘못된메뉴 선택으로 -1반환, 아니면 1~6 반환
+
+ etc
+ -
+*/
+extension ReflectionSystem {
+ func userMenuInput() -> Int {
+ print("메뉴를 선택하세요: ", terminator: "")
+ guard let input = readLine(), let menu = Int(input), menu >= 1 && menu <= 6 else {
+ print("잘못된 메뉴 선택입니다.\n")
+ return -1
+ }
+ return menu
+ }
+}
diff --git a/geunwoong/WeekAssign02/WeekAssign02/UtilFunction/ExecuteMenu.swift b/geunwoong/WeekAssign02/WeekAssign02/UtilFunction/ExecuteMenu.swift
new file mode 100644
index 0000000..58877af
--- /dev/null
+++ b/geunwoong/WeekAssign02/WeekAssign02/UtilFunction/ExecuteMenu.swift
@@ -0,0 +1,20 @@
+/*
+ File: ExecuteMenu.swift
+ Purpose: 입력받은 메뉴에 따른 메뉴 실행
+
+ Data
+ - menu: Int // 입력받은 메뉴 값의 Int형, 1~6은 정상적인 입력으로 메뉴 실행, -1은 오류상태
+
+ etc
+ - 지금은 -1이 들어오면 아무것도 안하는데 나중엔 먼가 처리를 해주면 좋을듯
+*/
+extension ReflectionSystem {
+ func executeMenu(menu: Int) {
+ if menu == 1 { addReflection() }
+ if menu == 2 { searchReflection() }
+ if menu == 3 { editReflection() }
+ if menu == 4 { deleteReflection() }
+ if menu == 5 { printAllReflection() }
+ if menu == 6 { exitProgram() }
+ }
+}
diff --git a/geunwoong/WeekAssign02/WeekAssign02/UtilFunction/ValidateDate.swift b/geunwoong/WeekAssign02/WeekAssign02/UtilFunction/ValidateDate.swift
new file mode 100644
index 0000000..fe955fc
--- /dev/null
+++ b/geunwoong/WeekAssign02/WeekAssign02/UtilFunction/ValidateDate.swift
@@ -0,0 +1,57 @@
+/*
+ File: ValidateDate.swift
+ Purpose: 입력받은 날짜의 유효성 판단
+
+ Data
+ - date: String // 1차 검사로 nil이 아닌 값이 들어옴
+ - regex: 정규식 // yyyy-mm-dd 그중에서도 mm은 01~09,10~12까지, dd는 01~09,10~29,30,31만 가능하다
+ - dateArr: [String] // [0]: yyyy, [1]: mm, [2]: dd 형태
+
+ etc
+ - 정규식을 활용한 date.wholeMatch(of: regex)는 판단만 하면 되서 '_' 처리
+ - 2월과 30일까지인 달 처리가 먼가 예쁘지 않다. 나중에 하나로 합쳐보자
+*/
+extension ReflectionSystem {
+ // 유효성 검사
+ func validateDate(date: String) -> Bool {
+ // 입력 형식에 따른 검사
+ let regex = /\d{4}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])/ // 정규식(yyyy-mm-dd)
+ guard let _ = date.wholeMatch(of: regex) else {
+ print("날짜의 입력형식이 잘못되었습니다.\n")
+ return false
+ }
+
+ // 입력된 날짜에 따른 검사
+ let dateArr: [String] = date.components(separatedBy: "-")
+ if dateArr[2] == "31", ["04", "06", "09", "11"].contains(dateArr[1]) {
+ print("날짜가 유효하지 않습니다.\n")
+ return false
+ }else if dateArr[1] == "02", ["29","30","31"].contains(dateArr[2]) {
+ print("날짜가 유효하지 않습니다.\n")
+ return false
+ }
+
+ // 둘다 통과하면 입력은 정상적
+ return true
+ }
+ func legacyValidateDate(date: String) -> Bool { // 날짜가 올바른 형식이고 날짜가 유효한지 판단
+ let regex = /\d{4}\-(0[1-9]|1[012])\-(0[1-9]|[12][0-9]|3[01])/ // yyyy-mm-dd 형식의 정규식
+ guard let dateMatch = date.wholeMatch(of: regex)?.output else { // 날짜의 형식이 맞지않음
+ print("날짜의 입력이 잘못되었습니다.\n")
+ return false
+ }
+ let month: String = String(dateMatch.1) // 월
+ let day: String = String(dateMatch.2) // 일
+
+ // 날짜가 유효하지 않음
+ if (month == "04" || month == "06" || month == "09" || month == "11") && day == "31" { // 30일까지 있음
+ print("날짜가 유효하지 않습니다.\n")
+ return false
+ }else if month == "02" && (day == "29" || day == "30" || day == "31") {
+ print("날짜가 유효하지 않습니다.\n")
+ return false
+ }
+ // 날짜가 유효함
+ return true
+ }
+}
diff --git a/geunwoong/WeekAssign02/WeekAssign02/main.swift b/geunwoong/WeekAssign02/WeekAssign02/main.swift
new file mode 100644
index 0000000..a8dfff2
--- /dev/null
+++ b/geunwoong/WeekAssign02/WeekAssign02/main.swift
@@ -0,0 +1,15 @@
+/*
+ File: main.swift
+ Purpose: 회고 시스템의 작동
+
+ Data
+ -
+
+ etc
+ -
+*/
+
+import Foundation
+
+// 프로그램 작동
+ReflectionSystem.shared.run()