From a24a941b66117d223e4f7ed224866727f50d3e33 Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Sat, 26 Jul 2014 17:35:23 -0500 Subject: [PATCH 01/12] Initial Commit --- HelloWorld.xcodeproj/project.pbxproj | 410 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + HelloWorld/AppDelegate.swift | 46 ++ HelloWorld/Base.lproj/Main.storyboard | 25 ++ .../AppIcon.appiconset/Contents.json | 23 + .../LaunchImage.launchimage/Contents.json | 23 + HelloWorld/Info.plist | 38 ++ HelloWorld/ViewController.swift | 25 ++ HelloWorldTests/HelloWorldTests.swift | 36 ++ HelloWorldTests/Info.plist | 24 + 10 files changed, 657 insertions(+) create mode 100644 HelloWorld.xcodeproj/project.pbxproj create mode 100644 HelloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 HelloWorld/AppDelegate.swift create mode 100644 HelloWorld/Base.lproj/Main.storyboard create mode 100644 HelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json create mode 100644 HelloWorld/Images.xcassets/LaunchImage.launchimage/Contents.json create mode 100644 HelloWorld/Info.plist create mode 100644 HelloWorld/ViewController.swift create mode 100644 HelloWorldTests/HelloWorldTests.swift create mode 100644 HelloWorldTests/Info.plist diff --git a/HelloWorld.xcodeproj/project.pbxproj b/HelloWorld.xcodeproj/project.pbxproj new file mode 100644 index 0000000..1126ed1 --- /dev/null +++ b/HelloWorld.xcodeproj/project.pbxproj @@ -0,0 +1,410 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 024F8AB9198464AA00E9DEB8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F8AB8198464AA00E9DEB8 /* AppDelegate.swift */; }; + 024F8ABB198464AA00E9DEB8 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F8ABA198464AA00E9DEB8 /* ViewController.swift */; }; + 024F8ABE198464AA00E9DEB8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 024F8ABC198464AA00E9DEB8 /* Main.storyboard */; }; + 024F8AC0198464AA00E9DEB8 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 024F8ABF198464AA00E9DEB8 /* Images.xcassets */; }; + 024F8ACC198464AA00E9DEB8 /* HelloWorldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F8ACB198464AA00E9DEB8 /* HelloWorldTests.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 024F8AC6198464AA00E9DEB8 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 024F8AAB198464AA00E9DEB8 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 024F8AB2198464AA00E9DEB8; + remoteInfo = HelloWorld; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 024F8AB3198464AA00E9DEB8 /* HelloWorld.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloWorld.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 024F8AB7198464AA00E9DEB8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 024F8AB8198464AA00E9DEB8 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 024F8ABA198464AA00E9DEB8 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 024F8ABD198464AA00E9DEB8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 024F8ABF198464AA00E9DEB8 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 024F8AC5198464AA00E9DEB8 /* HelloWorldTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HelloWorldTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 024F8ACA198464AA00E9DEB8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 024F8ACB198464AA00E9DEB8 /* HelloWorldTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelloWorldTests.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 024F8AB0198464AA00E9DEB8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 024F8AC2198464AA00E9DEB8 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 024F8AAA198464AA00E9DEB8 = { + isa = PBXGroup; + children = ( + 024F8AB5198464AA00E9DEB8 /* HelloWorld */, + 024F8AC8198464AA00E9DEB8 /* HelloWorldTests */, + 024F8AB4198464AA00E9DEB8 /* Products */, + ); + sourceTree = ""; + }; + 024F8AB4198464AA00E9DEB8 /* Products */ = { + isa = PBXGroup; + children = ( + 024F8AB3198464AA00E9DEB8 /* HelloWorld.app */, + 024F8AC5198464AA00E9DEB8 /* HelloWorldTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 024F8AB5198464AA00E9DEB8 /* HelloWorld */ = { + isa = PBXGroup; + children = ( + 024F8AB8198464AA00E9DEB8 /* AppDelegate.swift */, + 024F8ABA198464AA00E9DEB8 /* ViewController.swift */, + 024F8ABC198464AA00E9DEB8 /* Main.storyboard */, + 024F8ABF198464AA00E9DEB8 /* Images.xcassets */, + 024F8AB6198464AA00E9DEB8 /* Supporting Files */, + ); + path = HelloWorld; + sourceTree = ""; + }; + 024F8AB6198464AA00E9DEB8 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 024F8AB7198464AA00E9DEB8 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 024F8AC8198464AA00E9DEB8 /* HelloWorldTests */ = { + isa = PBXGroup; + children = ( + 024F8ACB198464AA00E9DEB8 /* HelloWorldTests.swift */, + 024F8AC9198464AA00E9DEB8 /* Supporting Files */, + ); + path = HelloWorldTests; + sourceTree = ""; + }; + 024F8AC9198464AA00E9DEB8 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 024F8ACA198464AA00E9DEB8 /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 024F8AB2198464AA00E9DEB8 /* HelloWorld */ = { + isa = PBXNativeTarget; + buildConfigurationList = 024F8ACF198464AA00E9DEB8 /* Build configuration list for PBXNativeTarget "HelloWorld" */; + buildPhases = ( + 024F8AAF198464AA00E9DEB8 /* Sources */, + 024F8AB0198464AA00E9DEB8 /* Frameworks */, + 024F8AB1198464AA00E9DEB8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = HelloWorld; + productName = HelloWorld; + productReference = 024F8AB3198464AA00E9DEB8 /* HelloWorld.app */; + productType = "com.apple.product-type.application"; + }; + 024F8AC4198464AA00E9DEB8 /* HelloWorldTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 024F8AD2198464AA00E9DEB8 /* Build configuration list for PBXNativeTarget "HelloWorldTests" */; + buildPhases = ( + 024F8AC1198464AA00E9DEB8 /* Sources */, + 024F8AC2198464AA00E9DEB8 /* Frameworks */, + 024F8AC3198464AA00E9DEB8 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 024F8AC7198464AA00E9DEB8 /* PBXTargetDependency */, + ); + name = HelloWorldTests; + productName = HelloWorldTests; + productReference = 024F8AC5198464AA00E9DEB8 /* HelloWorldTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 024F8AAB198464AA00E9DEB8 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0600; + ORGANIZATIONNAME = "JQ Software"; + TargetAttributes = { + 024F8AB2198464AA00E9DEB8 = { + CreatedOnToolsVersion = 6.0; + }; + 024F8AC4198464AA00E9DEB8 = { + CreatedOnToolsVersion = 6.0; + TestTargetID = 024F8AB2198464AA00E9DEB8; + }; + }; + }; + buildConfigurationList = 024F8AAE198464AA00E9DEB8 /* Build configuration list for PBXProject "HelloWorld" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 024F8AAA198464AA00E9DEB8; + productRefGroup = 024F8AB4198464AA00E9DEB8 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 024F8AB2198464AA00E9DEB8 /* HelloWorld */, + 024F8AC4198464AA00E9DEB8 /* HelloWorldTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 024F8AB1198464AA00E9DEB8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 024F8ABE198464AA00E9DEB8 /* Main.storyboard in Resources */, + 024F8AC0198464AA00E9DEB8 /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 024F8AC3198464AA00E9DEB8 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 024F8AAF198464AA00E9DEB8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 024F8ABB198464AA00E9DEB8 /* ViewController.swift in Sources */, + 024F8AB9198464AA00E9DEB8 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 024F8AC1198464AA00E9DEB8 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 024F8ACC198464AA00E9DEB8 /* HelloWorldTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 024F8AC7198464AA00E9DEB8 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 024F8AB2198464AA00E9DEB8 /* HelloWorld */; + targetProxy = 024F8AC6198464AA00E9DEB8 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 024F8ABC198464AA00E9DEB8 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 024F8ABD198464AA00E9DEB8 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 024F8ACD198464AA00E9DEB8 /* 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; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 024F8ACE198464AA00E9DEB8 /* 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; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 024F8AD0198464AA00E9DEB8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + INFOPLIST_FILE = HelloWorld/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 024F8AD1198464AA00E9DEB8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + INFOPLIST_FILE = HelloWorld/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 024F8AD3198464AA00E9DEB8 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/HelloWorld.app/HelloWorld"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = HelloWorldTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUNDLE_LOADER)"; + }; + name = Debug; + }; + 024F8AD4198464AA00E9DEB8 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/HelloWorld.app/HelloWorld"; + FRAMEWORK_SEARCH_PATHS = ( + "$(SDKROOT)/Developer/Library/Frameworks", + "$(inherited)", + ); + INFOPLIST_FILE = HelloWorldTests/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUNDLE_LOADER)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 024F8AAE198464AA00E9DEB8 /* Build configuration list for PBXProject "HelloWorld" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 024F8ACD198464AA00E9DEB8 /* Debug */, + 024F8ACE198464AA00E9DEB8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 024F8ACF198464AA00E9DEB8 /* Build configuration list for PBXNativeTarget "HelloWorld" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 024F8AD0198464AA00E9DEB8 /* Debug */, + 024F8AD1198464AA00E9DEB8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; + 024F8AD2198464AA00E9DEB8 /* Build configuration list for PBXNativeTarget "HelloWorldTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 024F8AD3198464AA00E9DEB8 /* Debug */, + 024F8AD4198464AA00E9DEB8 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = 024F8AAB198464AA00E9DEB8 /* Project object */; +} diff --git a/HelloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/HelloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..174a04e --- /dev/null +++ b/HelloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/HelloWorld/AppDelegate.swift b/HelloWorld/AppDelegate.swift new file mode 100644 index 0000000..34b6fff --- /dev/null +++ b/HelloWorld/AppDelegate.swift @@ -0,0 +1,46 @@ +// +// AppDelegate.swift +// HelloWorld +// +// Created by Jameson Quave on 7/26/14. +// Copyright (c) 2014 JQ Software. 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/HelloWorld/Base.lproj/Main.storyboard b/HelloWorld/Base.lproj/Main.storyboard new file mode 100644 index 0000000..9d65d6f --- /dev/null +++ b/HelloWorld/Base.lproj/Main.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json b/HelloWorld/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..a396706 --- /dev/null +++ b/HelloWorld/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/HelloWorld/Images.xcassets/LaunchImage.launchimage/Contents.json b/HelloWorld/Images.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 0000000..c79ebd3 --- /dev/null +++ b/HelloWorld/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/HelloWorld/Info.plist b/HelloWorld/Info.plist new file mode 100644 index 0000000..5577fb0 --- /dev/null +++ b/HelloWorld/Info.plist @@ -0,0 +1,38 @@ + + + + + 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 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/HelloWorld/ViewController.swift b/HelloWorld/ViewController.swift new file mode 100644 index 0000000..c605ecb --- /dev/null +++ b/HelloWorld/ViewController.swift @@ -0,0 +1,25 @@ +// +// ViewController.swift +// HelloWorld +// +// Created by Jameson Quave on 7/26/14. +// Copyright (c) 2014 JQ Software. 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/HelloWorldTests/HelloWorldTests.swift b/HelloWorldTests/HelloWorldTests.swift new file mode 100644 index 0000000..df2a134 --- /dev/null +++ b/HelloWorldTests/HelloWorldTests.swift @@ -0,0 +1,36 @@ +// +// HelloWorldTests.swift +// HelloWorldTests +// +// Created by Jameson Quave on 7/26/14. +// Copyright (c) 2014 JQ Software. All rights reserved. +// + +import UIKit +import XCTest + +class HelloWorldTests: 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. + } + } + +} diff --git a/HelloWorldTests/Info.plist b/HelloWorldTests/Info.plist new file mode 100644 index 0000000..a555585 --- /dev/null +++ b/HelloWorldTests/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 + + From 91c4134141b95c156cb47abc9c6c38dff99252b2 Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Sat, 26 Jul 2014 18:08:00 -0500 Subject: [PATCH 02/12] Part 2 --- .../xcschemes/HelloWorld.xcscheme | 96 +++++++++++++++++++ .../xcschemes/xcschememanagement.plist | 27 ++++++ HelloWorld/AppDelegate.swift | 2 +- HelloWorld/Base.lproj/Main.storyboard | 22 ++++- HelloWorld/ViewController.swift | 73 +++++++++++++- 5 files changed, 213 insertions(+), 7 deletions(-) create mode 100644 HelloWorld.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/HelloWorld.xcscheme create mode 100644 HelloWorld.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/xcschememanagement.plist diff --git a/HelloWorld.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/HelloWorld.xcscheme b/HelloWorld.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/HelloWorld.xcscheme new file mode 100644 index 0000000..541545d --- /dev/null +++ b/HelloWorld.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/HelloWorld.xcscheme @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HelloWorld.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/xcschememanagement.plist b/HelloWorld.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..8de7f7a --- /dev/null +++ b/HelloWorld.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,27 @@ + + + + + SchemeUserState + + HelloWorld.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 024F8AB2198464AA00E9DEB8 + + primary + + + 024F8AC4198464AA00E9DEB8 + + primary + + + + + diff --git a/HelloWorld/AppDelegate.swift b/HelloWorld/AppDelegate.swift index 34b6fff..e7883ab 100644 --- a/HelloWorld/AppDelegate.swift +++ b/HelloWorld/AppDelegate.swift @@ -15,7 +15,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool { - // Override point for customization after application launch. + println("Hello World") return true } diff --git a/HelloWorld/Base.lproj/Main.storyboard b/HelloWorld/Base.lproj/Main.storyboard index 9d65d6f..b74f4e2 100644 --- a/HelloWorld/Base.lproj/Main.storyboard +++ b/HelloWorld/Base.lproj/Main.storyboard @@ -1,25 +1,39 @@ - + - + - + - + + + + + + + + + + + + + + + diff --git a/HelloWorld/ViewController.swift b/HelloWorld/ViewController.swift index c605ecb..6575dac 100644 --- a/HelloWorld/ViewController.swift +++ b/HelloWorld/ViewController.swift @@ -8,11 +8,15 @@ import UIKit -class ViewController: UIViewController { +class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { + + @IBOutlet var appsTableView : UITableView? + var tableData = [] + override func viewDidLoad() { super.viewDidLoad() - // Do any additional setup after loading the view, typically from a nib. + searchItunesFor("JQ Software") } override func didReceiveMemoryWarning() { @@ -20,6 +24,71 @@ class ViewController: UIViewController { // 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") + + let rowData: NSDictionary = self.tableData[indexPath.row] as NSDictionary + + cell.textLabel.text = rowData["trackName"] as String + + // Grab the artworkUrl60 key to get an image URL for the app's thumbnail + let urlString: NSString = rowData["artworkUrl60"] as NSString + let imgURL: NSURL = NSURL(string: urlString) + + // Download an NSData representation of the image at the URL + let imgData: NSData = NSData(contentsOfURL: imgURL) + cell.imageView.image = UIImage(data: imgData) + + // Get the formatted price string for display in the subtitle + let formattedPrice: NSString = rowData["formattedPrice"] as NSString + + cell.detailTextLabel.text = formattedPrice + + return cell + } + + + + + + + func searchItunesFor(searchTerm: String) { + + // The iTunes API wants multiple terms separated by + symbols, so replace spaces with + signs + let itunesSearchTerm = searchTerm.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil) + + // Now escape anything else that isn't URL-friendly + let escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) + let urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=software" + let url: NSURL = 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 + 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)") + } + let results: NSArray = jsonResult["results"] as NSArray + dispatch_async(dispatch_get_main_queue(), { + self.tableData = results + self.appsTableView!.reloadData() + }) + }) + task.resume() + } } From 33bca770b90161d8dae7d267f0cbeab9b8216ba6 Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Sat, 26 Jul 2014 18:48:12 -0500 Subject: [PATCH 03/12] Part 3 --- HelloWorld/APIController.swift | 51 ++++++++++ HelloWorld/Base.lproj/Main.storyboard | 6 +- HelloWorld/SearchResultsViewController.swift | 69 ++++++++++++++ HelloWorld/ViewController.swift | 94 ------------------- .../project.pbxproj | 68 ++++++++------ .../contents.xcworkspacedata | 2 +- .../WorkspaceSettings.xcsettings | 10 ++ .../xcschemes/HelloWorld.xcscheme | 30 +++--- .../xcschemes/xcschememanagement.plist | 0 9 files changed, 186 insertions(+), 144 deletions(-) create mode 100644 HelloWorld/APIController.swift create mode 100644 HelloWorld/SearchResultsViewController.swift delete mode 100644 HelloWorld/ViewController.swift rename {HelloWorld.xcodeproj => MusicSearchTutorial.xcodeproj}/project.pbxproj (81%) rename {HelloWorld.xcodeproj => MusicSearchTutorial.xcodeproj}/project.xcworkspace/contents.xcworkspacedata (66%) create mode 100644 MusicSearchTutorial.xcodeproj/project.xcworkspace/xcuserdata/jquave.xcuserdatad/WorkspaceSettings.xcsettings rename {HelloWorld.xcodeproj => MusicSearchTutorial.xcodeproj}/xcuserdata/jquave.xcuserdatad/xcschemes/HelloWorld.xcscheme (75%) rename {HelloWorld.xcodeproj => MusicSearchTutorial.xcodeproj}/xcuserdata/jquave.xcuserdatad/xcschemes/xcschememanagement.plist (100%) diff --git a/HelloWorld/APIController.swift b/HelloWorld/APIController.swift new file mode 100644 index 0000000..6ac1730 --- /dev/null +++ b/HelloWorld/APIController.swift @@ -0,0 +1,51 @@ +// +// APIController.swift +// MusicSearchTutorial +// +// Created by Jameson Quave on 7/26/14. +// Copyright (c) 2014 JQ Software. All rights reserved. +// + +import Foundation + +protocol APIControllerProtocol { + func didReceiveAPIResults(results: NSDictionary) +} + +class APIController { + + var delegate: APIControllerProtocol? + + init() { + + } + + func searchItunesFor(searchTerm: String) { + + // The iTunes API wants multiple terms separated by + symbols, so replace spaces with + signs + let itunesSearchTerm = searchTerm.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil) + + // Now escape anything else that isn't URL-friendly + let escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) + let urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=software" + let url: NSURL = 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 + 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)") + } + let results: NSArray = jsonResult["results"] as NSArray + self.delegate?.didReceiveAPIResults(jsonResult) // THIS IS THE NEW LINE!! + }) + task.resume() + } + +} \ No newline at end of file diff --git a/HelloWorld/Base.lproj/Main.storyboard b/HelloWorld/Base.lproj/Main.storyboard index b74f4e2..8ac4900 100644 --- a/HelloWorld/Base.lproj/Main.storyboard +++ b/HelloWorld/Base.lproj/Main.storyboard @@ -4,10 +4,10 @@ - + - + @@ -28,7 +28,7 @@ - + diff --git a/HelloWorld/SearchResultsViewController.swift b/HelloWorld/SearchResultsViewController.swift new file mode 100644 index 0000000..c4b798f --- /dev/null +++ b/HelloWorld/SearchResultsViewController.swift @@ -0,0 +1,69 @@ +// +// ViewController.swift +// HelloWorld +// +// Created by Jameson Quave on 7/26/14. +// Copyright (c) 2014 JQ Software. All rights reserved. +// + +import UIKit + +class SearchResultsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, APIControllerProtocol { + + @IBOutlet var appsTableView : UITableView? + var tableData = [] + var api = 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. + } + + + // The APIControllerProtocol method + func didReceiveAPIResults(results: NSDictionary) { + var resultsArr: NSArray = results["results"] as NSArray + dispatch_async(dispatch_get_main_queue(), { + self.tableData = resultsArr + self.appsTableView!.reloadData() + }) + } + + + // The protocol methods for UITableViewDataSource and UITableViewDelegate + 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") + + let rowData: NSDictionary = self.tableData[indexPath.row] as NSDictionary + + cell.textLabel.text = rowData["trackName"] as String + + // Grab the artworkUrl60 key to get an image URL for the app's thumbnail + let urlString: NSString = rowData["artworkUrl60"] as NSString + let imgURL: NSURL = NSURL(string: urlString) + + // Download an NSData representation of the image at the URL + let imgData: NSData = NSData(contentsOfURL: imgURL) + cell.imageView.image = UIImage(data: imgData) + + // Get the formatted price string for display in the subtitle + let formattedPrice: NSString = rowData["formattedPrice"] as NSString + + cell.detailTextLabel.text = formattedPrice + + return cell + } + +} + diff --git a/HelloWorld/ViewController.swift b/HelloWorld/ViewController.swift deleted file mode 100644 index 6575dac..0000000 --- a/HelloWorld/ViewController.swift +++ /dev/null @@ -1,94 +0,0 @@ -// -// ViewController.swift -// HelloWorld -// -// Created by Jameson Quave on 7/26/14. -// Copyright (c) 2014 JQ Software. All rights reserved. -// - -import UIKit - -class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { - - @IBOutlet var appsTableView : UITableView? - var tableData = [] - - - override func viewDidLoad() { - super.viewDidLoad() - searchItunesFor("JQ Software") - } - - 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") - - let rowData: NSDictionary = self.tableData[indexPath.row] as NSDictionary - - cell.textLabel.text = rowData["trackName"] as String - - // Grab the artworkUrl60 key to get an image URL for the app's thumbnail - let urlString: NSString = rowData["artworkUrl60"] as NSString - let imgURL: NSURL = NSURL(string: urlString) - - // Download an NSData representation of the image at the URL - let imgData: NSData = NSData(contentsOfURL: imgURL) - cell.imageView.image = UIImage(data: imgData) - - // Get the formatted price string for display in the subtitle - let formattedPrice: NSString = rowData["formattedPrice"] as NSString - - cell.detailTextLabel.text = formattedPrice - - return cell - } - - - - - - - func searchItunesFor(searchTerm: String) { - - // The iTunes API wants multiple terms separated by + symbols, so replace spaces with + signs - let itunesSearchTerm = searchTerm.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil) - - // Now escape anything else that isn't URL-friendly - let escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) - let urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=software" - let url: NSURL = 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 - 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)") - } - let results: NSArray = jsonResult["results"] as NSArray - dispatch_async(dispatch_get_main_queue(), { - self.tableData = results - self.appsTableView!.reloadData() - }) - }) - task.resume() - } - -} - diff --git a/HelloWorld.xcodeproj/project.pbxproj b/MusicSearchTutorial.xcodeproj/project.pbxproj similarity index 81% rename from HelloWorld.xcodeproj/project.pbxproj rename to MusicSearchTutorial.xcodeproj/project.pbxproj index 1126ed1..1d24a25 100644 --- a/HelloWorld.xcodeproj/project.pbxproj +++ b/MusicSearchTutorial.xcodeproj/project.pbxproj @@ -8,10 +8,11 @@ /* Begin PBXBuildFile section */ 024F8AB9198464AA00E9DEB8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F8AB8198464AA00E9DEB8 /* AppDelegate.swift */; }; - 024F8ABB198464AA00E9DEB8 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F8ABA198464AA00E9DEB8 /* ViewController.swift */; }; + 024F8ABB198464AA00E9DEB8 /* SearchResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F8ABA198464AA00E9DEB8 /* SearchResultsViewController.swift */; }; 024F8ABE198464AA00E9DEB8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 024F8ABC198464AA00E9DEB8 /* Main.storyboard */; }; 024F8AC0198464AA00E9DEB8 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 024F8ABF198464AA00E9DEB8 /* Images.xcassets */; }; 024F8ACC198464AA00E9DEB8 /* HelloWorldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F8ACB198464AA00E9DEB8 /* HelloWorldTests.swift */; }; + 024F8AD619846FC100E9DEB8 /* APIController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F8AD519846FC100E9DEB8 /* APIController.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -25,15 +26,16 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 024F8AB3198464AA00E9DEB8 /* HelloWorld.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HelloWorld.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 024F8AB3198464AA00E9DEB8 /* MusicSearchTutorial.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MusicSearchTutorial.app; sourceTree = BUILT_PRODUCTS_DIR; }; 024F8AB7198464AA00E9DEB8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 024F8AB8198464AA00E9DEB8 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 024F8ABA198464AA00E9DEB8 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 024F8ABA198464AA00E9DEB8 /* SearchResultsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultsViewController.swift; sourceTree = ""; }; 024F8ABD198464AA00E9DEB8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 024F8ABF198464AA00E9DEB8 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; - 024F8AC5198464AA00E9DEB8 /* HelloWorldTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HelloWorldTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 024F8AC5198464AA00E9DEB8 /* MusicSearchTutorialTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MusicSearchTutorialTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 024F8ACA198464AA00E9DEB8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 024F8ACB198464AA00E9DEB8 /* HelloWorldTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelloWorldTests.swift; sourceTree = ""; }; + 024F8AD519846FC100E9DEB8 /* APIController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIController.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -57,8 +59,8 @@ 024F8AAA198464AA00E9DEB8 = { isa = PBXGroup; children = ( - 024F8AB5198464AA00E9DEB8 /* HelloWorld */, - 024F8AC8198464AA00E9DEB8 /* HelloWorldTests */, + 024F8AB5198464AA00E9DEB8 /* MusicSearchTutorial */, + 024F8AC8198464AA00E9DEB8 /* MusicSearchTutorialTests */, 024F8AB4198464AA00E9DEB8 /* Products */, ); sourceTree = ""; @@ -66,21 +68,23 @@ 024F8AB4198464AA00E9DEB8 /* Products */ = { isa = PBXGroup; children = ( - 024F8AB3198464AA00E9DEB8 /* HelloWorld.app */, - 024F8AC5198464AA00E9DEB8 /* HelloWorldTests.xctest */, + 024F8AB3198464AA00E9DEB8 /* MusicSearchTutorial.app */, + 024F8AC5198464AA00E9DEB8 /* MusicSearchTutorialTests.xctest */, ); name = Products; sourceTree = ""; }; - 024F8AB5198464AA00E9DEB8 /* HelloWorld */ = { + 024F8AB5198464AA00E9DEB8 /* MusicSearchTutorial */ = { isa = PBXGroup; children = ( 024F8AB8198464AA00E9DEB8 /* AppDelegate.swift */, - 024F8ABA198464AA00E9DEB8 /* ViewController.swift */, + 024F8ABA198464AA00E9DEB8 /* SearchResultsViewController.swift */, 024F8ABC198464AA00E9DEB8 /* Main.storyboard */, 024F8ABF198464AA00E9DEB8 /* Images.xcassets */, 024F8AB6198464AA00E9DEB8 /* Supporting Files */, + 024F8AD519846FC100E9DEB8 /* APIController.swift */, ); + name = MusicSearchTutorial; path = HelloWorld; sourceTree = ""; }; @@ -92,12 +96,13 @@ name = "Supporting Files"; sourceTree = ""; }; - 024F8AC8198464AA00E9DEB8 /* HelloWorldTests */ = { + 024F8AC8198464AA00E9DEB8 /* MusicSearchTutorialTests */ = { isa = PBXGroup; children = ( 024F8ACB198464AA00E9DEB8 /* HelloWorldTests.swift */, 024F8AC9198464AA00E9DEB8 /* Supporting Files */, ); + name = MusicSearchTutorialTests; path = HelloWorldTests; sourceTree = ""; }; @@ -112,9 +117,9 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 024F8AB2198464AA00E9DEB8 /* HelloWorld */ = { + 024F8AB2198464AA00E9DEB8 /* MusicSearchTutorial */ = { isa = PBXNativeTarget; - buildConfigurationList = 024F8ACF198464AA00E9DEB8 /* Build configuration list for PBXNativeTarget "HelloWorld" */; + buildConfigurationList = 024F8ACF198464AA00E9DEB8 /* Build configuration list for PBXNativeTarget "MusicSearchTutorial" */; buildPhases = ( 024F8AAF198464AA00E9DEB8 /* Sources */, 024F8AB0198464AA00E9DEB8 /* Frameworks */, @@ -124,14 +129,14 @@ ); dependencies = ( ); - name = HelloWorld; + name = MusicSearchTutorial; productName = HelloWorld; - productReference = 024F8AB3198464AA00E9DEB8 /* HelloWorld.app */; + productReference = 024F8AB3198464AA00E9DEB8 /* MusicSearchTutorial.app */; productType = "com.apple.product-type.application"; }; - 024F8AC4198464AA00E9DEB8 /* HelloWorldTests */ = { + 024F8AC4198464AA00E9DEB8 /* MusicSearchTutorialTests */ = { isa = PBXNativeTarget; - buildConfigurationList = 024F8AD2198464AA00E9DEB8 /* Build configuration list for PBXNativeTarget "HelloWorldTests" */; + buildConfigurationList = 024F8AD2198464AA00E9DEB8 /* Build configuration list for PBXNativeTarget "MusicSearchTutorialTests" */; buildPhases = ( 024F8AC1198464AA00E9DEB8 /* Sources */, 024F8AC2198464AA00E9DEB8 /* Frameworks */, @@ -142,9 +147,9 @@ dependencies = ( 024F8AC7198464AA00E9DEB8 /* PBXTargetDependency */, ); - name = HelloWorldTests; + name = MusicSearchTutorialTests; productName = HelloWorldTests; - productReference = 024F8AC5198464AA00E9DEB8 /* HelloWorldTests.xctest */; + productReference = 024F8AC5198464AA00E9DEB8 /* MusicSearchTutorialTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; /* End PBXNativeTarget section */ @@ -165,7 +170,7 @@ }; }; }; - buildConfigurationList = 024F8AAE198464AA00E9DEB8 /* Build configuration list for PBXProject "HelloWorld" */; + buildConfigurationList = 024F8AAE198464AA00E9DEB8 /* Build configuration list for PBXProject "MusicSearchTutorial" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; @@ -178,8 +183,8 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 024F8AB2198464AA00E9DEB8 /* HelloWorld */, - 024F8AC4198464AA00E9DEB8 /* HelloWorldTests */, + 024F8AB2198464AA00E9DEB8 /* MusicSearchTutorial */, + 024F8AC4198464AA00E9DEB8 /* MusicSearchTutorialTests */, ); }; /* End PBXProject section */ @@ -208,8 +213,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 024F8ABB198464AA00E9DEB8 /* ViewController.swift in Sources */, + 024F8ABB198464AA00E9DEB8 /* SearchResultsViewController.swift in Sources */, 024F8AB9198464AA00E9DEB8 /* AppDelegate.swift in Sources */, + 024F8AD619846FC100E9DEB8 /* APIController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -226,7 +232,7 @@ /* Begin PBXTargetDependency section */ 024F8AC7198464AA00E9DEB8 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 024F8AB2198464AA00E9DEB8 /* HelloWorld */; + target = 024F8AB2198464AA00E9DEB8 /* MusicSearchTutorial */; targetProxy = 024F8AC6198464AA00E9DEB8 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -327,7 +333,7 @@ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; INFOPLIST_FILE = HelloWorld/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = MusicSearchTutorial; }; name = Debug; }; @@ -338,7 +344,7 @@ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; INFOPLIST_FILE = HelloWorld/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = MusicSearchTutorial; }; name = Release; }; @@ -356,7 +362,7 @@ ); INFOPLIST_FILE = HelloWorldTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = MusicSearchTutorialTests; TEST_HOST = "$(BUNDLE_LOADER)"; }; name = Debug; @@ -371,7 +377,7 @@ ); INFOPLIST_FILE = HelloWorldTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = MusicSearchTutorialTests; TEST_HOST = "$(BUNDLE_LOADER)"; }; name = Release; @@ -379,7 +385,7 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 024F8AAE198464AA00E9DEB8 /* Build configuration list for PBXProject "HelloWorld" */ = { + 024F8AAE198464AA00E9DEB8 /* Build configuration list for PBXProject "MusicSearchTutorial" */ = { isa = XCConfigurationList; buildConfigurations = ( 024F8ACD198464AA00E9DEB8 /* Debug */, @@ -388,7 +394,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 024F8ACF198464AA00E9DEB8 /* Build configuration list for PBXNativeTarget "HelloWorld" */ = { + 024F8ACF198464AA00E9DEB8 /* Build configuration list for PBXNativeTarget "MusicSearchTutorial" */ = { isa = XCConfigurationList; buildConfigurations = ( 024F8AD0198464AA00E9DEB8 /* Debug */, @@ -396,7 +402,7 @@ ); defaultConfigurationIsVisible = 0; }; - 024F8AD2198464AA00E9DEB8 /* Build configuration list for PBXNativeTarget "HelloWorldTests" */ = { + 024F8AD2198464AA00E9DEB8 /* Build configuration list for PBXNativeTarget "MusicSearchTutorialTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 024F8AD3198464AA00E9DEB8 /* Debug */, diff --git a/HelloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/MusicSearchTutorial.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 66% rename from HelloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to MusicSearchTutorial.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 174a04e..3492714 100644 --- a/HelloWorld.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/MusicSearchTutorial.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:MusicSearchTutorial.xcodeproj"> diff --git a/MusicSearchTutorial.xcodeproj/project.xcworkspace/xcuserdata/jquave.xcuserdatad/WorkspaceSettings.xcsettings b/MusicSearchTutorial.xcodeproj/project.xcworkspace/xcuserdata/jquave.xcuserdatad/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..bfffcfe --- /dev/null +++ b/MusicSearchTutorial.xcodeproj/project.xcworkspace/xcuserdata/jquave.xcuserdatad/WorkspaceSettings.xcsettings @@ -0,0 +1,10 @@ + + + + + HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges + + SnapshotAutomaticallyBeforeSignificantChanges + + + diff --git a/HelloWorld.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/HelloWorld.xcscheme b/MusicSearchTutorial.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/HelloWorld.xcscheme similarity index 75% rename from HelloWorld.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/HelloWorld.xcscheme rename to MusicSearchTutorial.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/HelloWorld.xcscheme index 541545d..b266de8 100644 --- a/HelloWorld.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/HelloWorld.xcscheme +++ b/MusicSearchTutorial.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/HelloWorld.xcscheme @@ -15,9 +15,9 @@ + BuildableName = "MusicSearchTutorial.app" + BlueprintName = "MusicSearchTutorial" + ReferencedContainer = "container:MusicSearchTutorial.xcodeproj"> @@ -33,9 +33,9 @@ + BuildableName = "MusicSearchTutorialTests.xctest" + BlueprintName = "MusicSearchTutorialTests" + ReferencedContainer = "container:MusicSearchTutorial.xcodeproj"> @@ -43,9 +43,9 @@ + BuildableName = "MusicSearchTutorial.app" + BlueprintName = "MusicSearchTutorial" + ReferencedContainer = "container:MusicSearchTutorial.xcodeproj"> @@ -62,9 +62,9 @@ + BuildableName = "MusicSearchTutorial.app" + BlueprintName = "MusicSearchTutorial" + ReferencedContainer = "container:MusicSearchTutorial.xcodeproj"> @@ -80,9 +80,9 @@ + BuildableName = "MusicSearchTutorial.app" + BlueprintName = "MusicSearchTutorial" + ReferencedContainer = "container:MusicSearchTutorial.xcodeproj"> diff --git a/HelloWorld.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/xcschememanagement.plist b/MusicSearchTutorial.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/xcschememanagement.plist similarity index 100% rename from HelloWorld.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/xcschememanagement.plist rename to MusicSearchTutorial.xcodeproj/xcuserdata/jquave.xcuserdatad/xcschemes/xcschememanagement.plist From 5cc4eb78e3d4cfb4ec22cd285481030b928d2fda Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Sat, 26 Jul 2014 19:19:28 -0500 Subject: [PATCH 04/12] Part4 --- HelloWorld/Base.lproj/Main.storyboard | 22 ++++++++++++++++++++ HelloWorld/SearchResultsViewController.swift | 18 +++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/HelloWorld/Base.lproj/Main.storyboard b/HelloWorld/Base.lproj/Main.storyboard index 8ac4900..ed472a8 100644 --- a/HelloWorld/Base.lproj/Main.storyboard +++ b/HelloWorld/Base.lproj/Main.storyboard @@ -19,6 +19,28 @@ + + + + + + + + + + + + diff --git a/HelloWorld/SearchResultsViewController.swift b/HelloWorld/SearchResultsViewController.swift index c4b798f..5d3b451 100644 --- a/HelloWorld/SearchResultsViewController.swift +++ b/HelloWorld/SearchResultsViewController.swift @@ -11,6 +11,7 @@ import UIKit class SearchResultsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, APIControllerProtocol { @IBOutlet var appsTableView : UITableView? + let kCellIdentifier: String = "SearchResultCell" var tableData = [] var api = APIController() @@ -43,7 +44,8 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa } func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { - let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell") + + let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(kCellIdentifier) as UITableViewCell let rowData: NSDictionary = self.tableData[indexPath.row] as NSDictionary @@ -64,6 +66,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() + } } From 16c9fcb4bcb8b1b89c45dbd5191f605709755b68 Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Sat, 26 Jul 2014 19:29:10 -0500 Subject: [PATCH 05/12] Part5 --- HelloWorld/Base.lproj/Main.storyboard | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HelloWorld/Base.lproj/Main.storyboard b/HelloWorld/Base.lproj/Main.storyboard index ed472a8..e65b9a4 100644 --- a/HelloWorld/Base.lproj/Main.storyboard +++ b/HelloWorld/Base.lproj/Main.storyboard @@ -55,7 +55,7 @@ - + From 547370d8e160a3c9c17341bd93490756fae35db1 Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Sat, 26 Jul 2014 20:02:23 -0500 Subject: [PATCH 06/12] Part5 --- HelloWorld/Blank52.png | Bin 0 -> 1471 bytes HelloWorld/SearchResultsViewController.swift | 52 +++++++++++++++--- MusicSearchTutorial.xcodeproj/project.pbxproj | 4 ++ 3 files changed, 47 insertions(+), 9 deletions(-) create mode 100644 HelloWorld/Blank52.png diff --git a/HelloWorld/Blank52.png b/HelloWorld/Blank52.png new file mode 100644 index 0000000000000000000000000000000000000000..c6ca077dd4ed6d1c8efe70a11c08036d1c9769b5 GIT binary patch literal 1471 zcmeAS@N?(olHy`uVBq!ia0vp^CLqkg1SGwrdiDS*$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWuD@%qp275hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|81#=KlDb#X~hD#E>34K5C;EJ)Q4 zN-fSWElLJPT$(b-ssbzLqSVBa{GyQj{2W*)24v)y-fM)1rW~NwK8d(}z8auifxR_WN8oHV|nV6V58#)`Ao0}RM zI5|1O^t$9Hm*%GCmB93-!1X#A;M5CB47mkBn_W_iGRsm^+=}vZ6~Lah%Eav!7o6rn z^`_u-i=!(}z4}1M=!2pbDXL*Y!1M!R!V@l#15f&?dBF5u1WedR_pMpPz`$ha>Eakt zaqG>Dz1~iN6365h%PhIz6uqcp)50Z-E^7X2nzq0(BQtx&|08YB?An%1TOe>q!K1lp z!2&5RZYM|WQ`Qn) z^Z)#;Vsv`ci7dgUGMy# zME+NseeY`Zev6n+ox0RFnunD9FMs!FS!{ZOUBt_%<)4;i{B60h>!{1-n|-!d z4&2`QRXFLTTxY|i%~R7vA{Tpm?uc19$3(67&i#jhK~q!i{m7qvJIjLWg;#&%j;kuu zIey)JzhZ{avNgFqN^(a6x~mF|t1GmUa+hpM3hvKcvSUv-Z&(cH>x)YstJ^GCo7e1b zbka?z?b*t}&QPPB^Jd!~`^0-`@v&O9-RGyC&^UkOgvz0r>XWZ}tzc^7KeAZ!VzJ5M zv?E!YndU7{i+=B7vEo?Y|J8Hti|$U84*s-8WtQWPyG*I7tbJM~3p`H-t7)}{2;PlT zeJICOQ~Y#Qppf3rQ|96SpMJP-%FaD1{P%_h-~TlU{mV|=`Y@zHdFhsdWm+*|kK13A oMdVsk*W7%3y6v}g!F(njhUx_hu|BircY}&lPgg&ebxsLQ0FHV%ivR!s literal 0 HcmV?d00001 diff --git a/HelloWorld/SearchResultsViewController.swift b/HelloWorld/SearchResultsViewController.swift index 5d3b451..57ce04d 100644 --- a/HelloWorld/SearchResultsViewController.swift +++ b/HelloWorld/SearchResultsViewController.swift @@ -14,6 +14,8 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa let kCellIdentifier: String = "SearchResultCell" var tableData = [] var api = APIController() + + var imageCache = [String : UIImage]() override func viewDidLoad() { @@ -47,21 +49,53 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(kCellIdentifier) as UITableViewCell - let rowData: NSDictionary = self.tableData[indexPath.row] as NSDictionary - - cell.textLabel.text = rowData["trackName"] as String + var rowData: NSDictionary = self.tableData[indexPath.row] as NSDictionary - // Grab the artworkUrl60 key to get an image URL for the app's thumbnail - let urlString: NSString = rowData["artworkUrl60"] as NSString - let imgURL: NSURL = NSURL(string: urlString) + // Add a check to make sure this exists + let cellText: String? = rowData["trackName"] as? String + cell.textLabel.text = cellText + cell.imageView.image = UIImage(named: "Blank52") - // Download an NSData representation of the image at the URL - let imgData: NSData = NSData(contentsOfURL: imgURL) - cell.imageView.image = UIImage(data: imgData) // Get the formatted price string for display in the subtitle let 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 + let 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 + var image = self.imageCache[urlString] + + 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 + 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? { + image = UIImage(data: data) + + // Store the image in to our cache + self.imageCache["urlString"] = image + cell.imageView.image = image + } + else { + println("Error: \(error.localizedDescription)") + } + }) + + } + else { + cell.imageView.image = image + } + }) + cell.detailTextLabel.text = formattedPrice return cell diff --git a/MusicSearchTutorial.xcodeproj/project.pbxproj b/MusicSearchTutorial.xcodeproj/project.pbxproj index 1d24a25..28d4ebb 100644 --- a/MusicSearchTutorial.xcodeproj/project.pbxproj +++ b/MusicSearchTutorial.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 024F8AC0198464AA00E9DEB8 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 024F8ABF198464AA00E9DEB8 /* Images.xcassets */; }; 024F8ACC198464AA00E9DEB8 /* HelloWorldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F8ACB198464AA00E9DEB8 /* HelloWorldTests.swift */; }; 024F8AD619846FC100E9DEB8 /* APIController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F8AD519846FC100E9DEB8 /* APIController.swift */; }; + 024F8AD8198482D000E9DEB8 /* Blank52.png in Resources */ = {isa = PBXBuildFile; fileRef = 024F8AD7198482D000E9DEB8 /* Blank52.png */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -36,6 +37,7 @@ 024F8ACA198464AA00E9DEB8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 024F8ACB198464AA00E9DEB8 /* HelloWorldTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelloWorldTests.swift; sourceTree = ""; }; 024F8AD519846FC100E9DEB8 /* APIController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIController.swift; sourceTree = ""; }; + 024F8AD7198482D000E9DEB8 /* Blank52.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Blank52.png; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -77,6 +79,7 @@ 024F8AB5198464AA00E9DEB8 /* MusicSearchTutorial */ = { isa = PBXGroup; children = ( + 024F8AD7198482D000E9DEB8 /* Blank52.png */, 024F8AB8198464AA00E9DEB8 /* AppDelegate.swift */, 024F8ABA198464AA00E9DEB8 /* SearchResultsViewController.swift */, 024F8ABC198464AA00E9DEB8 /* Main.storyboard */, @@ -194,6 +197,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 024F8AD8198482D000E9DEB8 /* Blank52.png in Resources */, 024F8ABE198464AA00E9DEB8 /* Main.storyboard in Resources */, 024F8AC0198464AA00E9DEB8 /* Images.xcassets in Resources */, ); From ad03a021029a8a13bd67c63a21be9cb799879a1b Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Sat, 26 Jul 2014 20:24:51 -0500 Subject: [PATCH 07/12] Part6 --- HelloWorld/APIController.swift | 8 ++++---- HelloWorld/SearchResultsViewController.swift | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/HelloWorld/APIController.swift b/HelloWorld/APIController.swift index 6ac1730..35584a4 100644 --- a/HelloWorld/APIController.swift +++ b/HelloWorld/APIController.swift @@ -14,10 +14,10 @@ protocol APIControllerProtocol { class APIController { - var delegate: APIControllerProtocol? + var delegate: APIControllerProtocol - init() { - + init(delegate: APIControllerProtocol) { + self.delegate = delegate } func searchItunesFor(searchTerm: String) { @@ -43,7 +43,7 @@ class APIController { println("JSON Error \(err!.localizedDescription)") } let results: NSArray = jsonResult["results"] as NSArray - self.delegate?.didReceiveAPIResults(jsonResult) // THIS IS THE NEW LINE!! + self.delegate.didReceiveAPIResults(jsonResult) // THIS IS THE NEW LINE!! }) task.resume() } diff --git a/HelloWorld/SearchResultsViewController.swift b/HelloWorld/SearchResultsViewController.swift index 57ce04d..3f8a68c 100644 --- a/HelloWorld/SearchResultsViewController.swift +++ b/HelloWorld/SearchResultsViewController.swift @@ -13,15 +13,15 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa @IBOutlet var appsTableView : UITableView? let kCellIdentifier: String = "SearchResultCell" var tableData = [] - var api = APIController() + var api : APIController? var imageCache = [String : UIImage]() override func viewDidLoad() { super.viewDidLoad() - self.api.delegate = self - api.searchItunesFor("Angry Birds") + self.api = APIController(delegate: self) + api!.searchItunesFor("Angry Birds") } override func didReceiveMemoryWarning() { From d8d7c615e526f59160faec37da6936f3d53458d2 Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Sat, 26 Jul 2014 20:27:18 -0500 Subject: [PATCH 08/12] Lazy api --- HelloWorld/SearchResultsViewController.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/HelloWorld/SearchResultsViewController.swift b/HelloWorld/SearchResultsViewController.swift index 3f8a68c..2f5905d 100644 --- a/HelloWorld/SearchResultsViewController.swift +++ b/HelloWorld/SearchResultsViewController.swift @@ -13,15 +13,14 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa @IBOutlet var appsTableView : UITableView? let kCellIdentifier: String = "SearchResultCell" var tableData = [] - var api : APIController? + lazy var api : APIController = APIController(delegate: self) var imageCache = [String : UIImage]() override func viewDidLoad() { super.viewDidLoad() - self.api = APIController(delegate: self) - api!.searchItunesFor("Angry Birds") + api.searchItunesFor("Angry Birds") } override func didReceiveMemoryWarning() { From 7a38913130a18594cc6bdf56ad4e1b4efe59c58e Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Sat, 26 Jul 2014 21:14:41 -0500 Subject: [PATCH 09/12] Part6 --- HelloWorld/APIController.swift | 2 +- HelloWorld/Album.swift | 73 +++++++++++++++++++ HelloWorld/Base.lproj/Main.storyboard | 73 ++++++++++++++++++- HelloWorld/DetailsViewController.swift | 25 +++++++ HelloWorld/SearchResultsViewController.swift | 43 +++++------ MusicSearchTutorial.xcodeproj/project.pbxproj | 8 ++ 6 files changed, 197 insertions(+), 27 deletions(-) create mode 100644 HelloWorld/Album.swift create mode 100644 HelloWorld/DetailsViewController.swift diff --git a/HelloWorld/APIController.swift b/HelloWorld/APIController.swift index 35584a4..d5b181b 100644 --- a/HelloWorld/APIController.swift +++ b/HelloWorld/APIController.swift @@ -27,7 +27,7 @@ class APIController { // Now escape anything else that isn't URL-friendly let escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) - let urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=software" + let urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=music&entity=album" let url: NSURL = NSURL(string: urlPath) let session = NSURLSession.sharedSession() let task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in diff --git a/HelloWorld/Album.swift b/HelloWorld/Album.swift new file mode 100644 index 0000000..21160b5 --- /dev/null +++ b/HelloWorld/Album.swift @@ -0,0 +1,73 @@ +// +// Album.swift +// MusicSearchTutorial +// +// Created by Jameson Quave on 7/26/14. +// Copyright (c) 2014 JQ Software. All rights reserved. +// + +import Foundation + +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 + } + + class func albumsWithJSON(allResults: NSArray) -> [Album] { + + // Create an empty array of Albums to append to from this list + var albums = [Album]() + + // Store the results in our table data array + if allResults.count>0 { + + // Sometimes iTunes returns a collection, not a track, so we check both for the 'name' + for result in allResults { + + var name = 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 = 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 = result["artworkUrl60"] as? String + let imageURL = result["artworkUrl100"] as? String + let artistURL = result["artistViewUrl"] as? String + + var itemURL = 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) + } + } + return albums + } +} \ No newline at end of file diff --git a/HelloWorld/Base.lproj/Main.storyboard b/HelloWorld/Base.lproj/Main.storyboard index e65b9a4..b16770b 100644 --- a/HelloWorld/Base.lproj/Main.storyboard +++ b/HelloWorld/Base.lproj/Main.storyboard @@ -1,5 +1,5 @@ - + @@ -39,6 +39,9 @@ + + + @@ -49,12 +52,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HelloWorld/DetailsViewController.swift b/HelloWorld/DetailsViewController.swift new file mode 100644 index 0000000..e15d2b0 --- /dev/null +++ b/HelloWorld/DetailsViewController.swift @@ -0,0 +1,25 @@ +// +// DetailsViewController.swift +// MusicSearchTutorial +// +// Created by Jameson Quave on 7/26/14. +// Copyright (c) 2014 JQ Software. All rights reserved. +// + +import UIKit +class DetailsViewController: UIViewController { + + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var albumCover: UIImageView! + 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/HelloWorld/SearchResultsViewController.swift b/HelloWorld/SearchResultsViewController.swift index 2f5905d..a01cccf 100644 --- a/HelloWorld/SearchResultsViewController.swift +++ b/HelloWorld/SearchResultsViewController.swift @@ -12,7 +12,8 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa @IBOutlet var appsTableView : UITableView? let kCellIdentifier: String = "SearchResultCell" - var tableData = [] + var albums = [Album]() + lazy var api : APIController = APIController(delegate: self) var imageCache = [String : UIImage]() @@ -20,7 +21,8 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa override func viewDidLoad() { super.viewDidLoad() - api.searchItunesFor("Angry Birds") + UIApplication.sharedApplication().networkActivityIndicatorVisible = true + api.searchItunesFor("Bob Dylan"); } override func didReceiveMemoryWarning() { @@ -33,37 +35,34 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa func didReceiveAPIResults(results: NSDictionary) { var resultsArr: NSArray = results["results"] as NSArray dispatch_async(dispatch_get_main_queue(), { - self.tableData = resultsArr + self.albums = Album.albumsWithJSON(resultsArr) self.appsTableView!.reloadData() - }) + UIApplication.sharedApplication().networkActivityIndicatorVisible = false + }) } // The protocol methods for UITableViewDataSource and UITableViewDelegate func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int { - return tableData.count + return albums.count } func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(kCellIdentifier) as UITableViewCell - 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.textLabel.text = cellText + let album = self.albums[indexPath.row] + cell.textLabel.text = album.title cell.imageView.image = UIImage(named: "Blank52") - // Get the formatted price string for display in the subtitle - let formattedPrice: NSString = rowData["formattedPrice"] as NSString + let formattedPrice = 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 - let 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 @@ -100,18 +99,12 @@ 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() + + 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 } } diff --git a/MusicSearchTutorial.xcodeproj/project.pbxproj b/MusicSearchTutorial.xcodeproj/project.pbxproj index 28d4ebb..fa94b84 100644 --- a/MusicSearchTutorial.xcodeproj/project.pbxproj +++ b/MusicSearchTutorial.xcodeproj/project.pbxproj @@ -14,6 +14,8 @@ 024F8ACC198464AA00E9DEB8 /* HelloWorldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F8ACB198464AA00E9DEB8 /* HelloWorldTests.swift */; }; 024F8AD619846FC100E9DEB8 /* APIController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F8AD519846FC100E9DEB8 /* APIController.swift */; }; 024F8AD8198482D000E9DEB8 /* Blank52.png in Resources */ = {isa = PBXBuildFile; fileRef = 024F8AD7198482D000E9DEB8 /* Blank52.png */; }; + 024F8ADA19848E1E00E9DEB8 /* Album.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F8AD919848E1E00E9DEB8 /* Album.swift */; }; + 024F8ADC1984946C00E9DEB8 /* DetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F8ADB1984946C00E9DEB8 /* DetailsViewController.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -38,6 +40,8 @@ 024F8ACB198464AA00E9DEB8 /* HelloWorldTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelloWorldTests.swift; sourceTree = ""; }; 024F8AD519846FC100E9DEB8 /* APIController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIController.swift; sourceTree = ""; }; 024F8AD7198482D000E9DEB8 /* Blank52.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Blank52.png; sourceTree = ""; }; + 024F8AD919848E1E00E9DEB8 /* Album.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = ""; }; + 024F8ADB1984946C00E9DEB8 /* DetailsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailsViewController.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -86,6 +90,8 @@ 024F8ABF198464AA00E9DEB8 /* Images.xcassets */, 024F8AB6198464AA00E9DEB8 /* Supporting Files */, 024F8AD519846FC100E9DEB8 /* APIController.swift */, + 024F8AD919848E1E00E9DEB8 /* Album.swift */, + 024F8ADB1984946C00E9DEB8 /* DetailsViewController.swift */, ); name = MusicSearchTutorial; path = HelloWorld; @@ -220,6 +226,8 @@ 024F8ABB198464AA00E9DEB8 /* SearchResultsViewController.swift in Sources */, 024F8AB9198464AA00E9DEB8 /* AppDelegate.swift in Sources */, 024F8AD619846FC100E9DEB8 /* APIController.swift in Sources */, + 024F8ADA19848E1E00E9DEB8 /* Album.swift in Sources */, + 024F8ADC1984946C00E9DEB8 /* DetailsViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 1a9c117fdc1b7b1080f594920614280c82410fc4 Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Sun, 27 Jul 2014 08:34:07 -0500 Subject: [PATCH 10/12] Part7 --- HelloWorld/APIController.swift | 28 ++++--- HelloWorld/Album.swift | 7 +- HelloWorld/Base.lproj/Main.storyboard | 78 ++++++++++++++++--- HelloWorld/DetailsViewController.swift | 59 +++++++++++++- HelloWorld/SearchResultsViewController.swift | 9 ++- HelloWorld/Track.swift | 57 ++++++++++++++ HelloWorld/TrackCell.swift | 14 ++++ MusicSearchTutorial.xcodeproj/project.pbxproj | 10 +++ 8 files changed, 238 insertions(+), 24 deletions(-) create mode 100644 HelloWorld/Track.swift create mode 100644 HelloWorld/TrackCell.swift diff --git a/HelloWorld/APIController.swift b/HelloWorld/APIController.swift index d5b181b..5e9323f 100644 --- a/HelloWorld/APIController.swift +++ b/HelloWorld/APIController.swift @@ -20,15 +20,8 @@ class APIController { self.delegate = delegate } - func searchItunesFor(searchTerm: String) { - - // The iTunes API wants multiple terms separated by + symbols, so replace spaces with + signs - let itunesSearchTerm = searchTerm.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil) - - // 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 = NSURL(string: urlPath) + 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") @@ -43,9 +36,24 @@ class APIController { println("JSON Error \(err!.localizedDescription)") } let results: NSArray = jsonResult["results"] as NSArray - self.delegate.didReceiveAPIResults(jsonResult) // THIS IS THE NEW LINE!! + self.delegate.didReceiveAPIResults(jsonResult) }) task.resume() } + + func searchItunesFor(searchTerm: String) { + + // The iTunes API wants multiple terms separated by + symbols, so replace spaces with + signs + let itunesSearchTerm = searchTerm.stringByReplacingOccurrencesOfString(" ", withString: "+", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil) + + // 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" + get(urlPath) + } + + func lookupAlbum(collectionId: Int) { + get("https://itunes.apple.com/lookup?id=\(collectionId)&entity=song") + } } \ No newline at end of file diff --git a/HelloWorld/Album.swift b/HelloWorld/Album.swift index 21160b5..46ebf29 100644 --- a/HelloWorld/Album.swift +++ b/HelloWorld/Album.swift @@ -15,14 +15,16 @@ 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 } class func albumsWithJSON(allResults: NSArray) -> [Album] { @@ -64,7 +66,8 @@ class Album { 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) } } diff --git a/HelloWorld/Base.lproj/Main.storyboard b/HelloWorld/Base.lproj/Main.storyboard index b16770b..19eea4a 100644 --- a/HelloWorld/Base.lproj/Main.storyboard +++ b/HelloWorld/Base.lproj/Main.storyboard @@ -73,42 +73,100 @@ - + + + - + diff --git a/HelloWorld/DetailsViewController.swift b/HelloWorld/DetailsViewController.swift index e15d2b0..3715602 100644 --- a/HelloWorld/DetailsViewController.swift +++ b/HelloWorld/DetailsViewController.swift @@ -7,12 +7,19 @@ // import UIKit -class DetailsViewController: UIViewController { +import MediaPlayer +import QuartzCore +class DetailsViewController: UIViewController, APIControllerProtocol { + var mediaPlayer: MPMoviePlayerController = MPMoviePlayerController() + @IBOutlet weak var detailsTrackView: UITableView! @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var albumCover: UIImageView! var album: Album? + var tracks = [Track]() + lazy var api : APIController = APIController(delegate: self) + init(coder aDecoder: NSCoder!) { super.init(coder: aDecoder) } @@ -21,5 +28,55 @@ 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? { + api.lookupAlbum(self.album!.collectionId) + } + } + + + // MARK: APIControllerProtocol + func didReceiveAPIResults(results: NSDictionary) { + var resultsArr: NSArray = results["results"] as NSArray + dispatch_async(dispatch_get_main_queue(), { + self.tracks = Track.tracksWithJSON(resultsArr) + self.detailsTrackView.reloadData() + UIApplication.sharedApplication().networkActivityIndicatorVisible = false + }) + } + + // UITableViewDataSource + 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 = "⬛️" + } } + + 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/HelloWorld/SearchResultsViewController.swift b/HelloWorld/SearchResultsViewController.swift index a01cccf..827f7b9 100644 --- a/HelloWorld/SearchResultsViewController.swift +++ b/HelloWorld/SearchResultsViewController.swift @@ -7,7 +7,7 @@ // import UIKit - +import QuartzCore class SearchResultsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, APIControllerProtocol { @IBOutlet var appsTableView : UITableView? @@ -99,6 +99,13 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa return cell } + 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) + }) + } + override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject) { var detailsViewController: DetailsViewController = segue.destinationViewController as DetailsViewController diff --git a/HelloWorld/Track.swift b/HelloWorld/Track.swift new file mode 100644 index 0000000..63c5ab3 --- /dev/null +++ b/HelloWorld/Track.swift @@ -0,0 +1,57 @@ +// +// Track.swift +// MusicSearchTutorial +// +// Created by Jameson Quave on 7/27/14. +// Copyright (c) 2014 JQ Software. All rights reserved. +// + +import Foundation +class Track { + + var title: String + var price: String + var previewUrl: String + + init(title: String, price: String, previewUrl: String) { + self.title = title + self.price = price + self.previewUrl = previewUrl + } + + class func tracksWithJSON(allResults: NSArray) -> [Track] { + + var tracks = [Track]() + + if allResults.count>0 { + for trackInfo in allResults { + // Create the track + if let kind = trackInfo["kind"] as? String { + if kind=="song" { + + var trackPrice = trackInfo["trackPrice"] as? String + var trackTitle = trackInfo["trackName"] as? String + var trackPreviewUrl = trackInfo["previewUrl"] as? String + + if(!trackTitle) { + trackTitle = "Unknown" + } + else if(!trackPrice) { + println("No trackPrice in \(trackInfo)") + trackPrice = "?" + } + else if(!trackPreviewUrl) { + trackPreviewUrl = "" + } + + var track = Track(title: trackTitle!, price: trackPrice!, previewUrl: trackPreviewUrl!) + tracks.append(track) + + } + } + } + } + return tracks + } + +} diff --git a/HelloWorld/TrackCell.swift b/HelloWorld/TrackCell.swift new file mode 100644 index 0000000..e7121b8 --- /dev/null +++ b/HelloWorld/TrackCell.swift @@ -0,0 +1,14 @@ +// +// TrackCell.swift +// MusicSearchTutorial +// +// Created by Jameson Quave on 7/27/14. +// Copyright (c) 2014 JQ Software. All rights reserved. +// + +import UIKit + +class TrackCell: UITableViewCell { + @IBOutlet weak var playIcon: UILabel! + @IBOutlet weak var titleLabel: UILabel! +} diff --git a/MusicSearchTutorial.xcodeproj/project.pbxproj b/MusicSearchTutorial.xcodeproj/project.pbxproj index fa94b84..142758e 100644 --- a/MusicSearchTutorial.xcodeproj/project.pbxproj +++ b/MusicSearchTutorial.xcodeproj/project.pbxproj @@ -16,6 +16,8 @@ 024F8AD8198482D000E9DEB8 /* Blank52.png in Resources */ = {isa = PBXBuildFile; fileRef = 024F8AD7198482D000E9DEB8 /* Blank52.png */; }; 024F8ADA19848E1E00E9DEB8 /* Album.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F8AD919848E1E00E9DEB8 /* Album.swift */; }; 024F8ADC1984946C00E9DEB8 /* DetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F8ADB1984946C00E9DEB8 /* DetailsViewController.swift */; }; + 024F8ADE19852C0200E9DEB8 /* Track.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F8ADD19852C0200E9DEB8 /* Track.swift */; }; + 024F8AE0198532B800E9DEB8 /* TrackCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 024F8ADF198532B800E9DEB8 /* TrackCell.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -42,6 +44,8 @@ 024F8AD7198482D000E9DEB8 /* Blank52.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Blank52.png; sourceTree = ""; }; 024F8AD919848E1E00E9DEB8 /* Album.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = ""; }; 024F8ADB1984946C00E9DEB8 /* DetailsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailsViewController.swift; sourceTree = ""; }; + 024F8ADD19852C0200E9DEB8 /* Track.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Track.swift; sourceTree = ""; }; + 024F8ADF198532B800E9DEB8 /* TrackCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrackCell.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -92,6 +96,8 @@ 024F8AD519846FC100E9DEB8 /* APIController.swift */, 024F8AD919848E1E00E9DEB8 /* Album.swift */, 024F8ADB1984946C00E9DEB8 /* DetailsViewController.swift */, + 024F8ADD19852C0200E9DEB8 /* Track.swift */, + 024F8ADF198532B800E9DEB8 /* TrackCell.swift */, ); name = MusicSearchTutorial; path = HelloWorld; @@ -223,11 +229,13 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 024F8AE0198532B800E9DEB8 /* TrackCell.swift in Sources */, 024F8ABB198464AA00E9DEB8 /* SearchResultsViewController.swift in Sources */, 024F8AB9198464AA00E9DEB8 /* AppDelegate.swift in Sources */, 024F8AD619846FC100E9DEB8 /* APIController.swift in Sources */, 024F8ADA19848E1E00E9DEB8 /* Album.swift in Sources */, 024F8ADC1984946C00E9DEB8 /* DetailsViewController.swift in Sources */, + 024F8ADE19852C0200E9DEB8 /* Track.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -413,6 +421,7 @@ 024F8AD1198464AA00E9DEB8 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; 024F8AD2198464AA00E9DEB8 /* Build configuration list for PBXNativeTarget "MusicSearchTutorialTests" */ = { isa = XCConfigurationList; @@ -421,6 +430,7 @@ 024F8AD4198464AA00E9DEB8 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; From 69a1309161ec8346520ad9eca217fd2881378801 Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Mon, 28 Jul 2014 14:45:34 -0500 Subject: [PATCH 11/12] Part7 --- HelloWorld/DetailsViewController.swift | 1 + HelloWorld/SearchResultsViewController.swift | 13 ++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/HelloWorld/DetailsViewController.swift b/HelloWorld/DetailsViewController.swift index 3715602..38c2ecb 100644 --- a/HelloWorld/DetailsViewController.swift +++ b/HelloWorld/DetailsViewController.swift @@ -52,6 +52,7 @@ class DetailsViewController: UIViewController, APIControllerProtocol { } func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { + var cell = tableView.dequeueReusableCellWithIdentifier("TrackCell") as TrackCell var track = tracks[indexPath.row] diff --git a/HelloWorld/SearchResultsViewController.swift b/HelloWorld/SearchResultsViewController.swift index 827f7b9..e389e42 100644 --- a/HelloWorld/SearchResultsViewController.swift +++ b/HelloWorld/SearchResultsViewController.swift @@ -80,8 +80,11 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa image = UIImage(data: data) // Store the image in to our cache - self.imageCache["urlString"] = image - cell.imageView.image = image + self.imageCache[urlString] = image + + if let cellToUpdate = tableView.cellForRowAtIndexPath(indexPath) { + cell.imageView.image = image + } } else { println("Error: \(error.localizedDescription)") @@ -90,7 +93,11 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa } else { - cell.imageView.image = image + dispatch_async(dispatch_get_main_queue(), { + if let cellToUpdate = tableView.cellForRowAtIndexPath(indexPath) { + cell.imageView.image = image + } + }) } }) From 3de15c402f70bb8c9296a562059eb3e63d6fe037 Mon Sep 17 00:00:00 2001 From: Jameson Quave Date: Mon, 4 Aug 2014 23:02:16 -0500 Subject: [PATCH 12/12] Part 7 --- HelloWorld/APIController.swift | 2 +- HelloWorld/Album.swift | 10 +++++----- HelloWorld/DetailsViewController.swift | 4 ++-- HelloWorld/SearchResultsViewController.swift | 4 ++-- HelloWorld/Track.swift | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/HelloWorld/APIController.swift b/HelloWorld/APIController.swift index 5e9323f..3845acf 100644 --- a/HelloWorld/APIController.swift +++ b/HelloWorld/APIController.swift @@ -31,7 +31,7 @@ class APIController { } var err: NSError? var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as NSDictionary - if(err?) { + if(err != nil) { // If there is an error parsing JSON, print it to the console println("JSON Error \(err!.localizedDescription)") } diff --git a/HelloWorld/Album.swift b/HelloWorld/Album.swift index 46ebf29..be1d15c 100644 --- a/HelloWorld/Album.swift +++ b/HelloWorld/Album.swift @@ -39,19 +39,19 @@ class Album { for result in allResults { var name = result["trackName"] as? String - if !name? { + if name == nil { 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 = result["formattedPrice"] as? String - if !price? { + if price == nil { price = result["collectionPrice"] as? String - if !price? { + if price == nil { var priceFloat: Float? = result["collectionPrice"] as? Float var nf: NSNumberFormatter = NSNumberFormatter() nf.maximumFractionDigits = 2; - if priceFloat? { + if priceFloat != nil { price = "$"+nf.stringFromNumber(priceFloat) } } @@ -62,7 +62,7 @@ class Album { let artistURL = result["artistViewUrl"] as? String var itemURL = result["collectionViewUrl"] as? String - if !itemURL? { + if itemURL == nil { itemURL = result["trackViewUrl"] as? String } diff --git a/HelloWorld/DetailsViewController.swift b/HelloWorld/DetailsViewController.swift index 38c2ecb..b429d39 100644 --- a/HelloWorld/DetailsViewController.swift +++ b/HelloWorld/DetailsViewController.swift @@ -20,7 +20,7 @@ class DetailsViewController: UIViewController, APIControllerProtocol { var tracks = [Track]() lazy var api : APIController = APIController(delegate: self) - init(coder aDecoder: NSCoder!) { + required init(coder aDecoder: NSCoder!) { super.init(coder: aDecoder) } @@ -30,7 +30,7 @@ class DetailsViewController: UIViewController, APIControllerProtocol { albumCover.image = UIImage(data: NSData(contentsOfURL: NSURL(string: self.album?.largeImageURL))) // Load in tracks - if self.album? { + if self.album != nil { api.lookupAlbum(self.album!.collectionId) } } diff --git a/HelloWorld/SearchResultsViewController.swift b/HelloWorld/SearchResultsViewController.swift index e389e42..11b731d 100644 --- a/HelloWorld/SearchResultsViewController.swift +++ b/HelloWorld/SearchResultsViewController.swift @@ -68,7 +68,7 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa //var image: UIImage? = self.imageCache.valueForKey(urlString) as? UIImage var image = self.imageCache[urlString] - if( !image? ) { + if( image == nil ) { // If the image does not exist, we need to download it var imgURL: NSURL = NSURL(string: urlString) @@ -76,7 +76,7 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa 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? { + if error == nil { image = UIImage(data: data) // Store the image in to our cache diff --git a/HelloWorld/Track.swift b/HelloWorld/Track.swift index 63c5ab3..e1f0c8a 100644 --- a/HelloWorld/Track.swift +++ b/HelloWorld/Track.swift @@ -33,14 +33,14 @@ class Track { var trackTitle = trackInfo["trackName"] as? String var trackPreviewUrl = trackInfo["previewUrl"] as? String - if(!trackTitle) { + if(trackTitle == nil) { trackTitle = "Unknown" } - else if(!trackPrice) { + else if(trackPrice == nil) { println("No trackPrice in \(trackInfo)") trackPrice = "?" } - else if(!trackPreviewUrl) { + else if(trackPreviewUrl == nil) { trackPreviewUrl = "" }