diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.pbxproj b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.pbxproj new file mode 100644 index 0000000..e340dc3 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.pbxproj @@ -0,0 +1,489 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 55; + objects = { + +/* Begin PBXBuildFile section */ + 0B547619280D35020046BDB3 /* FieldViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B547618280D35020046BDB3 /* FieldViewController.swift */; }; + 0B54761C280D4CC90046BDB3 /* UIView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B54761B280D4CC90046BDB3 /* UIView+Extension.swift */; }; + F70FE55F2813371C009858DE /* UIViewController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70FE55E2813371C009858DE /* UIViewController+Extension.swift */; }; + F72A5FB0280C5F3D005DEF66 /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A5FAF280C5F3D005DEF66 /* User.swift */; }; + F72A5FB3280C6033005DEF66 /* PokedexCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A5FB2280C6033005DEF66 /* PokedexCell.swift */; }; + F72A5FB5280C605A005DEF66 /* PokedexCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F72A5FB4280C605A005DEF66 /* PokedexCell.xib */; }; + F72A5FB7280C60F3005DEF66 /* PokedexViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A5FB6280C60F3005DEF66 /* PokedexViewController.swift */; }; + F72A5FBB280C66D6005DEF66 /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A5FB9280C66D6005DEF66 /* ImageCache.swift */; }; + F72A5FBC280C66D6005DEF66 /* ImageDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A5FBA280C66D6005DEF66 /* ImageDownloader.swift */; }; + F72A5FBE280C6FEC005DEF66 /* MapViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A5FBD280C6FEC005DEF66 /* MapViewController.swift */; }; + F72A5FC3280C711B005DEF66 /* HabitatCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A5FC1280C711B005DEF66 /* HabitatCell.swift */; }; + F72A5FC4280C711B005DEF66 /* HabitatCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F72A5FC2280C711B005DEF66 /* HabitatCell.xib */; }; + F72A5FC6280C72E3005DEF66 /* TotalHabitat.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72A5FC5280C72E3005DEF66 /* TotalHabitat.swift */; }; + F73FA2C72811BD3800C62123 /* PokedexDescriptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F73FA2C62811BD3800C62123 /* PokedexDescriptionView.swift */; }; + F73FA2C92811BD5100C62123 /* PokedexDescriptionView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F73FA2C82811BD5100C62123 /* PokedexDescriptionView.xib */; }; + F78EEC8F2809C16100EBF148 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78EEC8E2809C16100EBF148 /* AppDelegate.swift */; }; + F78EEC912809C16100EBF148 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78EEC902809C16100EBF148 /* SceneDelegate.swift */; }; + F78EEC962809C16100EBF148 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F78EEC942809C16100EBF148 /* Main.storyboard */; }; + F78EEC982809C16300EBF148 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F78EEC972809C16300EBF148 /* Assets.xcassets */; }; + F78EEC9B2809C16300EBF148 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F78EEC992809C16300EBF148 /* LaunchScreen.storyboard */; }; + F78EECA52809C1F500EBF148 /* Pokemon.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78EECA42809C1F500EBF148 /* Pokemon.swift */; }; + F78EECA82809C23B00EBF148 /* PokeSpecies.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78EECA72809C23B00EBF148 /* PokeSpecies.swift */; }; + F78EECAA2809C88A00EBF148 /* PokeHabitat.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78EECA92809C88A00EBF148 /* PokeHabitat.swift */; }; + F78EECAE2809C96500EBF148 /* NetworkAgent.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78EECAD2809C96500EBF148 /* NetworkAgent.swift */; }; + F78EECB02809C97A00EBF148 /* NetworkConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78EECAF2809C97A00EBF148 /* NetworkConstants.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0B547618280D35020046BDB3 /* FieldViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldViewController.swift; sourceTree = ""; }; + 0B54761B280D4CC90046BDB3 /* UIView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Extension.swift"; sourceTree = ""; }; + F70FE55E2813371C009858DE /* UIViewController+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Extension.swift"; sourceTree = ""; }; + F72A5FAF280C5F3D005DEF66 /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = ""; }; + F72A5FB2280C6033005DEF66 /* PokedexCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PokedexCell.swift; sourceTree = ""; }; + F72A5FB4280C605A005DEF66 /* PokedexCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PokedexCell.xib; sourceTree = ""; }; + F72A5FB6280C60F3005DEF66 /* PokedexViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PokedexViewController.swift; sourceTree = ""; }; + F72A5FB9280C66D6005DEF66 /* ImageCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageCache.swift; sourceTree = ""; }; + F72A5FBA280C66D6005DEF66 /* ImageDownloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageDownloader.swift; sourceTree = ""; }; + F72A5FBD280C6FEC005DEF66 /* MapViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewController.swift; sourceTree = ""; }; + F72A5FC1280C711B005DEF66 /* HabitatCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HabitatCell.swift; sourceTree = ""; }; + F72A5FC2280C711B005DEF66 /* HabitatCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = HabitatCell.xib; sourceTree = ""; }; + F72A5FC5280C72E3005DEF66 /* TotalHabitat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TotalHabitat.swift; sourceTree = ""; }; + F73FA2C62811BD3800C62123 /* PokedexDescriptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PokedexDescriptionView.swift; sourceTree = ""; }; + F73FA2C82811BD5100C62123 /* PokedexDescriptionView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PokedexDescriptionView.xib; sourceTree = ""; }; + F78EEC8B2809C16100EBF148 /* PokemonProject.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PokemonProject.app; sourceTree = BUILT_PRODUCTS_DIR; }; + F78EEC8E2809C16100EBF148 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + F78EEC902809C16100EBF148 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + F78EEC952809C16100EBF148 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + F78EEC972809C16300EBF148 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + F78EEC9A2809C16300EBF148 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + F78EEC9C2809C16300EBF148 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + F78EECA42809C1F500EBF148 /* Pokemon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pokemon.swift; sourceTree = ""; }; + F78EECA72809C23B00EBF148 /* PokeSpecies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PokeSpecies.swift; sourceTree = ""; }; + F78EECA92809C88A00EBF148 /* PokeHabitat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PokeHabitat.swift; sourceTree = ""; }; + F78EECAD2809C96500EBF148 /* NetworkAgent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkAgent.swift; sourceTree = ""; }; + F78EECAF2809C97A00EBF148 /* NetworkConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkConstants.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + F78EEC882809C16100EBF148 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0B54761A280D4CBC0046BDB3 /* Extension */ = { + isa = PBXGroup; + children = ( + 0B54761B280D4CC90046BDB3 /* UIView+Extension.swift */, + F70FE55E2813371C009858DE /* UIViewController+Extension.swift */, + ); + path = Extension; + sourceTree = ""; + }; + F72A5FAD280C5C95005DEF66 /* ViewController */ = { + isa = PBXGroup; + children = ( + F72A5FB6280C60F3005DEF66 /* PokedexViewController.swift */, + F72A5FBD280C6FEC005DEF66 /* MapViewController.swift */, + 0B547618280D35020046BDB3 /* FieldViewController.swift */, + ); + path = ViewController; + sourceTree = ""; + }; + F72A5FAE280C5CE4005DEF66 /* System */ = { + isa = PBXGroup; + children = ( + F78EEC8E2809C16100EBF148 /* AppDelegate.swift */, + F78EEC902809C16100EBF148 /* SceneDelegate.swift */, + ); + path = System; + sourceTree = ""; + }; + F72A5FB1280C601B005DEF66 /* View */ = { + isa = PBXGroup; + children = ( + F72A5FB2280C6033005DEF66 /* PokedexCell.swift */, + F72A5FB4280C605A005DEF66 /* PokedexCell.xib */, + F72A5FC1280C711B005DEF66 /* HabitatCell.swift */, + F72A5FC2280C711B005DEF66 /* HabitatCell.xib */, + F73FA2C62811BD3800C62123 /* PokedexDescriptionView.swift */, + F73FA2C82811BD5100C62123 /* PokedexDescriptionView.xib */, + ); + path = View; + sourceTree = ""; + }; + F72A5FB8280C66B0005DEF66 /* Common */ = { + isa = PBXGroup; + children = ( + F72A5FB9280C66D6005DEF66 /* ImageCache.swift */, + F72A5FBA280C66D6005DEF66 /* ImageDownloader.swift */, + F78EECAD2809C96500EBF148 /* NetworkAgent.swift */, + F78EECAF2809C97A00EBF148 /* NetworkConstants.swift */, + ); + path = Common; + sourceTree = ""; + }; + F78EEC822809C16100EBF148 = { + isa = PBXGroup; + children = ( + F78EEC8D2809C16100EBF148 /* PokemonProject */, + F78EEC8C2809C16100EBF148 /* Products */, + ); + sourceTree = ""; + }; + F78EEC8C2809C16100EBF148 /* Products */ = { + isa = PBXGroup; + children = ( + F78EEC8B2809C16100EBF148 /* PokemonProject.app */, + ); + name = Products; + sourceTree = ""; + }; + F78EEC8D2809C16100EBF148 /* PokemonProject */ = { + isa = PBXGroup; + children = ( + 0B54761A280D4CBC0046BDB3 /* Extension */, + F72A5FAE280C5CE4005DEF66 /* System */, + F72A5FB8280C66B0005DEF66 /* Common */, + F78EECA32809C1E600EBF148 /* Model */, + F72A5FB1280C601B005DEF66 /* View */, + F72A5FAD280C5C95005DEF66 /* ViewController */, + F78EEC942809C16100EBF148 /* Main.storyboard */, + F78EEC972809C16300EBF148 /* Assets.xcassets */, + F78EEC992809C16300EBF148 /* LaunchScreen.storyboard */, + F78EEC9C2809C16300EBF148 /* Info.plist */, + ); + path = PokemonProject; + sourceTree = ""; + }; + F78EECA32809C1E600EBF148 /* Model */ = { + isa = PBXGroup; + children = ( + F78EECA42809C1F500EBF148 /* Pokemon.swift */, + F78EECA72809C23B00EBF148 /* PokeSpecies.swift */, + F78EECA92809C88A00EBF148 /* PokeHabitat.swift */, + F72A5FAF280C5F3D005DEF66 /* User.swift */, + F72A5FC5280C72E3005DEF66 /* TotalHabitat.swift */, + ); + path = Model; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + F78EEC8A2809C16100EBF148 /* PokemonProject */ = { + isa = PBXNativeTarget; + buildConfigurationList = F78EEC9F2809C16300EBF148 /* Build configuration list for PBXNativeTarget "PokemonProject" */; + buildPhases = ( + F78EEC872809C16100EBF148 /* Sources */, + F78EEC882809C16100EBF148 /* Frameworks */, + F78EEC892809C16100EBF148 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = PokemonProject; + productName = PokemonProject; + productReference = F78EEC8B2809C16100EBF148 /* PokemonProject.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + F78EEC832809C16100EBF148 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1320; + LastUpgradeCheck = 1320; + TargetAttributes = { + F78EEC8A2809C16100EBF148 = { + CreatedOnToolsVersion = 13.2.1; + }; + }; + }; + buildConfigurationList = F78EEC862809C16100EBF148 /* Build configuration list for PBXProject "PokemonProject" */; + compatibilityVersion = "Xcode 13.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = F78EEC822809C16100EBF148; + productRefGroup = F78EEC8C2809C16100EBF148 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + F78EEC8A2809C16100EBF148 /* PokemonProject */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + F78EEC892809C16100EBF148 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F73FA2C92811BD5100C62123 /* PokedexDescriptionView.xib in Resources */, + F72A5FC4280C711B005DEF66 /* HabitatCell.xib in Resources */, + F72A5FB5280C605A005DEF66 /* PokedexCell.xib in Resources */, + F78EEC9B2809C16300EBF148 /* LaunchScreen.storyboard in Resources */, + F78EEC982809C16300EBF148 /* Assets.xcassets in Resources */, + F78EEC962809C16100EBF148 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + F78EEC872809C16100EBF148 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F78EECB02809C97A00EBF148 /* NetworkConstants.swift in Sources */, + F72A5FBC280C66D6005DEF66 /* ImageDownloader.swift in Sources */, + 0B547619280D35020046BDB3 /* FieldViewController.swift in Sources */, + F78EECA52809C1F500EBF148 /* Pokemon.swift in Sources */, + F78EECAA2809C88A00EBF148 /* PokeHabitat.swift in Sources */, + F72A5FB3280C6033005DEF66 /* PokedexCell.swift in Sources */, + F73FA2C72811BD3800C62123 /* PokedexDescriptionView.swift in Sources */, + F78EECA82809C23B00EBF148 /* PokeSpecies.swift in Sources */, + F70FE55F2813371C009858DE /* UIViewController+Extension.swift in Sources */, + F72A5FBB280C66D6005DEF66 /* ImageCache.swift in Sources */, + F72A5FB0280C5F3D005DEF66 /* User.swift in Sources */, + F72A5FC3280C711B005DEF66 /* HabitatCell.swift in Sources */, + F72A5FB7280C60F3005DEF66 /* PokedexViewController.swift in Sources */, + 0B54761C280D4CC90046BDB3 /* UIView+Extension.swift in Sources */, + F78EEC8F2809C16100EBF148 /* AppDelegate.swift in Sources */, + F78EECAE2809C96500EBF148 /* NetworkAgent.swift in Sources */, + F78EEC912809C16100EBF148 /* SceneDelegate.swift in Sources */, + F72A5FC6280C72E3005DEF66 /* TotalHabitat.swift in Sources */, + F72A5FBE280C6FEC005DEF66 /* MapViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + F78EEC942809C16100EBF148 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + F78EEC952809C16100EBF148 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + F78EEC992809C16300EBF148 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + F78EEC9A2809C16300EBF148 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + F78EEC9D2809C16300EBF148 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + 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; + GCC_C_LANGUAGE_STANDARD = gnu11; + 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; + IPHONEOS_DEPLOYMENT_TARGET = 15.2; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + F78EEC9E2809C16300EBF148 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + 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; + GCC_C_LANGUAGE_STANDARD = gnu11; + 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; + IPHONEOS_DEPLOYMENT_TARGET = 15.2; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + F78EECA02809C16300EBF148 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = QKG65XDLX8; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = PokemonProject/Info.plist; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0.0; + PRODUCT_BUNDLE_IDENTIFIER = com.bong.Pokemon; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + F78EECA12809C16300EBF148 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = QKG65XDLX8; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = PokemonProject/Info.plist; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0.0; + PRODUCT_BUNDLE_IDENTIFIER = com.bong.Pokemon; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + F78EEC862809C16100EBF148 /* Build configuration list for PBXProject "PokemonProject" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F78EEC9D2809C16300EBF148 /* Debug */, + F78EEC9E2809C16300EBF148 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F78EEC9F2809C16300EBF148 /* Build configuration list for PBXNativeTarget "PokemonProject" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F78EECA02809C16300EBF148 /* Debug */, + F78EECA12809C16300EBF148 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = F78EEC832809C16100EBF148 /* Project object */; +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcshareddata/xcschemes/PokemonProject.xcscheme b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcshareddata/xcschemes/PokemonProject.xcscheme new file mode 100644 index 0000000..fdfcd50 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcshareddata/xcschemes/PokemonProject.xcscheme @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcuserdata/bong.xcuserdatad/xcschemes/xcschememanagement.plist b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcuserdata/bong.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..fc2b161 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcuserdata/bong.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + PokemonProject.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcuserdata/seunghee.xcuserdatad/xcschemes/xcschememanagement.plist b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcuserdata/seunghee.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..c682335 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject.xcodeproj/xcuserdata/seunghee.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + PokemonProject.xcscheme_^#shared#^_ + + orderHint + 0 + + + SuppressBuildableAutocreation + + F78EEC8A2809C16100EBF148 + + primary + + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/AccentColor.colorset/Contents.json b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/AppIcon.appiconset/Contents.json b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..9221b9b --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/Contents.json b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokeball.imageset/Contents.json b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokeball.imageset/Contents.json new file mode 100644 index 0000000..9e84fe4 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokeball.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "pokeball.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokeball.imageset/pokeball.png b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokeball.imageset/pokeball.png new file mode 100644 index 0000000..077d0d3 Binary files /dev/null and b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokeball.imageset/pokeball.png differ diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokedex.imageset/Contents.json b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokedex.imageset/Contents.json new file mode 100644 index 0000000..9c940c9 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokedex.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "pokedex.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokedex.imageset/pokedex.png b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokedex.imageset/pokedex.png new file mode 100644 index 0000000..49fbaec Binary files /dev/null and b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/pokedex.imageset/pokedex.png differ diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/professor_oh.imageset/Contents.json b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/professor_oh.imageset/Contents.json new file mode 100644 index 0000000..706380e --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/professor_oh.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "professor_oh.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/professor_oh.imageset/professor_oh.png b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/professor_oh.imageset/professor_oh.png new file mode 100644 index 0000000..a4ca25c Binary files /dev/null and b/seunghee/PokemonProject/PokemonProject/PokemonProject/Assets.xcassets/professor_oh.imageset/professor_oh.png differ diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Base.lproj/LaunchScreen.storyboard b/seunghee/PokemonProject/PokemonProject/PokemonProject/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..865e932 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Base.lproj/Main.storyboard b/seunghee/PokemonProject/PokemonProject/PokemonProject/Base.lproj/Main.storyboard new file mode 100644 index 0000000..6990b28 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Base.lproj/Main.storyboard @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/ImageCache.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/ImageCache.swift new file mode 100644 index 0000000..ca53b2d --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/ImageCache.swift @@ -0,0 +1,23 @@ +// +// Cache.swift +// ImageCache +// +// Created by seungbong on 2022/03/26. +// + +import UIKit + +class ImageCache { + private static var imageCache: NSCache? + + static var shared: NSCache { + if imageCache == nil { + imageCache = NSCache() + } + return imageCache! + } + + static func clear() { + imageCache = nil + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/ImageDownloader.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/ImageDownloader.swift new file mode 100644 index 0000000..b30b46d --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/ImageDownloader.swift @@ -0,0 +1,52 @@ +// +// ImageDownloader.swift +// ImageCachingProject +// +// Created by seungbong on 2022/03/26. +// + +import UIKit + +class ImageDownloader { + + private static var imageDownloader: ImageDownloader? + + static var shared: ImageDownloader { + if imageDownloader == nil { + imageDownloader = ImageDownloader() + } + return imageDownloader! + } + + func downloadImage(from urlString: String, + completion: @escaping (UIImage?)->Void) { + let cacheKey: String = urlString + if let image = cachedImage(key: urlString) { + completion(image) + return + } + + DispatchQueue.global().async { + guard let url = URL(string: urlString), + let data = try? Data(contentsOf: url), + let loadedImage = UIImage(data: data) else { + completion(nil) + return + } + self.saveLoadedImage(key: cacheKey, image: loadedImage) + completion(loadedImage) + } + } + + private func cachedImage(key: String) -> UIImage? { + return ImageCache.shared.object(forKey: key as NSString) + } + + private func saveLoadedImage(key: String, image: UIImage) { + ImageCache.shared.setObject(image, forKey: key as NSString) + } + + func clearCache() { + ImageCache.clear() + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/NetworkAgent.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/NetworkAgent.swift new file mode 100644 index 0000000..7b71d24 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/NetworkAgent.swift @@ -0,0 +1,78 @@ +// +// NetworkAgent.swift +// PokemonProject +// +// Created by seungbong on 2022/04/16. +// + +import Foundation + +class NetworkAgent { + + enum NetworkError: Error { + case invalidUrl + case serverError + case parsingError + } + + static var shared = NetworkAgent() + + func requestGET(_ urlString: String, completion: @escaping (Data)->Void) { + guard let url = URL(string: urlString) else { return } + + let urlRequest = URLRequest(url: url) + let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in + if let error = error { + self.handledClientError(error) + return + } + guard let httpResponse = response as? HTTPURLResponse, + (200...299).contains(httpResponse.statusCode) else { + self.handledServerError(response) + return + } + + guard let data = data else { return } + completion(data) + + } + task.resume() + } + + func requestGET(_ urlString: String, + responseType: T.Type, + completion: @escaping (T)->Void) { + guard let url = URL(string: urlString) else { return } + + let urlRequest = URLRequest(url: url) + let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in + if let error = error { + self.handledClientError(error) + return + } + guard let httpResponse = response as? HTTPURLResponse, + (200...299).contains(httpResponse.statusCode) else { + self.handledServerError(response) + return + } + + guard let data = data else { return } + let decoder = JSONDecoder() + if let json = try? decoder.decode(T.self, from: data) { + completion(json) + } else { + print("parsing error") + } + } + task.resume() + } + + // MARK: - Error Handling + private func handledClientError(_ error: Error) { + print("[client] \(error.localizedDescription)") + } + + private func handledServerError(_ response: URLResponse?) { + print("[server] \(response?.description ?? "")") + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/NetworkConstants.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/NetworkConstants.swift new file mode 100644 index 0000000..df095d6 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Common/NetworkConstants.swift @@ -0,0 +1,15 @@ +// +// NetworkConstants.swift +// PokemonProject +// +// Created by seungbong on 2022/04/16. +// + +import Foundation + +class NetworkConstants { + + static let pokemonAPI = "https://pokeapi.co/api/v2/pokemon/" // 포켓몬 API + static let speciesAPI = "https://pokeapi.co/api/v2/pokemon-species" // 포켓몬 종류 API + static let habitateAPI = "https://pokeapi.co/api/v2/pokemon-habitat" // 포켓몬 서식지 API +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Extension/UIView+Extension.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Extension/UIView+Extension.swift new file mode 100644 index 0000000..c1b2249 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Extension/UIView+Extension.swift @@ -0,0 +1,42 @@ +// +// UIView+Extension.swift +// PokemonProject +// +// Created by seunghee on 2022/04/18. +// + +import UIKit + +extension UIView { + func startRotate() { + DispatchQueue.main.async { + let rotation : CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z") + rotation.fromValue = 0 + rotation.toValue = NSNumber(value: M_PI * 2) + rotation.duration = 2 + rotation.isCumulative = true + rotation.repeatCount = FLT_MAX + self.layer.add(rotation, forKey: "rotationAnimation") + } + } + + func stopRotate() { + DispatchQueue.main.async { + self.layer.removeAnimation(forKey: "rotationAnimation") + } + } + + func setCornerRadius(_ radius: CGFloat = 20.0) { + self.layer.cornerRadius = radius + } + + func setConstraintEqualTo(_ view: UIView) { + self.translatesAutoresizingMaskIntoConstraints = false + NSLayoutConstraint.activate([ + self.leadingAnchor.constraint(equalTo: view.leadingAnchor), + self.trailingAnchor.constraint(equalTo: view.trailingAnchor), + self.topAnchor.constraint(equalTo: view.topAnchor), + self.bottomAnchor.constraint(equalTo: view.bottomAnchor) + ]) + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Extension/UIViewController+Extension.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Extension/UIViewController+Extension.swift new file mode 100644 index 0000000..36245b6 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Extension/UIViewController+Extension.swift @@ -0,0 +1,19 @@ +// +// UIViewController+Extension.swift +// PokemonProject +// +// Created by seungbong on 2022/04/23. +// + +import UIKit + +extension UIViewController { + func showAlert(message: String) { + DispatchQueue.main.async { + let alert = UIAlertController(title: "안내", + message: message, + preferredStyle: .alert) + self.present(alert, animated: true, completion: nil) + } + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Info.plist b/seunghee/PokemonProject/PokemonProject/PokemonProject/Info.plist new file mode 100644 index 0000000..dd3c9af --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Info.plist @@ -0,0 +1,25 @@ + + + + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/PokeHabitat.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/PokeHabitat.swift new file mode 100644 index 0000000..172d22e --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/PokeHabitat.swift @@ -0,0 +1,36 @@ +// +// PokeHabitat.swift +// PokemonProject +// +// Created by seungbong on 2022/04/16. +// + +import Foundation + +struct PokeHabitat: Codable { + var id: Int + var name: String + var speciesInfoList: [PokeSpeciesInfo] + + var response: Response? + + init(json: Response) { + self.id = json.id + self.name = json.name + self.speciesInfoList = json.pokemon_species ?? [] + } +} + +// MARK: - Poke Species Property Types +extension PokeHabitat { + struct Response: Codable { + var id: Int + var name: String + var pokemon_species: [PokeSpeciesInfo]? + } + + struct PokeSpeciesInfo: Codable { + var name: String + var url: String + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/PokeSpecies.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/PokeSpecies.swift new file mode 100644 index 0000000..868e4f8 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/PokeSpecies.swift @@ -0,0 +1,86 @@ +// +// PokeSpecies.swift +// PokemonProject +// +// Created by seungbong on 2022/04/16. +// + +import Foundation + +struct PokeSpecies: Codable { + + var id: Int + var name: String + var habitatName: String // 서식지 + var captureRate: Int // 포획률 (the higher the number, the easier the catch, 0~255) + var type: String + var descriptions: [String] + var habitat: NameUrlInfo? + + init(json: Response) { + self.id = json.id + self.name = PokeSpecies.korLanguage(from: json.names) ?? json.name + self.type = PokeSpecies.korType(from: json.genera) + self.habitat = json.habitat + self.captureRate = json.capture_rate + self.habitatName = json.habitat?.name ?? "" + self.descriptions = PokeSpecies.descriptionList(from: json.flavor_text_entries) + } + + + static func korLanguage(from nameList: [LanguageInfo]) -> String? { + let korName = nameList.filter{$0.language.name == "ko"}.first.map({$0.name}) + return (korName?.count == 0) ? nil : korName + } + + static func korType(from generaInfo: [GeneraInfo]) -> String { + return generaInfo.filter{$0.language.name == "ko"}.first.map({$0.genus}) ?? "???" + } + + static func descriptionList(from infoList: [DescriptionInfo]) -> [String] { + var list: [String] = [] + for info in infoList { + if info.language.name == "ko" && list.contains(info.flavor_text) == false { + list.append(info.flavor_text) + } + } + return list + } +} + +// MARK: - Poke Species Property Types +extension PokeSpecies { + + struct Response: Codable { + var id: Int + var name: String + var names: [LanguageInfo] + var habitat: NameUrlInfo? + var capture_rate: Int + var flavor_text_entries: [DescriptionInfo] + var genera: [GeneraInfo] + } + + struct NameUrlInfo: Codable { + var name: String + var url: String + } + + struct LanguageInfo: Codable { + var name: String + var language: NameUrlInfo + } + + struct DescriptionInfo: Codable { + var flavor_text: String + var language: NameUrlInfo + var version: NameUrlInfo + } + + struct GeneraInfo: Codable { + var genus: String + var language: NameUrlInfo + } +} + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/Pokemon.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/Pokemon.swift new file mode 100644 index 0000000..9cd5098 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/Pokemon.swift @@ -0,0 +1,47 @@ +// +// Pokemon.swift +// PokemonProject +// +// Created by seungbong on 2022/04/16. +// + +import UIKit + +struct Pokemon { + var id: Int + var name: String + var species: SpaiesInfo? + var sprites: SpriteInfo? + + var spriteImages: [UIImage] = [] + var pokeSpacies: PokeSpecies? + + init(json: Response) { + self.id = json.id + self.name = json.name + self.species = json.species + self.sprites = json.sprites + } +} + +// MARK: - Poke Species Property Types +extension Pokemon { + struct Response: Codable { + var id: Int + var name: String + var species: SpaiesInfo? + var sprites: SpriteInfo? + } + + struct SpaiesInfo: Codable { + var name: String + var url: String + } + + struct SpriteInfo: Codable { + var back_default: String? + var back_shiny: String? + var front_default: String? + var front_shiny: String? + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/TotalHabitat.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/TotalHabitat.swift new file mode 100644 index 0000000..1153753 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/TotalHabitat.swift @@ -0,0 +1,29 @@ +// +// TotalHabitat.swift +// PokemonProject +// +// Created by seungbong on 2022/04/18. +// + +import Foundation + +struct TotalHabitat { + var habitatInfoList: [HabitatInfo] + + init(json: Response) { + self.habitatInfoList = json.results + } +} + +// MARK: - Poke Species Property Types +extension TotalHabitat { + struct Response: Codable { + var results: [HabitatInfo] + } + + struct HabitatInfo: Codable { + var name: String + var url: String + + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/User.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/User.swift new file mode 100644 index 0000000..924ea34 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/Model/User.swift @@ -0,0 +1,27 @@ +// +// User.swift +// PokemonProject +// +// Created by seungbong on 2022/04/17. +// + +import Foundation + +class User { + private static var user: User? + + static var shared: User { + if User.user == nil { + User.user = User() + } + return User.user! + } + + var ownedPokemonList: [Pokemon] = [] + + func addPokemon(_ pokemon: Pokemon) { + if ownedPokemonList.filter({$0.id == pokemon.id}).isEmpty { + ownedPokemonList.append(pokemon) + } + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/System/AppDelegate.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/System/AppDelegate.swift new file mode 100644 index 0000000..f1f2bd3 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/System/AppDelegate.swift @@ -0,0 +1,25 @@ +// +// AppDelegate.swift +// PokemonProject +// +// Created by seungbong on 2022/04/16. +// + +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + return true + } + + // MARK: UISceneSession Lifecycle + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + } +} + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/System/SceneDelegate.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/System/SceneDelegate.swift new file mode 100644 index 0000000..66f3588 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/System/SceneDelegate.swift @@ -0,0 +1,33 @@ +// +// SceneDelegate.swift +// PokemonProject +// +// Created by seungbong on 2022/04/16. +// + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + guard let _ = (scene as? UIWindowScene) else { return } + } + + func sceneDidDisconnect(_ scene: UIScene) { + } + + func sceneDidBecomeActive(_ scene: UIScene) { + } + + func sceneWillResignActive(_ scene: UIScene) { + } + + func sceneWillEnterForeground(_ scene: UIScene) { + } + + func sceneDidEnterBackground(_ scene: UIScene) { + } +} + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/View/HabitatCell.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/HabitatCell.swift new file mode 100644 index 0000000..1879c08 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/HabitatCell.swift @@ -0,0 +1,19 @@ +// +// HabitatCell.swift +// PokemonProject +// +// Created by seungbong on 2022/04/18. +// + +import UIKit + +class HabitatCell: UICollectionViewCell { + + @IBOutlet weak var habitatNameLabel: UILabel! + + static let id = "HabitatCell" + + override func prepareForReuse() { + habitatNameLabel.text = "" + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/View/HabitatCell.xib b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/HabitatCell.xib new file mode 100644 index 0000000..71072a1 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/HabitatCell.xib @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexCell.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexCell.swift new file mode 100644 index 0000000..678e619 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexCell.swift @@ -0,0 +1,19 @@ +// +// PokedexCell.swift +// PokemonProject +// +// Created by seungbong on 2022/04/17. +// + +import UIKit + +class PokedexCell: UICollectionViewCell { + + static let id = "PokedexCell" + + @IBOutlet weak var pokemonImageView: UIImageView! + + override func prepareForReuse() { + pokemonImageView.image = nil + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexCell.xib b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexCell.xib new file mode 100644 index 0000000..b02d7db --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexCell.xib @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexDescriptionView.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexDescriptionView.swift new file mode 100644 index 0000000..2e430c4 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexDescriptionView.swift @@ -0,0 +1,44 @@ +// +// DescriptionView.swift +// PokemonProject +// +// Created by seungbong on 2022/04/22. +// + + +import UIKit + +class PokedexDescriptionView: UIView { + private let id = "PokedexDescriptionView" + @IBOutlet weak var descriptionLabel: UILabel! + + override init(frame: CGRect) { + super.init(frame: frame) + commonInit() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + commonInit() + } + + private func commonInit() { + let view = Bundle.main.loadNibNamed(id, owner: self, options: nil)?.first as! UIView + view.frame = self.bounds + self.addSubview(view) + } + + func updateLabel(species: PokeSpecies) { + var descriptionText = "이름: \(species.name)\n타입: \(species.type)" + for description in species.descriptions { + let textRemovedLineSpacing = description.replacingOccurrences(of: "\n", with: " ") + descriptionText += "\n\(textRemovedLineSpacing)" + } + descriptionLabel.text = descriptionText + } + + @IBAction func closeButtonDidTap(_ sender: Any) { + self.removeFromSuperview() + } +} + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexDescriptionView.xib b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexDescriptionView.xib new file mode 100644 index 0000000..ccd086e --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/View/PokedexDescriptionView.xib @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/ViewController/FieldViewController.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/ViewController/FieldViewController.swift new file mode 100644 index 0000000..fecb064 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/ViewController/FieldViewController.swift @@ -0,0 +1,145 @@ +// +// FieldViewController.swift +// PokemonProject +// +// Created by seunghee on 2022/04/18. +// + +import UIKit + +class FieldViewController: UIViewController { + + @IBOutlet weak var pokemonImageView: UIImageView! + @IBOutlet weak var pokemonNameLabel: UILabel! + @IBOutlet weak var descriptionLabel: UILabel! + + static let id = "FieldViewController" + + var pokeSpecies: PokeSpecies? + var pokemon: Pokemon? + + enum CatchResult { + case captured + case miss + case runAway + + var description: String { + switch self { + case .captured: return "을(를) 잡았다!" + case .miss: return "이(가) 잡히지 않았다." + case .runAway: return "이(가) 도망갔다." + } + } + + var textColor: UIColor { + switch self { + case .captured: return .orange + case .miss: return .black + case .runAway: return .cyan + } + } + } + + override func viewDidLoad() { + super.viewDidLoad() + + fetchPokemon() + configureView() + } + + private func configureView(){ + pokemonNameLabel.text = pokeSpecies?.name ?? "??" + descriptionLabel.text = "이(가) 나타났다!" + descriptionLabel.textColor = .black + } + + private func fetchPokemon() { + guard let species = pokeSpecies else { return } + + let urlString = NetworkConstants.pokemonAPI + "\(species.id)" + NetworkAgent.shared.requestGET(urlString, responseType: Pokemon.Response.self) { [weak self] response in + guard let self = self else { return } + + self.pokemon = Pokemon(json: response) + self.pokemon?.pokeSpacies = self.pokeSpecies + self.fetchPokemonImage() + } + } + + private func fetchPokemonImage() { + guard let pokemon = pokemon, + let sprites = pokemon.sprites else { return } + + let imageUrls = [sprites.front_default, sprites.front_shiny, sprites.back_default] + for imageUrl in imageUrls { + ImageDownloader.shared.downloadImage(from: imageUrl ?? "") { [weak self] pokemonImage in + guard let self = self else { return } + + DispatchQueue.main.async { + if imageUrl == sprites.front_default { + self.pokemonImageView.image = pokemonImage + self.pokemonImageView.startRotate() + } + } + } + } + } + + @IBAction func throwButtonDidTap(_ sender: Any) { + let captureResult = getCatchResult() + updateView(state: captureResult) + } + + private func getCatchResult() -> CatchResult { + let captureRate: Int = pokeSpecies?.captureRate ?? 0 + let runAwayRate: Int = Int(Double(255 - captureRate) * 0.3) + let random = Int.random(in: 0...255) + print("\(random) / \(captureRate) / \(runAwayRate)") + + if random <= captureRate { + return .captured + } else if random <= runAwayRate { + return .runAway + } else { + return .miss + } + } + + private func updateView(state: CatchResult) { + guard let pokemon = self.pokemon else { return } + descriptionLabel.text = state.description + descriptionLabel.textColor = state.textColor + + switch state { + case .captured: + User.shared.addPokemon(pokemon) + changeImageView(url: pokemon.sprites?.front_shiny ?? "", isRotate: false) + dismissViewController() + case .runAway: + changeImageView(url: pokemon.sprites?.back_default ?? "", isRotate: false) + dismissViewController() + case .miss: + break + } + } + + private func changeImageView(url: String, isRotate: Bool = false) { + ImageDownloader.shared.downloadImage(from: url, completion: { image in + DispatchQueue.main.async { + self.pokemonImageView.image = image + if isRotate { + self.pokemonImageView.startRotate() + } else { + self.pokemonImageView.stopRotate() + } + } + }) + } + + private func dismissViewController() { + self.view.isUserInteractionEnabled = false + DispatchQueue.main.asyncAfter(deadline: .now() + 1.5, execute: { + self.navigationController?.popViewController(animated: true) + }) + } +} diff --git a/seunghee/PokemonProject/PokemonProject/PokemonProject/ViewController/MapViewController.swift b/seunghee/PokemonProject/PokemonProject/PokemonProject/ViewController/MapViewController.swift new file mode 100644 index 0000000..56c1d39 --- /dev/null +++ b/seunghee/PokemonProject/PokemonProject/PokemonProject/ViewController/MapViewController.swift @@ -0,0 +1,97 @@ +// +// MapViewController.swift +// PokemonProject +// +// Created by seungbong on 2022/04/18. +// + +import UIKit + +class MapViewController: UIViewController { + + @IBOutlet weak var mapCollectionView: UICollectionView! + + static let id = "MapViewController" + + var totalHabitat: TotalHabitat? + var loadedHabitatList: [PokeHabitat] = [] + + override func viewDidLoad() { + super.viewDidLoad() + + fetchTotalHabitat() + configureView() + } + + private func configureView() { + let layout = UICollectionViewFlowLayout() + layout.itemSize = CGSize(width: 120, height: 120) + mapCollectionView.collectionViewLayout = layout + mapCollectionView.dataSource = self + mapCollectionView.delegate = self + + let nib = UINib(nibName: HabitatCell.id, bundle: nil) + mapCollectionView.register(nib, forCellWithReuseIdentifier: HabitatCell.id) + } + + private func fetchTotalHabitat() { + NetworkAgent.shared.requestGET(NetworkConstants.habitateAPI, + responseType: TotalHabitat.Response.self) { response in + self.totalHabitat = TotalHabitat(json: response) + DispatchQueue.main.async { + self.mapCollectionView.reloadData() + } + } + } + + private func fetchHabitat(url: String, completion: @escaping (PokeHabitat)->Void) { + NetworkAgent.shared.requestGET(url, responseType: PokeHabitat.Response.self) { response in + completion(PokeHabitat(json: response)) + } + } + + private func fetchSpecies(url: String, completion: @escaping (PokeSpecies)->Void) { + NetworkAgent.shared.requestGET(url, responseType: PokeSpecies.Response.self) { response in + completion(PokeSpecies(json: response)) + } + } +} + +// MARK: - CollectionView Delegate +extension MapViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return totalHabitat?.habitatInfoList.count ?? 0 + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: HabitatCell.id, for: indexPath) as? HabitatCell else { + return UICollectionViewCell() + } + + guard let habitatList = totalHabitat else { return UICollectionViewCell() } + + cell.habitatNameLabel.text = habitatList.habitatInfoList[indexPath.row].name + cell.setCornerRadius() + return cell + } + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + let selectedHabitatUrl = totalHabitat?.habitatInfoList[indexPath.row].url ?? "" + fetchHabitat(url: selectedHabitatUrl, completion: { [weak self] habiatat in + guard let self = self else { return } + + let random = Int.random(in: 0.. Int { + return User.shared.ownedPokemonList.count + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PokedexCell.id, for: indexPath) as? PokedexCell else { + return UICollectionViewCell() + } + + let pokemon = User.shared.ownedPokemonList[indexPath.row] + let downloadUrl = pokemon.sprites?.front_default ?? "" + ImageDownloader.shared.downloadImage(from: downloadUrl) { image in + DispatchQueue.main.async { + cell.pokemonImageView.image = image + } + } + return cell + } + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + let selectedPokemon = User.shared.ownedPokemonList[indexPath.row] + guard let species = selectedPokemon.pokeSpacies else { return } + let descriptionView = PokedexDescriptionView() + descriptionView.updateLabel(species: species) + self.view.addSubview(descriptionView) + descriptionView.setConstraintEqualTo(self.view) + } +}