diff --git a/Firebase Project/Firebase Project.xcodeproj/project.pbxproj b/Firebase Project/Firebase Project.xcodeproj/project.pbxproj new file mode 100644 index 0000000..4ff35be --- /dev/null +++ b/Firebase Project/Firebase Project.xcodeproj/project.pbxproj @@ -0,0 +1,403 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 2C0BBF3521BA80730080AAE5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C0BBF3421BA80730080AAE5 /* AppDelegate.swift */; }; + 2C0BBF3C21BA80880080AAE5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2C0BBF3B21BA80880080AAE5 /* Assets.xcassets */; }; + 2C0BBF3F21BA80880080AAE5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2C0BBF3D21BA80880080AAE5 /* LaunchScreen.storyboard */; }; + 2C0BBF4B21BA80D90080AAE5 /* Firebase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C0BBF4A21BA80D90080AAE5 /* Firebase.swift */; }; + 2C0BBF4D21BA81160080AAE5 /* FirebaseItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C0BBF4C21BA81160080AAE5 /* FirebaseItem.swift */; }; + 2C0BBF5321BA81540080AAE5 /* EntryCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2C0BBF4E21BA81540080AAE5 /* EntryCell.xib */; }; + 2C0BBF5421BA81540080AAE5 /* PersonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C0BBF4F21BA81540080AAE5 /* PersonCell.swift */; }; + 2C0BBF5521BA81540080AAE5 /* EntryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C0BBF5021BA81540080AAE5 /* EntryCell.swift */; }; + 2C0BBF5621BA81540080AAE5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2C0BBF5121BA81540080AAE5 /* Main.storyboard */; }; + 2C0BBF5721BA81540080AAE5 /* PersonCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2C0BBF5221BA81540080AAE5 /* PersonCell.xib */; }; + 2C0BBF5921BA819F0080AAE5 /* Person.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C0BBF5821BA819F0080AAE5 /* Person.swift */; }; + 2C0BBF5B21BA81C00080AAE5 /* ModelUpdateClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C0BBF5A21BA81C00080AAE5 /* ModelUpdateClient.swift */; }; + 2C0BBF5D21BA81EB0080AAE5 /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C0BBF5C21BA81EB0080AAE5 /* Model.swift */; }; + 2C0BBF5F21BA82400080AAE5 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C0BBF5E21BA82400080AAE5 /* DetailViewController.swift */; }; + 2C0BBF6121BA82870080AAE5 /* TableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C0BBF6021BA82870080AAE5 /* TableViewController.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 2C0BBF3121BA80730080AAE5 /* Firebase Project.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Firebase Project.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 2C0BBF3421BA80730080AAE5 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 2C0BBF3B21BA80880080AAE5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 2C0BBF3E21BA80880080AAE5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 2C0BBF4021BA80880080AAE5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 2C0BBF4A21BA80D90080AAE5 /* Firebase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Firebase.swift; sourceTree = ""; }; + 2C0BBF4C21BA81160080AAE5 /* FirebaseItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirebaseItem.swift; sourceTree = ""; }; + 2C0BBF4E21BA81540080AAE5 /* EntryCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EntryCell.xib; sourceTree = ""; }; + 2C0BBF4F21BA81540080AAE5 /* PersonCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersonCell.swift; sourceTree = ""; }; + 2C0BBF5021BA81540080AAE5 /* EntryCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntryCell.swift; sourceTree = ""; }; + 2C0BBF5121BA81540080AAE5 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; + 2C0BBF5221BA81540080AAE5 /* PersonCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PersonCell.xib; sourceTree = ""; }; + 2C0BBF5821BA819F0080AAE5 /* Person.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Person.swift; sourceTree = ""; }; + 2C0BBF5A21BA81C00080AAE5 /* ModelUpdateClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelUpdateClient.swift; sourceTree = ""; }; + 2C0BBF5C21BA81EB0080AAE5 /* Model.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = ""; }; + 2C0BBF5E21BA82400080AAE5 /* DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; + 2C0BBF6021BA82870080AAE5 /* TableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewController.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 2C0BBF2E21BA80730080AAE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 2C0BBF2821BA80730080AAE5 = { + isa = PBXGroup; + children = ( + 2C0BBF3321BA80730080AAE5 /* Firebase Project */, + 2C0BBF3221BA80730080AAE5 /* Products */, + ); + sourceTree = ""; + }; + 2C0BBF3221BA80730080AAE5 /* Products */ = { + isa = PBXGroup; + children = ( + 2C0BBF3121BA80730080AAE5 /* Firebase Project.app */, + ); + name = Products; + sourceTree = ""; + }; + 2C0BBF3321BA80730080AAE5 /* Firebase Project */ = { + isa = PBXGroup; + children = ( + 2C0BBF4921BA80C20080AAE5 /* Firebase */, + 2C0BBF4821BA80B30080AAE5 /* View Controller */, + 2C0BBF4721BA80AB0080AAE5 /* View */, + 2C0BBF4621BA80A10080AAE5 /* Model */, + 2C0BBF3421BA80730080AAE5 /* AppDelegate.swift */, + 2C0BBF3B21BA80880080AAE5 /* Assets.xcassets */, + 2C0BBF3D21BA80880080AAE5 /* LaunchScreen.storyboard */, + 2C0BBF4021BA80880080AAE5 /* Info.plist */, + ); + path = "Firebase Project"; + sourceTree = ""; + }; + 2C0BBF4621BA80A10080AAE5 /* Model */ = { + isa = PBXGroup; + children = ( + 2C0BBF5821BA819F0080AAE5 /* Person.swift */, + 2C0BBF5A21BA81C00080AAE5 /* ModelUpdateClient.swift */, + 2C0BBF5C21BA81EB0080AAE5 /* Model.swift */, + ); + path = Model; + sourceTree = ""; + }; + 2C0BBF4721BA80AB0080AAE5 /* View */ = { + isa = PBXGroup; + children = ( + 2C0BBF5021BA81540080AAE5 /* EntryCell.swift */, + 2C0BBF4E21BA81540080AAE5 /* EntryCell.xib */, + 2C0BBF5121BA81540080AAE5 /* Main.storyboard */, + 2C0BBF4F21BA81540080AAE5 /* PersonCell.swift */, + 2C0BBF5221BA81540080AAE5 /* PersonCell.xib */, + ); + path = View; + sourceTree = ""; + }; + 2C0BBF4821BA80B30080AAE5 /* View Controller */ = { + isa = PBXGroup; + children = ( + 2C0BBF6021BA82870080AAE5 /* TableViewController.swift */, + 2C0BBF5E21BA82400080AAE5 /* DetailViewController.swift */, + ); + path = "View Controller"; + sourceTree = ""; + }; + 2C0BBF4921BA80C20080AAE5 /* Firebase */ = { + isa = PBXGroup; + children = ( + 2C0BBF4A21BA80D90080AAE5 /* Firebase.swift */, + 2C0BBF4C21BA81160080AAE5 /* FirebaseItem.swift */, + ); + path = Firebase; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 2C0BBF3021BA80730080AAE5 /* Firebase Project */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2C0BBF4321BA80880080AAE5 /* Build configuration list for PBXNativeTarget "Firebase Project" */; + buildPhases = ( + 2C0BBF2D21BA80730080AAE5 /* Sources */, + 2C0BBF2E21BA80730080AAE5 /* Frameworks */, + 2C0BBF2F21BA80730080AAE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Firebase Project"; + productName = "Firebase Project"; + productReference = 2C0BBF3121BA80730080AAE5 /* Firebase Project.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 2C0BBF2921BA80730080AAE5 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1010; + LastUpgradeCheck = 1010; + ORGANIZATIONNAME = "Ivan Caldwell"; + TargetAttributes = { + 2C0BBF3021BA80730080AAE5 = { + CreatedOnToolsVersion = 10.1; + }; + }; + }; + buildConfigurationList = 2C0BBF2C21BA80730080AAE5 /* Build configuration list for PBXProject "Firebase Project" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 2C0BBF2821BA80730080AAE5; + productRefGroup = 2C0BBF3221BA80730080AAE5 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 2C0BBF3021BA80730080AAE5 /* Firebase Project */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 2C0BBF2F21BA80730080AAE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2C0BBF5321BA81540080AAE5 /* EntryCell.xib in Resources */, + 2C0BBF5621BA81540080AAE5 /* Main.storyboard in Resources */, + 2C0BBF5721BA81540080AAE5 /* PersonCell.xib in Resources */, + 2C0BBF3F21BA80880080AAE5 /* LaunchScreen.storyboard in Resources */, + 2C0BBF3C21BA80880080AAE5 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 2C0BBF2D21BA80730080AAE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2C0BBF5D21BA81EB0080AAE5 /* Model.swift in Sources */, + 2C0BBF4B21BA80D90080AAE5 /* Firebase.swift in Sources */, + 2C0BBF5421BA81540080AAE5 /* PersonCell.swift in Sources */, + 2C0BBF4D21BA81160080AAE5 /* FirebaseItem.swift in Sources */, + 2C0BBF5921BA819F0080AAE5 /* Person.swift in Sources */, + 2C0BBF6121BA82870080AAE5 /* TableViewController.swift in Sources */, + 2C0BBF5B21BA81C00080AAE5 /* ModelUpdateClient.swift in Sources */, + 2C0BBF5F21BA82400080AAE5 /* DetailViewController.swift in Sources */, + 2C0BBF5521BA81540080AAE5 /* EntryCell.swift in Sources */, + 2C0BBF3521BA80730080AAE5 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 2C0BBF3D21BA80880080AAE5 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 2C0BBF3E21BA80880080AAE5 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 2C0BBF4121BA80880080AAE5 /* 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++14"; + 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_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; + CODE_SIGN_IDENTITY = "iPhone Developer"; + 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 = 12.1; + 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; + }; + 2C0BBF4221BA80880080AAE5 /* 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++14"; + 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_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; + CODE_SIGN_IDENTITY = "iPhone Developer"; + 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 = 12.1; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 2C0BBF4421BA80880080AAE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = "Firebase Project/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "GrumpyCaldwell.Firebase-Project"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.2; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 2C0BBF4521BA80880080AAE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = "Firebase Project/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "GrumpyCaldwell.Firebase-Project"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 4.2; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 2C0BBF2C21BA80730080AAE5 /* Build configuration list for PBXProject "Firebase Project" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2C0BBF4121BA80880080AAE5 /* Debug */, + 2C0BBF4221BA80880080AAE5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2C0BBF4321BA80880080AAE5 /* Build configuration list for PBXNativeTarget "Firebase Project" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2C0BBF4421BA80880080AAE5 /* Debug */, + 2C0BBF4521BA80880080AAE5 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 2C0BBF2921BA80730080AAE5 /* Project object */; +} diff --git a/Firebase Project/Firebase Project.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Firebase Project/Firebase Project.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Firebase Project/Firebase Project.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Firebase Project/Firebase Project/AppDelegate.swift b/Firebase Project/Firebase Project/AppDelegate.swift new file mode 100644 index 0000000..35c021b --- /dev/null +++ b/Firebase Project/Firebase Project/AppDelegate.swift @@ -0,0 +1,46 @@ +// +// AppDelegate.swift +// Firebase Project +// +// Created by Ivan Caldwell on 12/7/18. +// Copyright © 2018 Ivan Caldwell. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + func applicationWillResignActive(_ application: UIApplication) { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. + } + + func applicationDidEnterBackground(_ application: UIApplication) { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(_ application: UIApplication) { + // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. + } + + func applicationDidBecomeActive(_ application: UIApplication) { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + } + + func applicationWillTerminate(_ application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + +} + diff --git a/Firebase Project/Firebase Project/Assets.xcassets/AppIcon.appiconset/Contents.json b/Firebase Project/Firebase Project/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d8db8d6 --- /dev/null +++ b/Firebase Project/Firebase Project/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Firebase Project/Firebase Project/Assets.xcassets/Contents.json b/Firebase Project/Firebase Project/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Firebase Project/Firebase Project/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Firebase Project/Firebase Project/Base.lproj/LaunchScreen.storyboard b/Firebase Project/Firebase Project/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..bfa3612 --- /dev/null +++ b/Firebase Project/Firebase Project/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Firebase Project/Firebase Project/Firebase/Firebase.swift b/Firebase Project/Firebase Project/Firebase/Firebase.swift new file mode 100644 index 0000000..32aa969 --- /dev/null +++ b/Firebase Project/Firebase Project/Firebase/Firebase.swift @@ -0,0 +1,143 @@ +import Foundation +/* + READ <- start the application + POST <- create, creating a new record, Firebase will return a new record identifier + PUT <- update a specific record + DELETE <- delete a specific record + */ + + +class Firebase { + static var baseURL: URL! { return URL(string: "https://student-firebase-ae727.firebaseio.com/") } + + static func requestURL(_ method: String, for recordIdentifier: String = "unknownid") -> URL { + switch method { + case "POST": + // You post to the main DB. It will return a new record identifier + return baseURL.appendingPathExtension("json") + case "DELETE", "PUT", "GET": + // These all work on individual records, and you need to use the + // record identifier in your URL with one exception, which is when + // all the records at once, in which case, you do not need the record + // identifier. + return baseURL + .appendingPathComponent(recordIdentifier) + .appendingPathExtension("json") + default: + fatalError("Unknown request method: \(method)") + } + } + + + // Handle a single request: meant for DELETE, PUT, POST. + // If you were doing a GET, you'd want to pass back a record and not a success token + static func processRequest( + method: String, + for item: Item, + with completion: @escaping (_ success: Bool) -> Void = { _ in } + ) { + + // Fetch appropriate request URL customized to method + var request = URLRequest(url: requestURL(method, for: item.recordIdentifier)) + request.httpMethod = method + + // Encode this record + do { + request.httpBody = try JSONEncoder().encode(item) + } catch { + NSLog("Unable to encode \(item): \(error)") + completion(false) + return + } + + // Create data task to perform request + let dataTask = URLSession.shared.dataTask(with: request) { data, _ , error in + + // Fail on error + if let error = error { + NSLog("Server \(method) error: \(error)") + completion(false) + return + } + + // Handle PUT, GET, DELETE and leave + guard method == "POST" else { + completion(true) + return + } + + // Process POST requests + // Fetch identifier from POST + guard let data = data else { + NSLog("Invalid server response data") + completion(false) + return + } + + do { + + // POST request returns `["name": recordIdentifier]`. Store the + // record identifier + let nameDict = try JSONDecoder().decode([String: String].self, from: data) + guard let name = nameDict["name"] else { + completion(false) + return + } + + // Update record and store that name. POST is now successful + // and includes the recordIdentifier as part of the item record. + item.recordIdentifier = name + processRequest(method: "PUT", for: item) + completion(true) + + } catch { + + NSLog("Error decoding JSON response: \(error)") + completion(false) + return + } + } + dataTask.resume() + } + + static func delete(item: Item, completion: @escaping (_ success: Bool) -> Void = { _ in }) { + processRequest(method: "DELETE", for: item, with: completion) + } + + static func save(item: Item, completion: @escaping (_ success: Bool) -> Void = { _ in }) { + switch item.recordIdentifier.isEmpty { + case true: // POST, new record + processRequest(method: "POST", for: item, with: completion) + case false: // PUT, existing record + processRequest(method: "PUT", for: item, with: completion) + } + } + + // Fetch all records and pass them to sender via completion handler + static func fetchRecords(completion: @escaping ([Item]?) -> Void) { + let requestURL = baseURL.appendingPathExtension("json") + let dataTask = URLSession.shared.dataTask(with: requestURL) { data, _, error in + + guard error == nil, let data = data else { + // Guaranteed to work + if let error = error { + NSLog("Error fetching entries: \(error)") + } + completion(nil) + return + } + + do { + let recordDict = try JSONDecoder().decode([String: Item].self, from:data) + for (key, value) in recordDict { value.recordIdentifier = key } // pure paranoia + let records = recordDict.map({ $0.value }) // This converts the [[id: item]] array of dictionary entries into an array of items + completion(records) + } catch { + NSLog("Error decoding received data: \(error)") + completion([]) + } + } + dataTask.resume() + } +} + diff --git a/Firebase Project/Firebase Project/Firebase/FirebaseItem.swift b/Firebase Project/Firebase Project/Firebase/FirebaseItem.swift new file mode 100644 index 0000000..5c9beb4 --- /dev/null +++ b/Firebase Project/Firebase Project/Firebase/FirebaseItem.swift @@ -0,0 +1,5 @@ +import Foundation + +protocol FirebaseItem: class { + var recordIdentifier: String {get set} +} diff --git a/Firebase Project/Firebase Project/Info.plist b/Firebase Project/Firebase Project/Info.plist new file mode 100644 index 0000000..16be3b6 --- /dev/null +++ b/Firebase Project/Firebase Project/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Firebase Project/Firebase Project/Model/Model.swift b/Firebase Project/Firebase Project/Model/Model.swift new file mode 100644 index 0000000..76f99ee --- /dev/null +++ b/Firebase Project/Firebase Project/Model/Model.swift @@ -0,0 +1,43 @@ +import Foundation + +class Model { + static let shared = Model() + private init() {} + var delegate: ModelUpdateClient? + + var persons: [Person] = [] + + // MARK: Core Data Source Methods + func count() -> Int { + return persons.count + } + + func person(at index: Int) -> Person { + return persons[index] + } + + // MARK: Core Database Management Methods + func add(person: Person, completion: @escaping () -> Void) { + persons.append(person) + delegate?.modelDidUpdate() + Firebase.save(item: person) { success in + guard success else { return } + DispatchQueue.main.async { + completion() + } + } + } + + func deletePerson(at indexPath: IndexPath, completion: @escaping () -> Void) { + let person = persons[indexPath.row] + persons.remove(at: indexPath.row) + Firebase.delete(item: person) { success in + guard success else { return } + DispatchQueue.main.async { completion() } + } + } +} + + + + diff --git a/Firebase Project/Firebase Project/Model/ModelUpdateClient.swift b/Firebase Project/Firebase Project/Model/ModelUpdateClient.swift new file mode 100644 index 0000000..502713b --- /dev/null +++ b/Firebase Project/Firebase Project/Model/ModelUpdateClient.swift @@ -0,0 +1,13 @@ +// +// ModelUpdateClient.swift +// Firebase Project +// +// Created by Ivan Caldwell on 12/7/18. +// Copyright © 2018 Ivan Caldwell. All rights reserved. +// + +import Foundation + +protocol ModelUpdateClient { + func modelDidUpdate() +} diff --git a/Firebase Project/Firebase Project/Model/Person.swift b/Firebase Project/Firebase Project/Model/Person.swift new file mode 100644 index 0000000..1971782 --- /dev/null +++ b/Firebase Project/Firebase Project/Model/Person.swift @@ -0,0 +1,20 @@ +// +// Person.swift +// Firebase Project +// +// Created by Ivan Caldwell on 12/7/18. +// Copyright © 2018 Ivan Caldwell. All rights reserved. +// + +import Foundation + +class Person: Codable, FirebaseItem { + var name: String + var cohort: String + var recordIdentifier = "" + + init(name: String, cohort: String) { + (self.name, self.cohort) = (name, cohort) + } +} + diff --git a/Firebase Project/Firebase Project/View Controller/DetailViewController.swift b/Firebase Project/Firebase Project/View Controller/DetailViewController.swift new file mode 100644 index 0000000..1c84cc6 --- /dev/null +++ b/Firebase Project/Firebase Project/View Controller/DetailViewController.swift @@ -0,0 +1,27 @@ +import Foundation +import UIKit + +class DetailViewController: UIViewController { + var person: Person? + + @IBOutlet weak var nameField: UITextField! + @IBOutlet weak var cohortField: UITextField! + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + guard let person = person else { return } + nameField.text = person.name + cohortField.text = person.cohort + } + + @IBAction func save(_ sender: Any) { + guard let person = person else { return } + guard let name = nameField.text, !name.isEmpty else { return } + person.name = name + person.cohort = cohortField.text ?? "" + navigationController?.popViewController(animated: true) + Firebase.save(item: person) { (success) in + guard success else {return} + } + } +} diff --git a/Firebase Project/Firebase Project/View Controller/TableViewController.swift b/Firebase Project/Firebase Project/View Controller/TableViewController.swift new file mode 100644 index 0000000..661ad12 --- /dev/null +++ b/Firebase Project/Firebase Project/View Controller/TableViewController.swift @@ -0,0 +1,92 @@ +import Foundation +import UIKit + +class TableViewController: UITableViewController, ModelUpdateClient { + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + navigationItem.rightBarButtonItem?.isEnabled = false + let activity = UIActivityIndicatorView() + activity.style = .gray + activity.startAnimating() + navigationItem.titleView = activity + + // Fetch records from Firebase and then reload the table view + // Note: this may be significantly delayed. + Firebase.fetchRecords { persons in + if let persons = persons { + Model.shared.persons = persons + + // Comment this out to show what it looks like while waiting + DispatchQueue.main.async { + self.tableView.reloadData() + self.navigationItem.rightBarButtonItem?.isEnabled = true + self.navigationItem.titleView = nil + self.title = "Person" + } + } + } + } + + + override func numberOfSections(in tableView: UITableView) -> Int { + return 2 + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + switch section { + case 0: + return 1 + case 1: + return Model.shared.count() + default: + fatalError("Illegal section") + } + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + if indexPath.section == 0 { + // handle the single entry cell return it + guard let cell = tableView.dequeueReusableCell(withIdentifier: EntryCell.reuseIdentifier, for: indexPath) as? EntryCell + else { fatalError("Unable to dequeue entry cell") } + cell.nameField.text = "" + cell.cohortField.text = "" + return cell + } + else { + // do anything related to person cell + guard let cell = tableView.dequeueReusableCell(withIdentifier: PersonCell.reuseIdentifier, for: indexPath) as? PersonCell + else { fatalError("Unable to dequeue person cell") } + + let person = Model.shared.person(at: indexPath.row) + cell.nameLabel.text = person.name + cell.cohortLabel.text = person.cohort + return cell + } + } + + + override func viewDidLoad() { + super.viewDidLoad() + Model.shared.delegate = self + } + + func modelDidUpdate() { + tableView.reloadData() + } + + override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { + guard editingStyle == .delete else { return } + Model.shared.deletePerson(at: indexPath) { + self.tableView.reloadData() + } + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + guard let indexPath = tableView.indexPathForSelectedRow + else { return } + guard let destination = segue.destination as? DetailViewController + else { return } + destination.person = Model.shared.person(at: indexPath.row) + } +} diff --git a/Firebase Project/Firebase Project/View/EntryCell.swift b/Firebase Project/Firebase Project/View/EntryCell.swift new file mode 100644 index 0000000..332a3de --- /dev/null +++ b/Firebase Project/Firebase Project/View/EntryCell.swift @@ -0,0 +1,20 @@ +import UIKit + +class EntryCell: UITableViewCell { + static let reuseIdentifier = "entry cell" + + @IBOutlet weak var nameField: UITextField! + + @IBOutlet weak var cohortField: UITextField! + + @IBAction func add(_ sender: Any) { + guard let name = nameField.text, !name.isEmpty else { return } + let cohort = cohortField.text ?? "" + let person = Person(name: name, cohort: cohort) + Model.shared.add(person: person){ + return + } + nameField.text = nil + cohortField.text = nil + } +} diff --git a/Firebase Project/Firebase Project/View/EntryCell.xib b/Firebase Project/Firebase Project/View/EntryCell.xib new file mode 100644 index 0000000..52c04e8 --- /dev/null +++ b/Firebase Project/Firebase Project/View/EntryCell.xib @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Firebase Project/Firebase Project/View/Main.storyboard b/Firebase Project/Firebase Project/View/Main.storyboard new file mode 100644 index 0000000..8355f36 --- /dev/null +++ b/Firebase Project/Firebase Project/View/Main.storyboard @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Firebase Project/Firebase Project/View/PersonCell.swift b/Firebase Project/Firebase Project/View/PersonCell.swift new file mode 100644 index 0000000..57762b0 --- /dev/null +++ b/Firebase Project/Firebase Project/View/PersonCell.swift @@ -0,0 +1,8 @@ +import UIKit + +class PersonCell: UITableViewCell { + static let reuseIdentifier = "person cell" + + @IBOutlet weak var nameLabel: UILabel! + @IBOutlet weak var cohortLabel: UILabel! +} diff --git a/Firebase Project/Firebase Project/View/PersonCell.xib b/Firebase Project/Firebase Project/View/PersonCell.xib new file mode 100644 index 0000000..c536c7c --- /dev/null +++ b/Firebase Project/Firebase Project/View/PersonCell.xib @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Questions.docx b/Questions.docx new file mode 100644 index 0000000..2a7de4e Binary files /dev/null and b/Questions.docx differ