From fba554c82c8f904b8cd62ffcf196e69acd7ffc3a Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Mon, 16 Jun 2014 10:05:29 -0500 Subject: [PATCH 1/8] Initial Commit --- SwiftTutorial.xcodeproj/project.pbxproj | 412 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + SwiftTutorial/AppDelegate.swift | 46 ++ SwiftTutorial/Base.lproj/Main.storyboard | 25 ++ .../AppIcon.appiconset/Contents.json | 23 + .../LaunchImage.launchimage/Contents.json | 23 + SwiftTutorial/Info.plist | 32 ++ SwiftTutorial/ViewController.swift | 25 ++ SwiftTutorialTests/Info.plist | 24 + SwiftTutorialTests/SwiftTutorialTests.swift | 35 ++ 10 files changed, 652 insertions(+) create mode 100644 SwiftTutorial.xcodeproj/project.pbxproj create mode 100644 SwiftTutorial.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 SwiftTutorial/AppDelegate.swift create mode 100644 SwiftTutorial/Base.lproj/Main.storyboard create mode 100644 SwiftTutorial/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 SwiftTutorial/Images.xcassets/LaunchImage.launchimage/Contents.json create mode 100644 SwiftTutorial/Info.plist create mode 100644 SwiftTutorial/ViewController.swift create mode 100644 SwiftTutorialTests/Info.plist create mode 100644 SwiftTutorialTests/SwiftTutorialTests.swift diff --git a/SwiftTutorial.xcodeproj/project.pbxproj b/SwiftTutorial.xcodeproj/project.pbxproj new file mode 100644 index 0000000..b8f94c9 --- /dev/null +++ b/SwiftTutorial.xcodeproj/project.pbxproj @@ -0,0 +1,412 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0256BB50194F3F38003E2942 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0256BB4F194F3F38003E2942 /* AppDelegate.swift */; }; + 0256BB52194F3F38003E2942 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0256BB51194F3F38003E2942 /* ViewController.swift */; }; + 0256BB55194F3F38003E2942 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0256BB53194F3F38003E2942 /* Main.storyboard */; }; + 0256BB57194F3F38003E2942 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0256BB56194F3F38003E2942 /* Images.xcassets */; }; + 0256BB63194F3F38003E2942 /* SwiftTutorialTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0256BB62194F3F38003E2942 /* SwiftTutorialTests.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 0256BB5D194F3F38003E2942 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0256BB42194F3F38003E2942 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0256BB49194F3F38003E2942; + remoteInfo = SwiftTutorial; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 0256BB4A194F3F38003E2942 /* SwiftTutorial.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftTutorial.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 0256BB4E194F3F38003E2942 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 0256BB4F194F3F38003E2942 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 0256BB51194F3F38003E2942 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 0256BB54194F3F38003E2942 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 0256BB56194F3F38003E2942 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 0256BB5C194F3F38003E2942 /* SwiftTutorialTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftTutorialTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 0256BB61194F3F38003E2942 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 0256BB62194F3F38003E2942 /* SwiftTutorialTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftTutorialTests.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 0256BB47194F3F38003E2942 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0256BB59194F3F38003E2942 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0256BB41194F3F38003E2942 = { + isa = PBXGroup; + children = ( + 0256BB4C194F3F38003E2942 /* SwiftTutorial */, + 0256BB5F194F3F38003E2942 /* SwiftTutorialTests */, + 0256BB4B194F3F38003E2942 /* Products */, + ); + sourceTree = ""; + }; + 0256BB4B194F3F38003E2942 /* Products */ = { + isa = PBXGroup; + children = ( + 0256BB4A194F3F38003E2942 /* SwiftTutorial.app */, + 0256BB5C194F3F38003E2942 /* SwiftTutorialTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 0256BB4C194F3F38003E2942 /* SwiftTutorial */ = { + isa = PBXGroup; + children = ( + 0256BB4F194F3F38003E2942 /* AppDelegate.swift */, + 0256BB51194F3F38003E2942 /* ViewController.swift */, + 0256BB53194F3F38003E2942 /* Main.storyboard */, + 0256BB56194F3F38003E2942 /* Images.xcassets */, + 0256BB4D194F3F38003E2942 /* Supporting Files */, + ); + path = SwiftTutorial; + sourceTree = ""; + }; + 0256BB4D194F3F38003E2942 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 0256BB4E194F3F38003E2942 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 0256BB5F194F3F38003E2942 /* SwiftTutorialTests */ = { + isa = PBXGroup; + children = ( + 0256BB62194F3F38003E2942 /* SwiftTutorialTests.swift */, + 0256BB60194F3F38003E2942 /* Supporting Files */, + ); + path = SwiftTutorialTests; + sourceTree = ""; + }; + 0256BB60194F3F38003E2942 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 0256BB61194F3F38003E2942 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 0256BB49194F3F38003E2942 /* SwiftTutorial */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0256BB66194F3F38003E2942 /* Build configuration list for PBXNativeTarget "SwiftTutorial" */; + buildPhases = ( + 0256BB46194F3F38003E2942 /* Sources */, + 0256BB47194F3F38003E2942 /* Frameworks */, + 0256BB48194F3F38003E2942 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SwiftTutorial; + productName = SwiftTutorial; + productReference = 0256BB4A194F3F38003E2942 /* SwiftTutorial.app */; + productType = "com.apple.product-type.application"; + }; + 0256BB5B194F3F38003E2942 /* SwiftTutorialTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0256BB69194F3F38003E2942 /* Build configuration list for PBXNativeTarget "SwiftTutorialTests" */; + buildPhases = ( + 0256BB58194F3F38003E2942 /* Sources */, + 0256BB59194F3F38003E2942 /* Frameworks */, + 0256BB5A194F3F38003E2942 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 0256BB5E194F3F38003E2942 /* PBXTargetDependency */, + ); + name = SwiftTutorialTests; + productName = SwiftTutorialTests; + productReference = 0256BB5C194F3F38003E2942 /* SwiftTutorialTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0256BB42194F3F38003E2942 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0600; + ORGANIZATIONNAME = "JQ Software LLC"; + TargetAttributes = { + 0256BB49194F3F38003E2942 = { + CreatedOnToolsVersion = 6.0; + }; + 0256BB5B194F3F38003E2942 = { + CreatedOnToolsVersion = 6.0; + TestTargetID = 0256BB49194F3F38003E2942; + }; + }; + }; + buildConfigurationList = 0256BB45194F3F38003E2942 /* Build configuration list for PBXProject "SwiftTutorial" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 0256BB41194F3F38003E2942; + productRefGroup = 0256BB4B194F3F38003E2942 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 0256BB49194F3F38003E2942 /* SwiftTutorial */, + 0256BB5B194F3F38003E2942 /* SwiftTutorialTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 0256BB48194F3F38003E2942 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0256BB55194F3F38003E2942 /* Main.storyboard in Resources */, + 0256BB57194F3F38003E2942 /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0256BB5A194F3F38003E2942 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 0256BB46194F3F38003E2942 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0256BB52194F3F38003E2942 /* ViewController.swift in Sources */, + 0256BB50194F3F38003E2942 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0256BB58194F3F38003E2942 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0256BB63194F3F38003E2942 /* SwiftTutorialTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 0256BB5E194F3F38003E2942 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 0256BB49194F3F38003E2942 /* SwiftTutorial */; + targetProxy = 0256BB5D194F3F38003E2942 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 0256BB53194F3F38003E2942 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 0256BB54194F3F38003E2942 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 0256BB64194F3F38003E2942 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + 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 = 8.0; + METAL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 0256BB65194F3F38003E2942 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = YES; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + 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 = 8.0; + METAL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 0256BB67194F3F38003E2942 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + INFOPLIST_FILE = SwiftTutorial/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 0256BB68194F3F38003E2942 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + INFOPLIST_FILE = SwiftTutorial/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 0256BB6A194F3F38003E2942 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/SwiftTutorial.app/SwiftTutorial"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = SwiftTutorialTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + METAL_ENABLE_DEBUG_INFO = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUNDLE_LOADER)"; + }; + name = Debug; + }; + 0256BB6B194F3F38003E2942 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/SwiftTutorial.app/SwiftTutorial"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + INFOPLIST_FILE = SwiftTutorialTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + METAL_ENABLE_DEBUG_INFO = NO; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUNDLE_LOADER)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 0256BB45194F3F38003E2942 /* Build configuration list for PBXProject "SwiftTutorial" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0256BB64194F3F38003E2942 /* Debug */, + 0256BB65194F3F38003E2942 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0256BB66194F3F38003E2942 /* Build configuration list for PBXNativeTarget "SwiftTutorial" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0256BB67194F3F38003E2942 /* Debug */, + 0256BB68194F3F38003E2942 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; + 0256BB69194F3F38003E2942 /* Build configuration list for PBXNativeTarget "SwiftTutorialTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0256BB6A194F3F38003E2942 /* Debug */, + 0256BB6B194F3F38003E2942 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0256BB42194F3F38003E2942 /* Project object */; +} diff --git a/SwiftTutorial.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/SwiftTutorial.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..fbcbb6e --- /dev/null +++ b/SwiftTutorial.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/SwiftTutorial/AppDelegate.swift b/SwiftTutorial/AppDelegate.swift new file mode 100644 index 0000000..2b6d79f --- /dev/null +++ b/SwiftTutorial/AppDelegate.swift @@ -0,0 +1,46 @@ +// +// AppDelegate.swift +// SwiftTutorial +// +// Created by Jameson Quave on 6/16/14. +// Copyright (c) 2014 JQ Software LLC. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + + func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> 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 throttle down OpenGL ES frame rates. 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 inactive 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/SwiftTutorial/Base.lproj/Main.storyboard b/SwiftTutorial/Base.lproj/Main.storyboard new file mode 100644 index 0000000..9d65d6f --- /dev/null +++ b/SwiftTutorial/Base.lproj/Main.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SwiftTutorial/Images.xcassets/AppIcon.appiconset/Contents.json b/SwiftTutorial/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..a396706 --- /dev/null +++ b/SwiftTutorial/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/SwiftTutorial/Images.xcassets/LaunchImage.launchimage/Contents.json b/SwiftTutorial/Images.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 0000000..c79ebd3 --- /dev/null +++ b/SwiftTutorial/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "orientation" : "portrait", + "idiom" : "iphone", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "portrait", + "idiom" : "iphone", + "subtype" : "retina4", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/SwiftTutorial/Info.plist b/SwiftTutorial/Info.plist new file mode 100644 index 0000000..310bb7e --- /dev/null +++ b/SwiftTutorial/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.jqsoftware.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + + diff --git a/SwiftTutorial/ViewController.swift b/SwiftTutorial/ViewController.swift new file mode 100644 index 0000000..54e8e8b --- /dev/null +++ b/SwiftTutorial/ViewController.swift @@ -0,0 +1,25 @@ +// +// ViewController.swift +// SwiftTutorial +// +// Created by Jameson Quave on 6/16/14. +// Copyright (c) 2014 JQ Software LLC. All rights reserved. +// + +import UIKit + +class ViewController: UIViewController { + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view, typically from a nib. + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + +} + diff --git a/SwiftTutorialTests/Info.plist b/SwiftTutorialTests/Info.plist new file mode 100644 index 0000000..a555585 --- /dev/null +++ b/SwiftTutorialTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + com.jqsoftware.${PRODUCT_NAME:rfc1034identifier} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/SwiftTutorialTests/SwiftTutorialTests.swift b/SwiftTutorialTests/SwiftTutorialTests.swift new file mode 100644 index 0000000..4633736 --- /dev/null +++ b/SwiftTutorialTests/SwiftTutorialTests.swift @@ -0,0 +1,35 @@ +// +// SwiftTutorialTests.swift +// SwiftTutorialTests +// +// Created by Jameson Quave on 6/16/14. +// Copyright (c) 2014 JQ Software LLC. All rights reserved. +// + +import XCTest + +class SwiftTutorialTests: XCTestCase { + + override func setUp() { + super.setUp() + // Put setup code here. This method is called before the invocation of each test method in the class. + } + + override func tearDown() { + // Put teardown code here. This method is called after the invocation of each test method in the class. + super.tearDown() + } + + func testExample() { + // This is an example of a functional test case. + XCTAssert(true, "Pass") + } + + func testPerformanceExample() { + // This is an example of a performance test case. + self.measureBlock() { + // Put the code you want to measure the time of here. + } + } + +} From 7c39481fa316cf058a612cd03268b4f183d6397f Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Mon, 16 Jun 2014 10:08:02 -0500 Subject: [PATCH 2/8] Part 1 --- SwiftTutorial/Base.lproj/Main.storyboard | 31 +++++++++++++++++++++--- SwiftTutorial/ViewController.swift | 14 ++++++++++- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/SwiftTutorial/Base.lproj/Main.storyboard b/SwiftTutorial/Base.lproj/Main.storyboard index 9d65d6f..cf0758e 100644 --- a/SwiftTutorial/Base.lproj/Main.storyboard +++ b/SwiftTutorial/Base.lproj/Main.storyboard @@ -1,13 +1,13 @@ - + - + - + @@ -15,11 +15,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SwiftTutorial/ViewController.swift b/SwiftTutorial/ViewController.swift index 54e8e8b..007ebf7 100644 --- a/SwiftTutorial/ViewController.swift +++ b/SwiftTutorial/ViewController.swift @@ -8,7 +8,7 @@ import UIKit -class ViewController: UIViewController { +class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { override func viewDidLoad() { super.viewDidLoad() @@ -19,6 +19,18 @@ class ViewController: UIViewController { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } + + func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int { + return 10 + } + func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { + let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell") + + cell.text = "Row #\(indexPath.row)" + cell.detailTextLabel.text = "Subtitle #\(indexPath.row)" + + return cell + } } From b0e6c62aef7834e77db753b8fbad4a3c04df55c4 Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Mon, 16 Jun 2014 10:24:19 -0500 Subject: [PATCH 3/8] Part 3 --- SwiftTutorial.xcodeproj/project.pbxproj | 12 ++-- SwiftTutorial/APIController.swift | 47 ++++++++++++++ SwiftTutorial/Base.lproj/Main.storyboard | 7 +- .../SearchResultsViewController.swift | 65 +++++++++++++++++++ SwiftTutorial/ViewController.swift | 37 ----------- 5 files changed, 125 insertions(+), 43 deletions(-) create mode 100644 SwiftTutorial/APIController.swift create mode 100644 SwiftTutorial/SearchResultsViewController.swift delete mode 100644 SwiftTutorial/ViewController.swift diff --git a/SwiftTutorial.xcodeproj/project.pbxproj b/SwiftTutorial.xcodeproj/project.pbxproj index b8f94c9..1ad9ac7 100644 --- a/SwiftTutorial.xcodeproj/project.pbxproj +++ b/SwiftTutorial.xcodeproj/project.pbxproj @@ -8,10 +8,11 @@ /* Begin PBXBuildFile section */ 0256BB50194F3F38003E2942 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0256BB4F194F3F38003E2942 /* AppDelegate.swift */; }; - 0256BB52194F3F38003E2942 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0256BB51194F3F38003E2942 /* ViewController.swift */; }; + 0256BB52194F3F38003E2942 /* SearchResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0256BB51194F3F38003E2942 /* SearchResultsViewController.swift */; }; 0256BB55194F3F38003E2942 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0256BB53194F3F38003E2942 /* Main.storyboard */; }; 0256BB57194F3F38003E2942 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0256BB56194F3F38003E2942 /* Images.xcassets */; }; 0256BB63194F3F38003E2942 /* SwiftTutorialTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0256BB62194F3F38003E2942 /* SwiftTutorialTests.swift */; }; + 0256BB6D194F41F5003E2942 /* APIController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0256BB6C194F41F5003E2942 /* APIController.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -28,12 +29,13 @@ 0256BB4A194F3F38003E2942 /* SwiftTutorial.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftTutorial.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0256BB4E194F3F38003E2942 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 0256BB4F194F3F38003E2942 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 0256BB51194F3F38003E2942 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 0256BB51194F3F38003E2942 /* SearchResultsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultsViewController.swift; sourceTree = ""; }; 0256BB54194F3F38003E2942 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 0256BB56194F3F38003E2942 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 0256BB5C194F3F38003E2942 /* SwiftTutorialTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftTutorialTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 0256BB61194F3F38003E2942 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 0256BB62194F3F38003E2942 /* SwiftTutorialTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftTutorialTests.swift; sourceTree = ""; }; + 0256BB6C194F41F5003E2942 /* APIController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIController.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -76,10 +78,11 @@ isa = PBXGroup; children = ( 0256BB4F194F3F38003E2942 /* AppDelegate.swift */, - 0256BB51194F3F38003E2942 /* ViewController.swift */, + 0256BB51194F3F38003E2942 /* SearchResultsViewController.swift */, 0256BB53194F3F38003E2942 /* Main.storyboard */, 0256BB56194F3F38003E2942 /* Images.xcassets */, 0256BB4D194F3F38003E2942 /* Supporting Files */, + 0256BB6C194F41F5003E2942 /* APIController.swift */, ); path = SwiftTutorial; sourceTree = ""; @@ -208,8 +211,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 0256BB52194F3F38003E2942 /* ViewController.swift in Sources */, + 0256BB52194F3F38003E2942 /* SearchResultsViewController.swift in Sources */, 0256BB50194F3F38003E2942 /* AppDelegate.swift in Sources */, + 0256BB6D194F41F5003E2942 /* APIController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/SwiftTutorial/APIController.swift b/SwiftTutorial/APIController.swift new file mode 100644 index 0000000..5b0b348 --- /dev/null +++ b/SwiftTutorial/APIController.swift @@ -0,0 +1,47 @@ +// +// APIController.swift +// SwiftTutorial +// +// Created by Jameson Quave on 6/16/14. +// Copyright (c) 2014 JQ Software LLC. All rights reserved. +// + +import UIKit + +protocol APIControllerProtocol { + func didReceiveAPIResults(results: NSDictionary) +} + +class APIController: NSObject { + var delegate: APIControllerProtocol? + + func searchItunesFor(searchTerm: String) { + + // The iTunes API wants multiple terms separated by + symbols, so replace spaces with + signs + var itunesSearchTerm = searchTerm.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil) + + // Now escape anything else that isn't URL-friendly + var escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) + var urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=software" + var url: NSURL = NSURL(string: urlPath) + var session = NSURLSession.sharedSession() + var task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in + println("Task completed") + if(error) { + // If there is an error in the web request, print it to the console + println(error.localizedDescription) + } + var err: NSError? + var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as NSDictionary + if(err?) { + // If there is an error parsing JSON, print it to the console + println("JSON Error \(err!.localizedDescription)") + } + var results: NSArray = jsonResult["results"] as NSArray + // Now send the JSON result to our delegate object + self.delegate?.didReceiveAPIResults(jsonResult) + }) + task.resume() + } + +} diff --git a/SwiftTutorial/Base.lproj/Main.storyboard b/SwiftTutorial/Base.lproj/Main.storyboard index cf0758e..b398504 100644 --- a/SwiftTutorial/Base.lproj/Main.storyboard +++ b/SwiftTutorial/Base.lproj/Main.storyboard @@ -4,10 +4,10 @@ - + - + @@ -41,6 +41,9 @@ + + + diff --git a/SwiftTutorial/SearchResultsViewController.swift b/SwiftTutorial/SearchResultsViewController.swift new file mode 100644 index 0000000..8a99d37 --- /dev/null +++ b/SwiftTutorial/SearchResultsViewController.swift @@ -0,0 +1,65 @@ +// +// ViewController.swift +// SwiftTutorial +// +// Created by Jameson Quave on 6/16/14. +// Copyright (c) 2014 JQ Software LLC. All rights reserved. +// + +import UIKit + +class SearchResultsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, APIControllerProtocol { + + @IBOutlet var appsTableView : UITableView + var tableData: NSArray = [] + var api: APIController = APIController() + + override func viewDidLoad() { + super.viewDidLoad() + self.api.delegate = self + api.searchItunesFor("Angry Birds") + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int { + return tableData.count + } + + func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { + let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell") + + var rowData: NSDictionary = self.tableData[indexPath.row] as NSDictionary + + cell.text = rowData["trackName"] as String + + // Grab the artworkUrl60 key to get an image URL for the app's thumbnail + var urlString: NSString = rowData["artworkUrl60"] as NSString + var imgURL: NSURL = NSURL(string: urlString) + + // Download an NSData representation of the image at the URL + var imgData: NSData = NSData(contentsOfURL: imgURL) + cell.image = UIImage(data: imgData) + + // Get the formatted price string for display in the subtitle + var formattedPrice: NSString = rowData["formattedPrice"] as NSString + + cell.detailTextLabel.text = formattedPrice + + return cell + } + + func didReceiveAPIResults(results: NSDictionary) { + var resultsArr: NSArray = results["results"] as NSArray + dispatch_async(dispatch_get_main_queue(), { + self.tableData = resultsArr + self.appsTableView.reloadData() + }) + } + + +} + diff --git a/SwiftTutorial/ViewController.swift b/SwiftTutorial/ViewController.swift deleted file mode 100644 index 007ebf7..0000000 --- a/SwiftTutorial/ViewController.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// ViewController.swift -// SwiftTutorial -// -// Created by Jameson Quave on 6/16/14. -// Copyright (c) 2014 JQ Software LLC. All rights reserved. -// - -import UIKit - -class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { - - override func viewDidLoad() { - super.viewDidLoad() - // Do any additional setup after loading the view, typically from a nib. - } - - override func didReceiveMemoryWarning() { - super.didReceiveMemoryWarning() - // Dispose of any resources that can be recreated. - } - - func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int { - return 10 - } - func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { - let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell") - - cell.text = "Row #\(indexPath.row)" - cell.detailTextLabel.text = "Subtitle #\(indexPath.row)" - - return cell - } - - -} - From d5a1bace6d0a8e1804cbdebb0f872c2fcff5b25c Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Mon, 16 Jun 2014 10:27:45 -0500 Subject: [PATCH 4/8] Part 4 --- SwiftTutorial/Base.lproj/Main.storyboard | 28 +++++++++++++++++++ .../SearchResultsViewController.swift | 17 ++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/SwiftTutorial/Base.lproj/Main.storyboard b/SwiftTutorial/Base.lproj/Main.storyboard index b398504..2c44c4c 100644 --- a/SwiftTutorial/Base.lproj/Main.storyboard +++ b/SwiftTutorial/Base.lproj/Main.storyboard @@ -19,6 +19,34 @@ + + + + + + + + + + + + diff --git a/SwiftTutorial/SearchResultsViewController.swift b/SwiftTutorial/SearchResultsViewController.swift index 8a99d37..35bde27 100644 --- a/SwiftTutorial/SearchResultsViewController.swift +++ b/SwiftTutorial/SearchResultsViewController.swift @@ -30,7 +30,8 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa } func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { - let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell") + let kCellIdentifier: String = "SearchResultCell" + var cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(kCellIdentifier) as UITableViewCell var rowData: NSDictionary = self.tableData[indexPath.row] as NSDictionary @@ -52,6 +53,20 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa return cell } + func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) { + // Get the row data for the selected row + var rowData: NSDictionary = self.tableData[indexPath.row] as NSDictionary + + var name: String = rowData["trackName"] as String + var formattedPrice: String = rowData["formattedPrice"] as String + + var alert: UIAlertView = UIAlertView() + alert.title = name + alert.message = formattedPrice + alert.addButtonWithTitle("Ok") + alert.show() + } + func didReceiveAPIResults(results: NSDictionary) { var resultsArr: NSArray = results["results"] as NSArray dispatch_async(dispatch_get_main_queue(), { From 049c048d1ff2cdc793bae4545a576e8f8044cfd1 Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Mon, 16 Jun 2014 10:46:00 -0500 Subject: [PATCH 5/8] Part 5 --- SwiftTutorial.xcodeproj/project.pbxproj | 4 + .../xcschemes/SwiftTutorial.xcscheme | 96 ++++++++++++++++++ .../xcschemes/xcschememanagement.plist | 27 +++++ SwiftTutorial/Blank52.png | Bin 0 -> 975 bytes .../SearchResultsViewController.swift | 57 +++++++++-- 5 files changed, 175 insertions(+), 9 deletions(-) create mode 100644 SwiftTutorial.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/SwiftTutorial.xcscheme create mode 100644 SwiftTutorial.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 SwiftTutorial/Blank52.png diff --git a/SwiftTutorial.xcodeproj/project.pbxproj b/SwiftTutorial.xcodeproj/project.pbxproj index 1ad9ac7..737a4fd 100644 --- a/SwiftTutorial.xcodeproj/project.pbxproj +++ b/SwiftTutorial.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 0256BB57194F3F38003E2942 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0256BB56194F3F38003E2942 /* Images.xcassets */; }; 0256BB63194F3F38003E2942 /* SwiftTutorialTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0256BB62194F3F38003E2942 /* SwiftTutorialTests.swift */; }; 0256BB6D194F41F5003E2942 /* APIController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0256BB6C194F41F5003E2942 /* APIController.swift */; }; + 0256BB6F194F4852003E2942 /* Blank52.png in Resources */ = {isa = PBXBuildFile; fileRef = 0256BB6E194F4852003E2942 /* Blank52.png */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -36,6 +37,7 @@ 0256BB61194F3F38003E2942 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 0256BB62194F3F38003E2942 /* SwiftTutorialTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftTutorialTests.swift; sourceTree = ""; }; 0256BB6C194F41F5003E2942 /* APIController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIController.swift; sourceTree = ""; }; + 0256BB6E194F4852003E2942 /* Blank52.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Blank52.png; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -77,6 +79,7 @@ 0256BB4C194F3F38003E2942 /* SwiftTutorial */ = { isa = PBXGroup; children = ( + 0256BB6E194F4852003E2942 /* Blank52.png */, 0256BB4F194F3F38003E2942 /* AppDelegate.swift */, 0256BB51194F3F38003E2942 /* SearchResultsViewController.swift */, 0256BB53194F3F38003E2942 /* Main.storyboard */, @@ -192,6 +195,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 0256BB6F194F4852003E2942 /* Blank52.png in Resources */, 0256BB55194F3F38003E2942 /* Main.storyboard in Resources */, 0256BB57194F3F38003E2942 /* Images.xcassets in Resources */, ); diff --git a/SwiftTutorial.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/SwiftTutorial.xcscheme b/SwiftTutorial.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/SwiftTutorial.xcscheme new file mode 100644 index 0000000..0be1e07 --- /dev/null +++ b/SwiftTutorial.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/SwiftTutorial.xcscheme @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SwiftTutorial.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/xcschememanagement.plist b/SwiftTutorial.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..05e9e8c --- /dev/null +++ b/SwiftTutorial.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,27 @@ + + + + + SchemeUserState + + SwiftTutorial.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 0256BB49194F3F38003E2942 + + primary + + + 0256BB5B194F3F38003E2942 + + primary + + + + + diff --git a/SwiftTutorial/Blank52.png b/SwiftTutorial/Blank52.png new file mode 100644 index 0000000000000000000000000000000000000000..132e1868cd27834d7e89b56a79dde9c1c1aef57a GIT binary patch literal 975 zcmaJ=zi-n(6h0_IrBVk*I-T4OAQ3yZW0zPlRU9YO2uD#8K}H<=l31yI=6u0U79=DF zB>n(a{sFeC14zs)3I9__gg3?E0L z$1!3aC5#O~IkqV<4KWM@W4}=^YnoE3t9nhA>#C*dR<&x`ilu6IY+G4!ZR}4X z6w@U)IOl3>xx5*ogn70R37?{%L2v};mo~!nu_$Zx7TjQcEb3aW#DbA{Y5ytp(!~0Q zZ&!`W4y)EjG3$528asM({F*(As$*BX`L|!6 literal 0 HcmV?d00001 diff --git a/SwiftTutorial/SearchResultsViewController.swift b/SwiftTutorial/SearchResultsViewController.swift index 35bde27..82c496b 100644 --- a/SwiftTutorial/SearchResultsViewController.swift +++ b/SwiftTutorial/SearchResultsViewController.swift @@ -13,6 +13,8 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa @IBOutlet var appsTableView : UITableView var tableData: NSArray = [] var api: APIController = APIController() + var imageCache = NSMutableDictionary() + let kCellIdentifier = "SearchResultCell" override func viewDidLoad() { super.viewDidLoad() @@ -30,24 +32,61 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa } func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { - let kCellIdentifier: String = "SearchResultCell" + var cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(kCellIdentifier) as UITableViewCell + if cell == nil { + cell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: kCellIdentifier) + } var rowData: NSDictionary = self.tableData[indexPath.row] as NSDictionary - cell.text = rowData["trackName"] as String - - // Grab the artworkUrl60 key to get an image URL for the app's thumbnail - var urlString: NSString = rowData["artworkUrl60"] as NSString - var imgURL: NSURL = NSURL(string: urlString) + // Add a check to make sure this exists + let cellText: String? = rowData["trackName"] as? String + cell.text = cellText + cell.image = UIImage(named: "Blank52") - // Download an NSData representation of the image at the URL - var imgData: NSData = NSData(contentsOfURL: imgURL) - cell.image = UIImage(data: imgData) // Get the formatted price string for display in the subtitle var formattedPrice: NSString = rowData["formattedPrice"] as NSString + dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { + // Jump in to a background thread to get the image for this item + + // Grab the artworkUrl60 key to get an image URL for the app's thumbnail + var urlString: NSString = rowData["artworkUrl60"] as NSString + + // Check our image cache for the existing key. This is just a dictionary of UIImages + var image: UIImage? = self.imageCache.valueForKey(urlString) as? UIImage + + if( !image? ) { + // If the image does not exist, we need to download it + var imgURL: NSURL = NSURL(string: urlString) + + // Download an NSData representation of the image at the URL + var request: NSURLRequest = NSURLRequest(URL: imgURL) + var urlConnection: NSURLConnection = NSURLConnection(request: request, delegate: self) + NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {(response: NSURLResponse!,data: NSData!,error: NSError!) -> Void in + if !error? { + //var imgData: NSData = NSData(contentsOfURL: imgURL) + image = UIImage(data: data) + + // Store the image in to our cache + self.imageCache.setValue(image, forKey: urlString) + cell.image = image + } + else { + println("Error: \(error.localizedDescription)") + } + }) + + } + else { + cell.image = image + } + + + }) + cell.detailTextLabel.text = formattedPrice return cell From a37c0a0f181d87d38d9ad47e42ccd6c271355fad Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Mon, 16 Jun 2014 11:04:06 -0500 Subject: [PATCH 6/8] Part 6 --- SwiftTutorial.xcodeproj/project.pbxproj | 8 ++ SwiftTutorial/APIController.swift | 6 +- SwiftTutorial/Album.swift | 25 ++++ SwiftTutorial/Base.lproj/Main.storyboard | 75 +++++++++++- SwiftTutorial/DetailsViewController.swift | 27 +++++ .../SearchResultsViewController.swift | 111 ++++++++++++------ 6 files changed, 216 insertions(+), 36 deletions(-) create mode 100644 SwiftTutorial/Album.swift create mode 100644 SwiftTutorial/DetailsViewController.swift diff --git a/SwiftTutorial.xcodeproj/project.pbxproj b/SwiftTutorial.xcodeproj/project.pbxproj index 737a4fd..1c8c236 100644 --- a/SwiftTutorial.xcodeproj/project.pbxproj +++ b/SwiftTutorial.xcodeproj/project.pbxproj @@ -14,6 +14,8 @@ 0256BB63194F3F38003E2942 /* SwiftTutorialTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0256BB62194F3F38003E2942 /* SwiftTutorialTests.swift */; }; 0256BB6D194F41F5003E2942 /* APIController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0256BB6C194F41F5003E2942 /* APIController.swift */; }; 0256BB6F194F4852003E2942 /* Blank52.png in Resources */ = {isa = PBXBuildFile; fileRef = 0256BB6E194F4852003E2942 /* Blank52.png */; }; + 0256BB71194F4A9F003E2942 /* Album.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0256BB70194F4A9F003E2942 /* Album.swift */; }; + 0256BB73194F4B47003E2942 /* DetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0256BB72194F4B47003E2942 /* DetailsViewController.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -38,6 +40,8 @@ 0256BB62194F3F38003E2942 /* SwiftTutorialTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftTutorialTests.swift; sourceTree = ""; }; 0256BB6C194F41F5003E2942 /* APIController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIController.swift; sourceTree = ""; }; 0256BB6E194F4852003E2942 /* Blank52.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Blank52.png; sourceTree = ""; }; + 0256BB70194F4A9F003E2942 /* Album.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = ""; }; + 0256BB72194F4B47003E2942 /* DetailsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailsViewController.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -86,6 +90,8 @@ 0256BB56194F3F38003E2942 /* Images.xcassets */, 0256BB4D194F3F38003E2942 /* Supporting Files */, 0256BB6C194F41F5003E2942 /* APIController.swift */, + 0256BB70194F4A9F003E2942 /* Album.swift */, + 0256BB72194F4B47003E2942 /* DetailsViewController.swift */, ); path = SwiftTutorial; sourceTree = ""; @@ -218,6 +224,8 @@ 0256BB52194F3F38003E2942 /* SearchResultsViewController.swift in Sources */, 0256BB50194F3F38003E2942 /* AppDelegate.swift in Sources */, 0256BB6D194F41F5003E2942 /* APIController.swift in Sources */, + 0256BB71194F4A9F003E2942 /* Album.swift in Sources */, + 0256BB73194F4B47003E2942 /* DetailsViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/SwiftTutorial/APIController.swift b/SwiftTutorial/APIController.swift index 5b0b348..e8477bc 100644 --- a/SwiftTutorial/APIController.swift +++ b/SwiftTutorial/APIController.swift @@ -15,6 +15,10 @@ protocol APIControllerProtocol { class APIController: NSObject { var delegate: APIControllerProtocol? + init(delegate: APIControllerProtocol?) { + self.delegate = delegate + } + func searchItunesFor(searchTerm: String) { // The iTunes API wants multiple terms separated by + symbols, so replace spaces with + signs @@ -22,7 +26,7 @@ class APIController: NSObject { // Now escape anything else that isn't URL-friendly var escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) - var urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=software" + var urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=music&entity=album" var url: NSURL = NSURL(string: urlPath) var session = NSURLSession.sharedSession() var task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in diff --git a/SwiftTutorial/Album.swift b/SwiftTutorial/Album.swift new file mode 100644 index 0000000..fe42eed --- /dev/null +++ b/SwiftTutorial/Album.swift @@ -0,0 +1,25 @@ +// +// Album.swift +// SwiftTutorial +// +// Created by Jameson Quave on 6/16/14. +// Copyright (c) 2014 JQ Software LLC. All rights reserved. +// + +class Album { + var title: String? + var price: String? + var thumbnailImageURL: String? + var largeImageURL: String? + var itemURL: String? + var artistURL: String? + + init(name: String!, price: String!, thumbnailImageURL: String!, largeImageURL: String!, itemURL: String!, artistURL: String!) { + self.title = name + self.price = price + self.thumbnailImageURL = thumbnailImageURL + self.largeImageURL = largeImageURL + self.itemURL = itemURL + self.artistURL = artistURL + } +} \ No newline at end of file diff --git a/SwiftTutorial/Base.lproj/Main.storyboard b/SwiftTutorial/Base.lproj/Main.storyboard index 2c44c4c..6772659 100644 --- a/SwiftTutorial/Base.lproj/Main.storyboard +++ b/SwiftTutorial/Base.lproj/Main.storyboard @@ -1,5 +1,5 @@ - + @@ -45,6 +45,9 @@ + + + @@ -69,12 +72,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SwiftTutorial/DetailsViewController.swift b/SwiftTutorial/DetailsViewController.swift new file mode 100644 index 0000000..ad687a3 --- /dev/null +++ b/SwiftTutorial/DetailsViewController.swift @@ -0,0 +1,27 @@ +// +// DetailsViewController.swift +// SwiftTutorial +// +// Created by Jameson Quave on 6/16/14. +// Copyright (c) 2014 JQ Software LLC. All rights reserved. +// + +import UIKit + +class DetailsViewController: UIViewController { + + @IBOutlet var albumCover : UIImageView + @IBOutlet var titleLabel : UILabel + + var album: Album? + + init(coder aDecoder: NSCoder!) { + super.init(coder: aDecoder) + } + + override func viewDidLoad() { + super.viewDidLoad() + titleLabel.text = self.album?.title + albumCover.image = UIImage(data: NSData(contentsOfURL: NSURL(string: self.album?.largeImageURL))) + } +} \ No newline at end of file diff --git a/SwiftTutorial/SearchResultsViewController.swift b/SwiftTutorial/SearchResultsViewController.swift index 82c496b..5d881ea 100644 --- a/SwiftTutorial/SearchResultsViewController.swift +++ b/SwiftTutorial/SearchResultsViewController.swift @@ -11,15 +11,15 @@ import UIKit class SearchResultsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, APIControllerProtocol { @IBOutlet var appsTableView : UITableView - var tableData: NSArray = [] - var api: APIController = APIController() + var albums: Album[] = [] + @lazy var api: APIController = APIController(delegate: self) var imageCache = NSMutableDictionary() let kCellIdentifier = "SearchResultCell" override func viewDidLoad() { super.viewDidLoad() - self.api.delegate = self - api.searchItunesFor("Angry Birds") + UIApplication.sharedApplication().networkActivityIndicatorVisible = true + api.searchItunesFor("Bob Dylan") } override func didReceiveMemoryWarning() { @@ -28,51 +28,58 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa } func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int { - return tableData.count + return albums.count + } + + override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject) { + var detailsViewController: DetailsViewController = segue.destinationViewController as DetailsViewController + var albumIndex = appsTableView.indexPathForSelectedRow().row + var selectedAlbum = self.albums[albumIndex] + detailsViewController.album = selectedAlbum } func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { var cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(kCellIdentifier) as UITableViewCell - if cell == nil { - cell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: kCellIdentifier) - } - var rowData: NSDictionary = self.tableData[indexPath.row] as NSDictionary - - // Add a check to make sure this exists - let cellText: String? = rowData["trackName"] as? String - cell.text = cellText + // Find this cell's album by passing in the indexPath.row to the subscript method for an array of type Album[] + let album = self.albums[indexPath.row] + cell.text = album.title cell.image = UIImage(named: "Blank52") - - - // Get the formatted price string for display in the subtitle - var formattedPrice: NSString = rowData["formattedPrice"] as NSString + cell.detailTextLabel.text = album.price dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { // Jump in to a background thread to get the image for this item // Grab the artworkUrl60 key to get an image URL for the app's thumbnail - var urlString: NSString = rowData["artworkUrl60"] as NSString + //var urlString: NSString = rowData["artworkUrl60"] as NSString + let urlString = album.thumbnailImageURL // Check our image cache for the existing key. This is just a dictionary of UIImages - var image: UIImage? = self.imageCache.valueForKey(urlString) as? UIImage + var image = self.imageCache[urlString!] as? UIImage if( !image? ) { // If the image does not exist, we need to download it - var imgURL: NSURL = NSURL(string: urlString) + let imgURL: NSURL = NSURL(string: urlString) // Download an NSData representation of the image at the URL - var request: NSURLRequest = NSURLRequest(URL: imgURL) - var urlConnection: NSURLConnection = NSURLConnection(request: request, delegate: self) + let request: NSURLRequest = NSURLRequest(URL: imgURL) + let urlConnection: NSURLConnection = NSURLConnection(request: request, delegate: self) NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {(response: NSURLResponse!,data: NSData!,error: NSError!) -> Void in if !error? { - //var imgData: NSData = NSData(contentsOfURL: imgURL) image = UIImage(data: data) // Store the image in to our cache - self.imageCache.setValue(image, forKey: urlString) - cell.image = image + self.imageCache[urlString!] = image + + // Sometimes this request takes a while, and it's possible that a cell could be re-used before the art is done loading. + // Let's explicitly call the cellForRowAtIndexPath method of our tableView to make sure the cell is not nil, and therefore still showing onscreen. + // While this method sounds a lot like the method we're in right now, it isn't. + // Ctrl+Click on the method name to see how it's defined, including the following comment: + /** // returns nil if cell is not visible or index path is out of range **/ + if let albumArtsCell: UITableViewCell? = tableView.cellForRowAtIndexPath(indexPath) { + albumArtsCell!.image = image + } } else { println("Error: \(error.localizedDescription)") @@ -86,14 +93,11 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa }) - - cell.detailTextLabel.text = formattedPrice - return cell } func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) { - // Get the row data for the selected row + /*// Get the row data for the selected row var rowData: NSDictionary = self.tableData[indexPath.row] as NSDictionary var name: String = rowData["trackName"] as String @@ -103,15 +107,54 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa alert.title = name alert.message = formattedPrice alert.addButtonWithTitle("Ok") - alert.show() + alert.show()*/ } func didReceiveAPIResults(results: NSDictionary) { - var resultsArr: NSArray = results["results"] as NSArray - dispatch_async(dispatch_get_main_queue(), { - self.tableData = resultsArr + // Store the results in our table data array + if results.count>0 { + + let allResults: NSDictionary[] = results["results"] as NSDictionary[] + + // Sometimes iTunes returns a collection, not a track, so we check both for the 'name' + for result: NSDictionary in allResults { + + var name: String? = result["trackName"] as? String + if !name? { + name = result["collectionName"] as? String + } + + // Sometimes price comes in as formattedPrice, sometimes as collectionPrice.. and sometimes it's a float instead of a string. Hooray! + var price: String? = result["formattedPrice"] as? String + if !price? { + price = result["collectionPrice"] as? String + if !price? { + var priceFloat: Float? = result["collectionPrice"] as? Float + var nf: NSNumberFormatter = NSNumberFormatter() + nf.maximumFractionDigits = 2; + if priceFloat? { + price = "$"+nf.stringFromNumber(priceFloat) + } + } + } + + let thumbnailURL: String? = result["artworkUrl60"] as? String + let imageURL: String? = result["artworkUrl100"] as? String + let artistURL: String? = result["artistViewUrl"] as? String + + var itemURL: String? = result["collectionViewUrl"] as? String + if !itemURL? { + itemURL = result["trackViewUrl"] as? String + } + + var newAlbum = Album(name: name!, price: price!, thumbnailImageURL: thumbnailURL!, largeImageURL: imageURL!, itemURL: itemURL!, artistURL: artistURL!) + albums.append(newAlbum) + } + + self.appsTableView.reloadData() - }) + UIApplication.sharedApplication().networkActivityIndicatorVisible = false + } } From deb008674e06cd74357c8081f744f169897fecd6 Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Mon, 16 Jun 2014 11:08:44 -0500 Subject: [PATCH 7/8] Part 7 Intro --- SwiftTutorial/APIController.swift | 14 +++++++------- SwiftTutorial/SearchResultsViewController.swift | 10 +++++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/SwiftTutorial/APIController.swift b/SwiftTutorial/APIController.swift index e8477bc..42626cf 100644 --- a/SwiftTutorial/APIController.swift +++ b/SwiftTutorial/APIController.swift @@ -22,14 +22,14 @@ class APIController: NSObject { func searchItunesFor(searchTerm: String) { // The iTunes API wants multiple terms separated by + symbols, so replace spaces with + signs - var itunesSearchTerm = searchTerm.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil) + let itunesSearchTerm = searchTerm.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil) // Now escape anything else that isn't URL-friendly - var escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) - var urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=music&entity=album" - var url: NSURL = NSURL(string: urlPath) - var session = NSURLSession.sharedSession() - var task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in + let escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) + let urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=music&entity=album" + let url = NSURL(string: urlPath) + let session = NSURLSession.sharedSession() + let task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in println("Task completed") if(error) { // If there is an error in the web request, print it to the console @@ -41,7 +41,7 @@ class APIController: NSObject { // If there is an error parsing JSON, print it to the console println("JSON Error \(err!.localizedDescription)") } - var results: NSArray = jsonResult["results"] as NSArray + var results = jsonResult["results"] as NSArray // Now send the JSON result to our delegate object self.delegate?.didReceiveAPIResults(jsonResult) }) diff --git a/SwiftTutorial/SearchResultsViewController.swift b/SwiftTutorial/SearchResultsViewController.swift index 5d881ea..b538006 100644 --- a/SwiftTutorial/SearchResultsViewController.swift +++ b/SwiftTutorial/SearchResultsViewController.swift @@ -32,15 +32,15 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa } override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject) { - var detailsViewController: DetailsViewController = segue.destinationViewController as DetailsViewController - var albumIndex = appsTableView.indexPathForSelectedRow().row - var selectedAlbum = self.albums[albumIndex] + let detailsViewController: DetailsViewController = segue.destinationViewController as DetailsViewController + let albumIndex = appsTableView.indexPathForSelectedRow().row + let selectedAlbum = self.albums[albumIndex] detailsViewController.album = selectedAlbum } func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { - var cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(kCellIdentifier) as UITableViewCell + let cell = tableView.dequeueReusableCellWithIdentifier(kCellIdentifier) as UITableViewCell // Find this cell's album by passing in the indexPath.row to the subscript method for an array of type Album[] let album = self.albums[indexPath.row] @@ -60,7 +60,7 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa if( !image? ) { // If the image does not exist, we need to download it - let imgURL: NSURL = NSURL(string: urlString) + let imgURL = NSURL(string: urlString) // Download an NSData representation of the image at the URL let request: NSURLRequest = NSURLRequest(URL: imgURL) From 6ecbe8be8bbcc0413f6798415b11a583a404f866 Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Mon, 16 Jun 2014 11:34:15 -0500 Subject: [PATCH 8/8] Part 7 --- SwiftTutorial.xcodeproj/project.pbxproj | 10 +++ .../xcdebugger/Breakpoints_v2.xcbkptlist | 23 +++++++ SwiftTutorial/APIController.swift | 10 ++- SwiftTutorial/Album.swift | 4 +- SwiftTutorial/Base.lproj/Main.storyboard | 63 +++++++++++++++++- SwiftTutorial/DetailsViewController.swift | 65 ++++++++++++++++++- .../SearchResultsViewController.swift | 16 ++++- SwiftTutorial/Track.swift | 22 +++++++ SwiftTutorial/TrackCell.swift | 14 ++++ 9 files changed, 219 insertions(+), 8 deletions(-) create mode 100644 SwiftTutorial.xcodeproj/xcuserdata/jquave.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist create mode 100644 SwiftTutorial/Track.swift create mode 100644 SwiftTutorial/TrackCell.swift diff --git a/SwiftTutorial.xcodeproj/project.pbxproj b/SwiftTutorial.xcodeproj/project.pbxproj index 1c8c236..2304254 100644 --- a/SwiftTutorial.xcodeproj/project.pbxproj +++ b/SwiftTutorial.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 021C0E56194F506F0005B787 /* Track.swift in Sources */ = {isa = PBXBuildFile; fileRef = 021C0E55194F506F0005B787 /* Track.swift */; }; + 021C0E58194F51610005B787 /* TrackCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 021C0E57194F51610005B787 /* TrackCell.swift */; }; 0256BB50194F3F38003E2942 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0256BB4F194F3F38003E2942 /* AppDelegate.swift */; }; 0256BB52194F3F38003E2942 /* SearchResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0256BB51194F3F38003E2942 /* SearchResultsViewController.swift */; }; 0256BB55194F3F38003E2942 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0256BB53194F3F38003E2942 /* Main.storyboard */; }; @@ -29,6 +31,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 021C0E55194F506F0005B787 /* Track.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Track.swift; sourceTree = ""; }; + 021C0E57194F51610005B787 /* TrackCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrackCell.swift; sourceTree = ""; }; 0256BB4A194F3F38003E2942 /* SwiftTutorial.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftTutorial.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0256BB4E194F3F38003E2942 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 0256BB4F194F3F38003E2942 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -92,6 +96,8 @@ 0256BB6C194F41F5003E2942 /* APIController.swift */, 0256BB70194F4A9F003E2942 /* Album.swift */, 0256BB72194F4B47003E2942 /* DetailsViewController.swift */, + 021C0E55194F506F0005B787 /* Track.swift */, + 021C0E57194F51610005B787 /* TrackCell.swift */, ); path = SwiftTutorial; sourceTree = ""; @@ -221,11 +227,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 021C0E58194F51610005B787 /* TrackCell.swift in Sources */, 0256BB52194F3F38003E2942 /* SearchResultsViewController.swift in Sources */, 0256BB50194F3F38003E2942 /* AppDelegate.swift in Sources */, 0256BB6D194F41F5003E2942 /* APIController.swift in Sources */, 0256BB71194F4A9F003E2942 /* Album.swift in Sources */, 0256BB73194F4B47003E2942 /* DetailsViewController.swift in Sources */, + 021C0E56194F506F0005B787 /* Track.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -413,6 +421,7 @@ 0256BB68194F3F38003E2942 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; 0256BB69194F3F38003E2942 /* Build configuration list for PBXNativeTarget "SwiftTutorialTests" */ = { isa = XCConfigurationList; @@ -421,6 +430,7 @@ 0256BB6B194F3F38003E2942 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/SwiftTutorial.xcodeproj/xcuserdata/jquave.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/SwiftTutorial.xcodeproj/xcuserdata/jquave.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..2da389e --- /dev/null +++ b/SwiftTutorial.xcodeproj/xcuserdata/jquave.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,23 @@ + + + + + + + + + diff --git a/SwiftTutorial/APIController.swift b/SwiftTutorial/APIController.swift index 42626cf..c676999 100644 --- a/SwiftTutorial/APIController.swift +++ b/SwiftTutorial/APIController.swift @@ -27,7 +27,15 @@ class APIController: NSObject { // Now escape anything else that isn't URL-friendly let escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) let urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=music&entity=album" - let url = NSURL(string: urlPath) + get(urlPath) + } + + func lookupAlbum(collectionId: Int) { + get("https://itunes.apple.com/lookup?id=\(collectionId)&entity=song") + } + + func get(path: String) { + let url = NSURL(string: path) let session = NSURLSession.sharedSession() let task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in println("Task completed") diff --git a/SwiftTutorial/Album.swift b/SwiftTutorial/Album.swift index fe42eed..9777afd 100644 --- a/SwiftTutorial/Album.swift +++ b/SwiftTutorial/Album.swift @@ -13,13 +13,15 @@ class Album { var largeImageURL: String? var itemURL: String? var artistURL: String? + var collectionId: Int? - init(name: String!, price: String!, thumbnailImageURL: String!, largeImageURL: String!, itemURL: String!, artistURL: String!) { + init(name: String!, price: String!, thumbnailImageURL: String!, largeImageURL: String!, itemURL: String!, artistURL: String!, collectionId: Int?) { self.title = name self.price = price self.thumbnailImageURL = thumbnailImageURL self.largeImageURL = largeImageURL self.itemURL = itemURL self.artistURL = artistURL + self.collectionId = collectionId } } \ No newline at end of file diff --git a/SwiftTutorial/Base.lproj/Main.storyboard b/SwiftTutorial/Base.lproj/Main.storyboard index 6772659..09a9ebb 100644 --- a/SwiftTutorial/Base.lproj/Main.storyboard +++ b/SwiftTutorial/Base.lproj/Main.storyboard @@ -20,7 +20,7 @@ - + @@ -90,6 +90,7 @@ + @@ -114,23 +170,26 @@ + + + - + diff --git a/SwiftTutorial/DetailsViewController.swift b/SwiftTutorial/DetailsViewController.swift index ad687a3..a03e277 100644 --- a/SwiftTutorial/DetailsViewController.swift +++ b/SwiftTutorial/DetailsViewController.swift @@ -7,11 +7,19 @@ // import UIKit +import MediaPlayer +import QuartzCore -class DetailsViewController: UIViewController { +class DetailsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, APIControllerProtocol { + + var mediaPlayer: MPMoviePlayerController = MPMoviePlayerController() + var tracks: Track[] = [] @IBOutlet var albumCover : UIImageView @IBOutlet var titleLabel : UILabel + @IBOutlet var tracksTableView : UITableView + + @lazy var api: APIController = APIController(delegate: self) var album: Album? @@ -23,5 +31,60 @@ class DetailsViewController: UIViewController { super.viewDidLoad() titleLabel.text = self.album?.title albumCover.image = UIImage(data: NSData(contentsOfURL: NSURL(string: self.album?.largeImageURL))) + + // Load in tracks + if self.album?.collectionId? { + api.lookupAlbum(self.album!.collectionId!) + } + } + + func didReceiveAPIResults(results: NSDictionary) { + if let allResults = results["results"] as? NSDictionary[] { + for trackInfo in allResults { + // Create the track + if let kind = trackInfo["kind"] as? String { + if kind=="song" { + var track = Track(dict: trackInfo) + tracks.append(track) + } + } + } + } + dispatch_async(dispatch_get_main_queue(), { + self.tracksTableView.reloadData() + }) + } + + func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int { + return tracks.count + } + + func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { + var cell = tableView.dequeueReusableCellWithIdentifier("TrackCell") as TrackCell + + var track = tracks[indexPath.row] + cell.titleLabel.text = track.title + cell.playIcon.text = "▶️" + + return cell + } + + func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) { + var track = tracks[indexPath.row] + mediaPlayer.stop() + mediaPlayer.contentURL = NSURL(string: track.previewUrl) + mediaPlayer.play() + if let cell = tableView.cellForRowAtIndexPath(indexPath) as? TrackCell { + cell.playIcon.text = "YOUR_STOP_ICON" + } } + + func tableView(tableView: UITableView!, willDisplayCell cell: UITableViewCell!, forRowAtIndexPath indexPath: NSIndexPath!) { + cell.layer.transform = CATransform3DMakeScale(0.1,0.1,1) + UIView.animateWithDuration(0.25, animations: { + cell.layer.transform = CATransform3DMakeScale(1,1,1) + }) + } + + } \ No newline at end of file diff --git a/SwiftTutorial/SearchResultsViewController.swift b/SwiftTutorial/SearchResultsViewController.swift index b538006..44b5e4f 100644 --- a/SwiftTutorial/SearchResultsViewController.swift +++ b/SwiftTutorial/SearchResultsViewController.swift @@ -7,6 +7,7 @@ // import UIKit +import QuartzCore class SearchResultsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, APIControllerProtocol { @@ -147,16 +148,25 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa itemURL = result["trackViewUrl"] as? String } - var newAlbum = Album(name: name!, price: price!, thumbnailImageURL: thumbnailURL!, largeImageURL: imageURL!, itemURL: itemURL!, artistURL: artistURL!) + var collectionId = result["collectionId"] as? Int + var newAlbum = Album(name: name!, price: price!, thumbnailImageURL: thumbnailURL!, largeImageURL: imageURL!, itemURL: itemURL!, artistURL: artistURL!, collectionId: collectionId!) albums.append(newAlbum) } + dispatch_async(dispatch_get_main_queue(), { + self.appsTableView.reloadData() + }) - self.appsTableView.reloadData() UIApplication.sharedApplication().networkActivityIndicatorVisible = false } } - + + func tableView(tableView: UITableView!, willDisplayCell cell: UITableViewCell!, forRowAtIndexPath indexPath: NSIndexPath!) { + cell.layer.transform = CATransform3DMakeScale(0.1,0.1,1) + UIView.animateWithDuration(0.25, animations: { + cell.layer.transform = CATransform3DMakeScale(1,1,1) + }) + } } diff --git a/SwiftTutorial/Track.swift b/SwiftTutorial/Track.swift new file mode 100644 index 0000000..a6548e4 --- /dev/null +++ b/SwiftTutorial/Track.swift @@ -0,0 +1,22 @@ +// +// Track.swift +// SwiftTutorial +// +// Created by Jameson Quave on 6/16/14. +// Copyright (c) 2014 JQ Software LLC. All rights reserved. +// + +import Foundation + +class Track { + + var title: String? + var price: String? + var previewUrl: String? + + init(dict: NSDictionary!) { + self.title = dict["trackName"] as? String + self.price = dict["trackPrice"] as? String + self.previewUrl = dict["previewUrl"] as? String + } +} \ No newline at end of file diff --git a/SwiftTutorial/TrackCell.swift b/SwiftTutorial/TrackCell.swift new file mode 100644 index 0000000..b98af27 --- /dev/null +++ b/SwiftTutorial/TrackCell.swift @@ -0,0 +1,14 @@ +// +// TrackCell.swift +// SwiftTutorial +// +// Created by Jameson Quave on 6/16/14. +// Copyright (c) 2014 JQ Software LLC. All rights reserved. +// + +import UIKit + +class TrackCell: UITableViewCell { + @IBOutlet var titleLabel : UILabel + @IBOutlet var playIcon : UILabel +}