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()