diff --git a/README.md b/README.md index af78fa5..27fe470 100644 --- a/README.md +++ b/README.md @@ -1 +1,90 @@ -## 내일배움캠프 2주차 과제입니다. +# Swift 과제 정리 + +Swift 기본 문법을 연습하면서 작성한 과제 풀이 코드입니다. +클로저, 고차함수, 제네릭, 프로토콜, 에러 처리까지 직접 구현해봤습니다. + +--- + +## 📁 프로젝트 구성 + +- `main.swift` + Playground / Command Line Tool 환경에서 실행 가능한 단일 파일 + +--- + +## ✅ 과제 1: 클로저 (Closure) + +- `(Int, Int) -> String` 타입의 클로저 정의 +- 클로저를 파라미터로 받아 호출하는 함수 구현 + +--- + +## ✅ 과제 2: 고차함수 (map / filter) + +- `map`으로 타입 변환 +- `filter` + `map` 체이닝 +- 클로저를 받아 동작하는 커스텀 `map` 구현 + +--- + +## ✅ 과제 3: 제네릭 (Generic) + +- Int / String 배열에서 동일한 로직을 타입별로 구현 +- 제네릭으로 공통 로직 통합 +- `Numeric` 제약을 걸어 특정 타입만 받도록 처리 + +--- + +## ✅ 과제 4: 프로토콜 & 타입 캐스팅 + +### Introducible 프로토콜 + +- `name` 프로퍼티 +- `introduce()` 메서드 요구 + +### 구현 타입 + +- `Robot / Cat / Dog` + +### 확인한 내용 + +- 프로토콜 타입 배열에 담으면 프로토콜에 정의된 멤버만 접근 가능 +- 구체 타입의 기능은 다운캐스팅 후 사용 가능 + +--- + +## ✅ 과제 5: 에러 처리 (throws) + +- enum + associated value로 에러 케이스 정의 +- throwing 함수 구현 +- do–try–catch로 상황별 분기 처리 + +--- + +## 🚀 도전 과제 2: 제네릭 제약 + 조건부 메서드 + +- `SortableBox` 제네릭 구조체 구현 (`items: [T]`) +- `T: Comparable`일 때만 `sortItems()`가 보이도록 확장 +- Comparable이 아닌 타입은 `sortItems()` 호출 시 컴파일 오류로 막히는 것 확인 + +--- + +## 🚀 도전 과제 3: 프로토콜 기본 구현 + +- `Introducible` extension에서 기본 `introduce()` 제공 +- `Cat`, `Dog`는 `introduce()` 구현 없이 기본 동작 사용 +- `Robot`은 기본 동작 대신 커스텀 `introduce()` 구현 + +--- + +## ▶️ 실행 방법 + +- Xcode Playground 또는 Command Line Tool 프로젝트에서 + `main.swift` 실행 + +--- + +## 🙋‍♀️ 작성자 + +- 김주희 +- 내일배움캠프 iOS 9기 `🤓왜_되는지_증명못함` 팀 diff --git a/juhee.xcodeproj/project.pbxproj b/juhee.xcodeproj/project.pbxproj new file mode 100644 index 0000000..2d92c75 --- /dev/null +++ b/juhee.xcodeproj/project.pbxproj @@ -0,0 +1,301 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXCopyFilesBuildPhase section */ + B96062ED2F0CF71F0082C173 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + B96062EF2F0CF71F0082C173 /* juhee */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = juhee; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + B96062F12F0CF71F0082C173 /* juhee */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = juhee; + sourceTree = ""; + }; +/* End PBXFileSystemSynchronizedRootGroup section */ + +/* Begin PBXFrameworksBuildPhase section */ + B96062EC2F0CF71F0082C173 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + B96062E62F0CF71F0082C173 = { + isa = PBXGroup; + children = ( + B96062F12F0CF71F0082C173 /* juhee */, + B96062F02F0CF71F0082C173 /* Products */, + ); + sourceTree = ""; + usesTabs = 0; + }; + B96062F02F0CF71F0082C173 /* Products */ = { + isa = PBXGroup; + children = ( + B96062EF2F0CF71F0082C173 /* juhee */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + B96062EE2F0CF71F0082C173 /* juhee */ = { + isa = PBXNativeTarget; + buildConfigurationList = B96062F62F0CF71F0082C173 /* Build configuration list for PBXNativeTarget "juhee" */; + buildPhases = ( + B96062EB2F0CF71F0082C173 /* Sources */, + B96062EC2F0CF71F0082C173 /* Frameworks */, + B96062ED2F0CF71F0082C173 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + B96062F12F0CF71F0082C173 /* juhee */, + ); + name = juhee; + packageProductDependencies = ( + ); + productName = juhee; + productReference = B96062EF2F0CF71F0082C173 /* juhee */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + B96062E72F0CF71F0082C173 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 2620; + LastUpgradeCheck = 2620; + TargetAttributes = { + B96062EE2F0CF71F0082C173 = { + CreatedOnToolsVersion = 26.2; + }; + }; + }; + buildConfigurationList = B96062EA2F0CF71F0082C173 /* Build configuration list for PBXProject "juhee" */; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = B96062E62F0CF71F0082C173; + minimizedProjectReferenceProxies = 1; + preferredProjectObjectVersion = 77; + productRefGroup = B96062F02F0CF71F0082C173 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + B96062EE2F0CF71F0082C173 /* juhee */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + B96062EB2F0CF71F0082C173 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + B96062F42F0CF71F0082C173 /* 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; + DEVELOPMENT_TEAM = YSBKYH9JX6; + 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 = 26.1; + 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; + }; + B96062F52F0CF71F0082C173 /* 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"; + DEVELOPMENT_TEAM = YSBKYH9JX6; + 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 = 26.1; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + }; + name = Release; + }; + B96062F72F0CF71F0082C173 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = YSBKYH9JX6; + ENABLE_HARDENED_RUNTIME = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_APPROACHABLE_CONCURRENCY = YES; + SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + B96062F82F0CF71F0082C173 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = YSBKYH9JX6; + ENABLE_HARDENED_RUNTIME = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_APPROACHABLE_CONCURRENCY = YES; + SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + B96062EA2F0CF71F0082C173 /* Build configuration list for PBXProject "juhee" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B96062F42F0CF71F0082C173 /* Debug */, + B96062F52F0CF71F0082C173 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B96062F62F0CF71F0082C173 /* Build configuration list for PBXNativeTarget "juhee" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B96062F72F0CF71F0082C173 /* Debug */, + B96062F82F0CF71F0082C173 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = B96062E72F0CF71F0082C173 /* Project object */; +} diff --git a/juhee.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/juhee.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/juhee.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/juhee.xcodeproj/project.xcworkspace/xcuserdata/gimjuhui.xcuserdatad/UserInterfaceState.xcuserstate b/juhee.xcodeproj/project.xcworkspace/xcuserdata/gimjuhui.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..0687b24 Binary files /dev/null and b/juhee.xcodeproj/project.xcworkspace/xcuserdata/gimjuhui.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/juhee.xcodeproj/xcuserdata/gimjuhui.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/juhee.xcodeproj/xcuserdata/gimjuhui.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..aa1e1c5 --- /dev/null +++ b/juhee.xcodeproj/xcuserdata/gimjuhui.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,24 @@ + + + + + + + + + diff --git a/juhee.xcodeproj/xcuserdata/gimjuhui.xcuserdatad/xcschemes/xcschememanagement.plist b/juhee.xcodeproj/xcuserdata/gimjuhui.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..c39169f --- /dev/null +++ b/juhee.xcodeproj/xcuserdata/gimjuhui.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + juhee.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/juhee/main.swift b/juhee/main.swift new file mode 100644 index 0000000..e58ba86 --- /dev/null +++ b/juhee/main.swift @@ -0,0 +1,352 @@ +// +// main.swift +// juhee +// +// Created by 김주희 on 1/6/26. +// + +import Foundation + +// MARK: - 과제 1 풀이 + +// 1-1 +// sum의 타입도 명시하고 클로저 내부 구현도 함 +// 타입 추론 기능을 이용해 간결하게 리펙토링 +let sum: (Int, Int) -> String = { "두 수의 합은 \($0 + $1) 입니다." } // return 생략 + +print(sum(10, 20)) // 두 수의 합은 30 입니다. 출력 + +// 1-2 +func calculate(a: Int, b: Int, closure: (Int, Int) -> String) { + print(closure(a, b)) +} +// 함수의 출력값이 없을때 -> Void 생략 가능 + + + + +// MARK: - 과제 2 풀이 + +// 2-1 +let numbers = [1, 2, 3, 4, 5] + +var result = [String]() + +result = numbers.map { String($0) } + +print(result) // ["1", "2", "3", "4", "5"] 출력 + + + +// 2-2 +let numbers2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + +// 체이닝 방식으로 수정 +let result2 = numbers2 + .filter { $0 % 2 == 0} + .map { String($0) } // 줄바꿈 (수정), result2 배열 let으로 선언 (수정) + +print(result2) // ["2", "4", "6", "8", "10"] 출력 + + + +// 2-3 +func myMap (a: [Int], operation: (Int) -> String) -> [String] { + var result = [String]() + for i in a { + result.append(operation(i)) // 파라미터로 받은 클로저 이용해서 변환 + } + return result +} + +let result4 = myMap(a: [1, 2, 3, 4, 5]) { + String($0) +} + +print(result4) // ["1", "2", "3", "4", "5"] 출력 + + + + +// MARK: - 과제3 풀이 + +// 3-1 +// 3-1은 .enumarated()를 이용한 풀이로 수정 +func a(_ array: [Int]) -> [Int] { + array.enumerated() // [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)] + .filter { (idx, _) in // 튜플에서 인덱스만 보고 2의 배수인것만 남긴다 + idx.isMultiple(of: 2) // [(0, 1), (2, 3), (4, 5)]만 필터링 되어서 남음 + } + .map { (_, value) in // 튜플에서 value값만 뽑아서 배열로 만듬 + value + } + // [1, 3, 5] +} + +print(a([1, 2, 3, 4, 5])) // [1, 3, 5] 출력 + + + +// 3-2 +// 3-1번 풀이와 매개변수의 타입만 다를뿐 풀이 방식은 같음 +func b (array: [String]) -> [String] { + array.enumerated() // [(0, "가"), (1, "나"), (2, "다"), (3, "라"), (4, "마")] + .filter { (idx, _) in // 튜플에서 인덱스만 보고 2의 배수인것만 남긴다 + idx.isMultiple(of: 2) // [(0, "가"), (2, "다"), (4, "마")]만 필터링 되어서 남음 + } + .map { (_, value) in // 튜플에서 value값만 뽑아서 배열로 만듬 + value + } +} + +print(b(array: ["가", "나", "다", "라", "마"])) // ["가", "다", "마"] 출력 + + + +// 3-3 +// 제네릭 +func c(array: [T]) ->[T] { + + var returnArray = [T]() + + for i in 0..> 로 변경 +func d(array: [T]) ->[T] { + + var returnArray = [T]() + + for i in 0.. String +} + + +class Robot: Introducible { + var name: String { + // 프로퍼티 옵져버 + didSet { // 값이 변경되었음을 알릴때는 willSet보다 didSet이 적합함 + if oldValue != name { + print("name 변경 알림") + print("변경 이전 값: \(oldValue)") + print("변경 이후 값: \(name)") + } + } + } + + func introduce() -> String { + return "안녕하세요, 저는 \(name) 입니다." + } + + func batteryCharge() -> String { + return "전원을 충전합니다." + } + + init(name: String) { + self.name = name + } +} + + +class Cat: Introducible { + var name: String + + func introduce() -> String { + return "안녕하세요, 저는 \(name) 입니다." + } + + func grooming() -> String { + return "야옹" + } + + init(name: String) { + self.name = name + } +} + + +class Dog: Introducible { + var name: String + + func introduce() -> String { + return "안녕하세요, 저는 \(name) 입니다." + } + + func bark() -> String { + return "멍멍멍" + } + + init(name: String) { + self.name = name + } +} + +var robot = Robot(name: "로봇") +robot.name = "로봇" // willSet 출력문 실행 X +robot.name = "로봇 이름 변경" // name 변경 알림 변경 이전 값: 로봇 변경 이후 값: 로봇 이름 변경 출력 + + +// 4-2 +var cat = Cat(name: "냥이") +var dog = Dog(name: "멈무") + +let arrayIntroducible: [Introducible] = [robot, cat, dog] // 선언과 동시에 초기화 하도록 리펙토링 + +arrayIntroducible.forEach { + // i.batteryCharge() error: Value of type 'any Introducible' has no member 'batteryCharge' + if let robot = $0 as? Robot { // 비효율적인 반복을 줄이고 가독성 향상을 위해 else if문으로 수정 + print(robot.batteryCharge()) + } else if let cat = $0 as? Cat { + print(cat.grooming()) + } else if let dog = $0 as? Dog { + print(dog.bark()) + } +} + + + + +// MARK: - 문제 5 풀이 + +enum DeliveryStatus{ + case notStarted + case inTransit(daysRemaining: Int) + case error +} + +enum DeliveryError: Error { + case invalidAddress + case notStarted + case systemError(reason: String) +} + +// throwing function +func predictDeliveryDay(for address: String, status: DeliveryStatus) throws -> String { + + guard !address.isEmpty else { // if else 중첩문에서 guard로 리펙토링 + throw DeliveryError.invalidAddress + } + switch status { + case .notStarted: + throw DeliveryError.notStarted + case .error: + throw DeliveryError.systemError(reason: "알 수 없음") + case .inTransit(let daysRemaining): + return("배송까지 \(daysRemaining)일 남았습니다.") + } +} + +do { + let message = try predictDeliveryDay(for: "제주특별시", status: .inTransit(daysRemaining: 3)) + print(message) +} catch DeliveryError.invalidAddress { + print("주소가 잘못입력되었습니다. 주소를 확인해주세요.") +} catch DeliveryError.notStarted { + print("배송이 아직 시작되지 않았습니다.") +} catch DeliveryError.systemError(let reason) { + print("시스템 에러가 발생하였습니다: \(reason)") +} + + + +// MARK: - 도전 문제 풀이 + + + +// 1-2 문제 + +// 제네릭 구조체 정의 +struct SortableBox { + var items: [T] +} + +// 타입 T가 Comparable을 준수할 때에만 sortItems() 메서드 확장 +extension SortableBox where T: Comparable { + mutating func sortItems() { // mutating 키워드 필수 + items.sort() + } +} + +// Comparable 따르는 타입 +var intBox = SortableBox(items: [4, 10, 3]) // 변수이름의 의미가 명확히 드러나게 수정 (intBox) +intBox.sortItems() +print(intBox.items) // [3, 4, 10] 정상 출력 + +// T가 Comparable이 아닌 구조체 사용 +struct BoxTypeB { + var i: Int +} + +var nonComparableBox = SortableBox(items: [BoxTypeB(i: 7), BoxTypeB(i: 27)]) // 변수 이름 수정 (가독성) + +// nonComparableBox.sortItems() +// 컴파일 에러: Referencing instance method 'sortItems()' on 'SortableBox' requires that 'BoxTypeB' conform to 'Comparable' + + + +// 1-3 문제 + +//protocol Introducible { +// var name: String { get } +// func introduce() -> String +//} +// +//extension Introducible { +// func introduce() -> String { // 기본 동작 제공 +// "안녕하세요. 제 이름은 \(name) 입니다." +// } +//} +// +//struct Robot: Introducible { +// let name: String +// +// func introduce() -> String { +// "저는 동물이 아닌 로봇 \(name)입니다." +// } +//} +// +//struct Cat: Introducible { +// let name: String +//} +// +//struct Dog: Introducible { +// let name: String +//} +// +//let robot = Robot(name: "쓱싹쓱싹 로봇 청소기") +//let cat = Cat(name: "아기고냥이") +//let dog = Dog(name: "모찌") +// +//print(robot.introduce()) // 저는 동물이 아닌 로봇 쓱싹쓱싹 로봇 청소기입니다. 출력 +//print(cat.introduce()) // 안녕하세요. 제 이름은 아기고냥이 입니다. +//print(dog.introduce()) // 안녕하세요. 제 이름은 모찌 입니다.