diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..5008ddf
Binary files /dev/null and b/.DS_Store differ
diff --git a/1 - Prelude/.DS_Store b/1 - Prelude/.DS_Store
new file mode 100644
index 0000000..7d3b065
Binary files /dev/null and b/1 - Prelude/.DS_Store differ
diff --git a/1 - Prelude/1 - GettingStarted.playground/contents.xcplayground b/1 - Prelude/1 - GettingStarted.playground/contents.xcplayground
new file mode 100644
index 0000000..8e39341
--- /dev/null
+++ b/1 - Prelude/1 - GettingStarted.playground/contents.xcplayground
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/1 - Prelude/1 - GettingStarted.playground/section-1.swift b/1 - Prelude/1 - GettingStarted.playground/section-1.swift
new file mode 100644
index 0000000..36d57ab
--- /dev/null
+++ b/1 - Prelude/1 - GettingStarted.playground/section-1.swift
@@ -0,0 +1,37 @@
+
+// Declaring Variables
+var myVariable = "I can change" // -> No more semicolons (unless you want multiple statements on one line)
+
+// Declaring Constants
+let myConstant = "I'm constant"
+// myConstant = "Try me" // -> Error: cannot reassign a constant
+
+// Notice we aren't declaring a type -> Type Inference
+// Try option + clicking a variable or constant to see its type
+
+// Specifying a Type
+let myString: String = "a string" // -> No Longer need @ prefix for strings
+let myInteger: Int = 100
+let myDouble: Double = 1.234
+let myBool: Bool = true
+let myArray: Array = ["string 1", "string 2"] // -> Infers contained types
+let myIntArray: [Int] = [1, 2]
+let myDictionary: Dictionary = ["key":"value"] // -> Infers contained types
+let myIntDictionary: [Int:Int] = [1:2, 3:4]
+
+// Variables and Constants in Swift cannot be nil
+// var nilVariable = nil // -> Error: cannot be nil
+// let nilConstant = nil
+
+// String Interpolation
+let stringWithVariable = "Look at me, \(myVariable)"
+
+// Concatenate Strings
+let twoStrings = "String 1 and " + "String 2"
+
+// Logging
+print(stringWithVariable)
+println(twoStrings) // -> Adds a newline, more commonly used
+
+// In Swift we access methods and properties with dot syntax
+twoStrings.isEmpty
diff --git a/1 - Prelude/1 - GettingStarted.playground/timeline.xctimeline b/1 - Prelude/1 - GettingStarted.playground/timeline.xctimeline
new file mode 100644
index 0000000..bf468af
--- /dev/null
+++ b/1 - Prelude/1 - GettingStarted.playground/timeline.xctimeline
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/1 - Prelude/2 - Strings.playground/contents.xcplayground b/1 - Prelude/2 - Strings.playground/contents.xcplayground
new file mode 100644
index 0000000..8e39341
--- /dev/null
+++ b/1 - Prelude/2 - Strings.playground/contents.xcplayground
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/1 - Prelude/2 - Strings.playground/section-1.swift b/1 - Prelude/2 - Strings.playground/section-1.swift
new file mode 100644
index 0000000..f980c01
--- /dev/null
+++ b/1 - Prelude/2 - Strings.playground/section-1.swift
@@ -0,0 +1,16 @@
+// Playground - noun: a place where people can play
+
+import UIKit
+
+// We no longer need @
+let string1 = "Game Over"
+let string2 = " Man"
+// We can concatenate strings easily
+let combinedString = string1 + string2
+
+var quote = "Game Over ".stringByAppendingString("Man")
+quote += ", Game Over!"
+println(quote.capitalizedString)
+
+// String Interpolation
+let interpolatedString = "\(combinedString), Game Over!"
diff --git a/1 - Prelude/2 - Strings.playground/timeline.xctimeline b/1 - Prelude/2 - Strings.playground/timeline.xctimeline
new file mode 100644
index 0000000..bf468af
--- /dev/null
+++ b/1 - Prelude/2 - Strings.playground/timeline.xctimeline
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/1 - Prelude/3 - Numerics.playground/contents.xcplayground b/1 - Prelude/3 - Numerics.playground/contents.xcplayground
new file mode 100644
index 0000000..8e39341
--- /dev/null
+++ b/1 - Prelude/3 - Numerics.playground/contents.xcplayground
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/1 - Prelude/3 - Numerics.playground/section-1.swift b/1 - Prelude/3 - Numerics.playground/section-1.swift
new file mode 100644
index 0000000..cb6a83a
--- /dev/null
+++ b/1 - Prelude/3 - Numerics.playground/section-1.swift
@@ -0,0 +1,45 @@
+// Playground - noun: a place where people can play
+
+import UIKit
+
+let crewMembers = 4 // Type Int
+let lightyearsAway = 1.234 // Type Double
+
+// Tip: Underscores can be used as thousands separator
+let aMillionCredits = 1000000
+let aCoolMillionCredits = 1_000_000
+
+// Arithmetic
+10 + 10 // Addition
+10 - 10 // Subtraction
+10 * 10 // Multiplication
+10 / 10 // Division
+10 % 10 // Remainder
+
+// Numeric conversions must be explicit
+
+let integer = 10
+let double = 1.234
+
+//let result = integer * double // Error: needs a type
+let doubleResult = Double(integer) * double
+let integerResult = integer * Int(double)
+
+// Compound Operations
+var compound = 10
+compound += 10 // compound = compound + 10
+compound -= 10
+compound *= 10
+compound /= 10
+compound %= 10
+
+// Unary Operations
+var unary = 10
+
+// Prefix
+++unary
+--unary
+
+// Postfix
+unary++
+unary--
diff --git a/1 - Prelude/3 - Numerics.playground/timeline.xctimeline b/1 - Prelude/3 - Numerics.playground/timeline.xctimeline
new file mode 100644
index 0000000..bf468af
--- /dev/null
+++ b/1 - Prelude/3 - Numerics.playground/timeline.xctimeline
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/1 - Prelude/4 - Booleans.playground/contents.xcplayground b/1 - Prelude/4 - Booleans.playground/contents.xcplayground
new file mode 100644
index 0000000..8e39341
--- /dev/null
+++ b/1 - Prelude/4 - Booleans.playground/contents.xcplayground
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/1 - Prelude/4 - Booleans.playground/section-1.swift b/1 - Prelude/4 - Booleans.playground/section-1.swift
new file mode 100644
index 0000000..b59b5ff
--- /dev/null
+++ b/1 - Prelude/4 - Booleans.playground/section-1.swift
@@ -0,0 +1,19 @@
+// Playground - noun: a place where people can play
+
+import UIKit
+
+let theCake = false
+
+// Only accepts true/false
+let theCake = YES // Error
+let theCake = TRUE // Error
+
+// Only Booleans can be true/false
+var myString = "The Cake is a Lie"
+myString == true // Error
+if myString {
+ // Error
+}
+
+var myInt = 1
+myInt == true // Error
diff --git a/1 - Prelude/4 - Booleans.playground/timeline.xctimeline b/1 - Prelude/4 - Booleans.playground/timeline.xctimeline
new file mode 100644
index 0000000..bf468af
--- /dev/null
+++ b/1 - Prelude/4 - Booleans.playground/timeline.xctimeline
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/1 - Prelude/5 - Collections.playground/contents.xcplayground b/1 - Prelude/5 - Collections.playground/contents.xcplayground
new file mode 100644
index 0000000..8e39341
--- /dev/null
+++ b/1 - Prelude/5 - Collections.playground/contents.xcplayground
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/1 - Prelude/5 - Collections.playground/section-1.swift b/1 - Prelude/5 - Collections.playground/section-1.swift
new file mode 100644
index 0000000..f887a34
--- /dev/null
+++ b/1 - Prelude/5 - Collections.playground/section-1.swift
@@ -0,0 +1,37 @@
+// Playground - noun: a place where people can play
+
+import UIKit
+
+// Arrays
+var characters = ["Luke Skywalker", "Anakin Skywalker"]
+characters[1] = "Darth Vader"
+
+// Easy concatenate
+let moreCharacters = ["C3PO", "R2D2"]
+characters += moreCharacters
+
+// Methods
+characters.append("Han Solo")
+characters.insert("Princess Leia", atIndex: 0)
+characters.removeAtIndex(1)
+
+characters.count
+characters.isEmpty
+characters.first
+characters.last
+
+// Dictionaries
+var professions = ["Boba Fett": "Bounty Hunter", "Han Solo": "Smuggler"]
+
+// Access with key
+professions["Han Solo"]
+
+// Add with key
+professions["Darth Vader"] = "Sith Lord"
+
+// Methods
+professions.removeValueForKey("Han Solo")
+professions.updateValue("Boba Fett", forKey: "Sarlac Food")
+
+professions.count
+professions.isEmpty
\ No newline at end of file
diff --git a/1 - Prelude/5 - Collections.playground/timeline.xctimeline b/1 - Prelude/5 - Collections.playground/timeline.xctimeline
new file mode 100644
index 0000000..bf468af
--- /dev/null
+++ b/1 - Prelude/5 - Collections.playground/timeline.xctimeline
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/1 - Prelude/6 - ControlFlow.playground/contents.xcplayground b/1 - Prelude/6 - ControlFlow.playground/contents.xcplayground
new file mode 100644
index 0000000..8e39341
--- /dev/null
+++ b/1 - Prelude/6 - ControlFlow.playground/contents.xcplayground
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/1 - Prelude/6 - ControlFlow.playground/section-1.swift b/1 - Prelude/6 - ControlFlow.playground/section-1.swift
new file mode 100644
index 0000000..96e247c
--- /dev/null
+++ b/1 - Prelude/6 - ControlFlow.playground/section-1.swift
@@ -0,0 +1,61 @@
+// Playground - noun: a place where people can play
+
+import UIKit
+
+// Loops
+for i in 1...3 {
+ println("O'doyle Rules")
+}
+
+var range = Range(start: 1, end: 4)
+
+var i = 0
+while i < 5 {
+ println("O'doyle Rules")
+ i++
+}
+
+let oceans = ["George Clooney", "Brad Pitt", "Matt Damon"]
+
+for actor in oceans {
+ println(actor)
+ i++
+}
+
+// If/else
+let enemyType = "Aliens"
+
+if enemyType == "Wraith" {
+ println("Use Fire")
+} else if enemyType == "Werewolf" {
+ println("Use Silver")
+} else {
+ println("Nuke it from orbit")
+}
+
+// Comparison Operators
+// == equal
+// != not equal
+// > greater than
+// < less than
+// >= greater or equal
+// <= less or equal
+
+// Logical Operators
+// ! Not (invert)
+// && And
+// || Or
+
+// Switches
+let hero = "Thor"
+
+switch hero {
+case "Thor":
+ println("Asguard")
+case "Iron Man", "Captain America":
+ println("New York, NY")
+case "Hawkeye":
+ println("Waverly, Iowa")
+default:
+ println("Unknown")
+}
\ No newline at end of file
diff --git a/1 - Prelude/6 - ControlFlow.playground/timeline.xctimeline b/1 - Prelude/6 - ControlFlow.playground/timeline.xctimeline
new file mode 100644
index 0000000..bf468af
--- /dev/null
+++ b/1 - Prelude/6 - ControlFlow.playground/timeline.xctimeline
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/2 - Act I/.DS_Store b/2 - Act I/.DS_Store
new file mode 100644
index 0000000..f81e049
Binary files /dev/null and b/2 - Act I/.DS_Store differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/.DS_Store b/2 - Act I/1 - Starting Project/SwiftMovies/.DS_Store
new file mode 100644
index 0000000..59b421f
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/.DS_Store differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..02bd8c2
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj
@@ -0,0 +1,474 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ F45D76761A5FD9FE001807F2 /* SwiftyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */; };
+ F4646C331A5DF40800336DFC /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4646C321A5DF40800336DFC /* SettingsViewController.swift */; };
+ F4678DB91A5A82F1005A33DE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DB81A5A82F1005A33DE /* AppDelegate.swift */; };
+ F4678DC01A5A82F1005A33DE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F4678DBE1A5A82F1005A33DE /* Main.storyboard */; };
+ F4678DC21A5A82F1005A33DE /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F4678DC11A5A82F1005A33DE /* Images.xcassets */; };
+ F4678DC51A5A82F1005A33DE /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */; };
+ F4678DD11A5A82F1005A33DE /* SwiftMoviesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */; };
+ F4678DE11A5A9582005A33DE /* Movie.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DE01A5A9582005A33DE /* Movie.swift */; };
+ F477D6AE1A5F20E2006FD97E /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */; };
+ F477D6B21A5F20FF006FD97E /* FilterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F477D6B11A5F20FF006FD97E /* FilterViewController.swift */; };
+ F49C6F8A1A5F47B200D0C49E /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F49C6F891A5F47B200D0C49E /* WebViewController.swift */; };
+ F4DC98D01A5E5B0C0030CC99 /* CollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */; };
+ F4DC98D21A5E6B460030CC99 /* TMDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4DC98D11A5E6B460030CC99 /* TMDB.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ F4678DCB1A5A82F1005A33DE /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = F4678DAB1A5A82F1005A33DE /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F4678DB21A5A82F1005A33DE;
+ remoteInfo = SwiftMovies;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyJSON.swift; sourceTree = ""; };
+ F4646C321A5DF40800336DFC /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; };
+ F4678DB31A5A82F1005A33DE /* SwiftMovies.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftMovies.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ F4678DB71A5A82F1005A33DE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ F4678DB81A5A82F1005A33DE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ F4678DBF1A5A82F1005A33DE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
+ F4678DC11A5A82F1005A33DE /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
+ F4678DC41A5A82F1005A33DE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
+ F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftMoviesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ F4678DCF1A5A82F1005A33DE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftMoviesTests.swift; sourceTree = ""; };
+ F4678DE01A5A9582005A33DE /* Movie.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Movie.swift; sourceTree = ""; };
+ F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; };
+ F477D6B11A5F20FF006FD97E /* FilterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilterViewController.swift; sourceTree = ""; };
+ F49C6F891A5F47B200D0C49E /* WebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebViewController.swift; sourceTree = ""; };
+ F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewController.swift; sourceTree = ""; };
+ F4DC98D11A5E6B460030CC99 /* TMDB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TMDB.swift; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ F4678DB01A5A82F1005A33DE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC71A5A82F1005A33DE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ F4678DAA1A5A82F1005A33DE = {
+ isa = PBXGroup;
+ children = (
+ F4678DB51A5A82F1005A33DE /* SwiftMovies */,
+ F4678DCD1A5A82F1005A33DE /* SwiftMoviesTests */,
+ F4678DB41A5A82F1005A33DE /* Products */,
+ );
+ sourceTree = "";
+ };
+ F4678DB41A5A82F1005A33DE /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DB31A5A82F1005A33DE /* SwiftMovies.app */,
+ F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ F4678DB51A5A82F1005A33DE /* SwiftMovies */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DB81A5A82F1005A33DE /* AppDelegate.swift */,
+ F4678DC11A5A82F1005A33DE /* Images.xcassets */,
+ F477D6AA1A5F209D006FD97E /* Controllers */,
+ F477D6B31A5F210F006FD97E /* Models */,
+ F477D6B71A5F215E006FD97E /* Networking */,
+ F4678DBE1A5A82F1005A33DE /* Main.storyboard */,
+ F4678DB61A5A82F1005A33DE /* Supporting Files */,
+ );
+ path = SwiftMovies;
+ sourceTree = "";
+ };
+ F4678DB61A5A82F1005A33DE /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */,
+ F4678DB71A5A82F1005A33DE /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ F4678DCD1A5A82F1005A33DE /* SwiftMoviesTests */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */,
+ F4678DCE1A5A82F1005A33DE /* Supporting Files */,
+ );
+ path = SwiftMoviesTests;
+ sourceTree = "";
+ };
+ F4678DCE1A5A82F1005A33DE /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DCF1A5A82F1005A33DE /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ F477D6AA1A5F209D006FD97E /* Controllers */ = {
+ isa = PBXGroup;
+ children = (
+ F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */,
+ F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */,
+ F477D6B11A5F20FF006FD97E /* FilterViewController.swift */,
+ F4646C321A5DF40800336DFC /* SettingsViewController.swift */,
+ F49C6F891A5F47B200D0C49E /* WebViewController.swift */,
+ );
+ name = Controllers;
+ sourceTree = "";
+ };
+ F477D6B31A5F210F006FD97E /* Models */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DE01A5A9582005A33DE /* Movie.swift */,
+ );
+ name = Models;
+ sourceTree = "";
+ };
+ F477D6B71A5F215E006FD97E /* Networking */ = {
+ isa = PBXGroup;
+ children = (
+ F4DC98D11A5E6B460030CC99 /* TMDB.swift */,
+ F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */,
+ );
+ name = Networking;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ F4678DB21A5A82F1005A33DE /* SwiftMovies */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F4678DD41A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMovies" */;
+ buildPhases = (
+ F4678DAF1A5A82F1005A33DE /* Sources */,
+ F4678DB01A5A82F1005A33DE /* Frameworks */,
+ F4678DB11A5A82F1005A33DE /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = SwiftMovies;
+ productName = SwiftMovies;
+ productReference = F4678DB31A5A82F1005A33DE /* SwiftMovies.app */;
+ productType = "com.apple.product-type.application";
+ };
+ F4678DC91A5A82F1005A33DE /* SwiftMoviesTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F4678DD71A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMoviesTests" */;
+ buildPhases = (
+ F4678DC61A5A82F1005A33DE /* Sources */,
+ F4678DC71A5A82F1005A33DE /* Frameworks */,
+ F4678DC81A5A82F1005A33DE /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ F4678DCC1A5A82F1005A33DE /* PBXTargetDependency */,
+ );
+ name = SwiftMoviesTests;
+ productName = SwiftMoviesTests;
+ productReference = F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ F4678DAB1A5A82F1005A33DE /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0610;
+ ORGANIZATIONNAME = "Philly Cocoaheads";
+ TargetAttributes = {
+ F4678DB21A5A82F1005A33DE = {
+ CreatedOnToolsVersion = 6.1.1;
+ };
+ F4678DC91A5A82F1005A33DE = {
+ CreatedOnToolsVersion = 6.1.1;
+ TestTargetID = F4678DB21A5A82F1005A33DE;
+ };
+ };
+ };
+ buildConfigurationList = F4678DAE1A5A82F1005A33DE /* Build configuration list for PBXProject "SwiftMovies" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = F4678DAA1A5A82F1005A33DE;
+ productRefGroup = F4678DB41A5A82F1005A33DE /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ F4678DB21A5A82F1005A33DE /* SwiftMovies */,
+ F4678DC91A5A82F1005A33DE /* SwiftMoviesTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ F4678DB11A5A82F1005A33DE /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4678DC01A5A82F1005A33DE /* Main.storyboard in Resources */,
+ F4678DC51A5A82F1005A33DE /* LaunchScreen.xib in Resources */,
+ F4678DC21A5A82F1005A33DE /* Images.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC81A5A82F1005A33DE /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ F4678DAF1A5A82F1005A33DE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4646C331A5DF40800336DFC /* SettingsViewController.swift in Sources */,
+ F477D6AE1A5F20E2006FD97E /* DetailViewController.swift in Sources */,
+ F49C6F8A1A5F47B200D0C49E /* WebViewController.swift in Sources */,
+ F45D76761A5FD9FE001807F2 /* SwiftyJSON.swift in Sources */,
+ F4DC98D01A5E5B0C0030CC99 /* CollectionViewController.swift in Sources */,
+ F4678DE11A5A9582005A33DE /* Movie.swift in Sources */,
+ F4DC98D21A5E6B460030CC99 /* TMDB.swift in Sources */,
+ F477D6B21A5F20FF006FD97E /* FilterViewController.swift in Sources */,
+ F4678DB91A5A82F1005A33DE /* AppDelegate.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC61A5A82F1005A33DE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4678DD11A5A82F1005A33DE /* SwiftMoviesTests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ F4678DCC1A5A82F1005A33DE /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F4678DB21A5A82F1005A33DE /* SwiftMovies */;
+ targetProxy = F4678DCB1A5A82F1005A33DE /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ F4678DBE1A5A82F1005A33DE /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F4678DBF1A5A82F1005A33DE /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "";
+ };
+ F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F4678DC41A5A82F1005A33DE /* Base */,
+ );
+ name = LaunchScreen.xib;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ F4678DD21A5A82F1005A33DE /* 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.1;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ F4678DD31A5A82F1005A33DE /* 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.1;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ F4678DD51A5A82F1005A33DE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = SwiftMovies/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ F4678DD61A5A82F1005A33DE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = SwiftMovies/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ F4678DD81A5A82F1005A33DE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = SwiftMoviesTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftMovies.app/SwiftMovies";
+ };
+ name = Debug;
+ };
+ F4678DD91A5A82F1005A33DE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = SwiftMoviesTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftMovies.app/SwiftMovies";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ F4678DAE1A5A82F1005A33DE /* Build configuration list for PBXProject "SwiftMovies" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD21A5A82F1005A33DE /* Debug */,
+ F4678DD31A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ F4678DD41A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMovies" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD51A5A82F1005A33DE /* Debug */,
+ F4678DD61A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ F4678DD71A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMoviesTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD81A5A82F1005A33DE /* Debug */,
+ F4678DD91A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = F4678DAB1A5A82F1005A33DE /* Project object */;
+}
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..7890687
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..69f5a3b
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
new file mode 100644
index 0000000..fe2b454
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -0,0 +1,5 @@
+
+
+
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme
new file mode 100644
index 0000000..ec387aa
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..dd30f16
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,27 @@
+
+
+
+
+ SchemeUserState
+
+ SwiftMovies.xcscheme
+
+ orderHint
+ 0
+
+
+ SuppressBuildableAutocreation
+
+ F4678DB21A5A82F1005A33DE
+
+ primary
+
+
+ F4678DC91A5A82F1005A33DE
+
+ primary
+
+
+
+
+
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/AppDelegate.swift b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/AppDelegate.swift
new file mode 100644
index 0000000..9c2f2cc
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/AppDelegate.swift
@@ -0,0 +1,46 @@
+//
+// AppDelegate.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+@UIApplicationMain
+class AppDelegate: UIResponder, UIApplicationDelegate {
+
+ var window: UIWindow?
+
+
+ func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> 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/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib
new file mode 100644
index 0000000..9e43426
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..664ffcf
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard
@@ -0,0 +1,604 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/CollectionViewController.swift b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/CollectionViewController.swift
new file mode 100644
index 0000000..985fefc
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/CollectionViewController.swift
@@ -0,0 +1,84 @@
+//
+// MovieCollectionController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Since we don't have to worry about headers and imports in Swift
+// It sometimes makes sense to keep multiple classes in the same file
+final class MovieCell: UICollectionViewCell {
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var imageView: UIImageView!
+}
+
+final class CollectionViewController: UIViewController {
+ @IBOutlet weak var collectionView: UICollectionView!
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+
+ var activeList: TMDB.MovieList = TMDB.MovieList.Popular
+ var movies: [Movie] = []
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.collectionView.delegate = self
+ self.collectionView.dataSource = self
+ self.loadPlaceholderData()
+ }
+
+ func loadPlaceholderData() {
+ let goneGirl = Movie(title: "Gone Girl", posterPath: "gonePoster", averageRating: 8.1, voteCount: 845)
+ let guardians = Movie(title: "Guardians of the Galaxy", posterPath: "guardiansPoster", averageRating: 9.2, voteCount: 1026)
+ let theHobbit = Movie(title: "The Hobbit", posterPath: "hobbitPoster", averageRating: 7.4, voteCount: 1343)
+ let theInterview = Movie(title: "The Interview", posterPath: "interviewPoster", averageRating: 6.3, voteCount: 824)
+
+ self.movies = [goneGirl, guardians, theHobbit, theInterview]
+ }
+
+ override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
+ if segue.identifier == "showMovieView" {
+ // We use "as" to typecast to a certain object type
+ let movieController = segue.destinationViewController as DetailViewController
+ let indexPath = self.collectionView.indexPathsForSelectedItems().first as NSIndexPath?
+ if let selectedPath = indexPath {
+ // Pass the selected movie to detail view
+ let movie = self.movies[selectedPath.row]
+ movieController.movie = movie
+ }
+ }
+
+ if segue.identifier == "showFilterView" {
+ // We use "as" to typecast to a certain object type
+ let navController = segue.destinationViewController as UINavigationController
+ let filterController = navController.viewControllers.first as FilterViewController
+ // By setting the delegate to this controller we receive updates when the filter changes.
+ filterController.delegate = self
+ }
+ }
+}
+
+extension CollectionViewController: UICollectionViewDataSource, UICollectionViewDelegate {
+ func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+ return self.movies.count
+ }
+
+ func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
+ let movieCell = collectionView.dequeueReusableCellWithReuseIdentifier("movieCell", forIndexPath: indexPath) as MovieCell
+ let movie = self.movies[indexPath.row]
+ movieCell.imageView.image = UIImage(named: movie.posterPath)
+
+ return movieCell
+ }
+}
+
+extension CollectionViewController: FilterViewDelegate {
+ func filterDidChange(list: TMDB.MovieList) {
+ self.activeList = list
+ self.navigationItem.title = list.listName
+ //self.collectionView.setContentOffset(CGPoint(x: 0, y:-self.collectionView.contentInset.top), animated: false)
+ //self.refreshMovieResults()
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/DetailViewController.swift b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/DetailViewController.swift
new file mode 100644
index 0000000..1e6c1aa
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/DetailViewController.swift
@@ -0,0 +1,57 @@
+//
+// MovieViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class DetailViewController: UIViewController {
+ @IBOutlet weak var backdropImageView: UIImageView!
+ @IBOutlet weak var backdropActivityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var titleLabel: UILabel!
+ @IBOutlet weak var ratingLabel: UILabel!
+ @IBOutlet weak var summaryLabel: UILabel!
+ @IBOutlet weak var releaseDateLabel: UILabel!
+ @IBOutlet weak var genresLabel: UILabel!
+ @IBOutlet weak var runtimeLabel: UILabel!
+
+ var movie: Movie?
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.loadMovieInfo()
+ }
+
+ private func loadMovieInfo() {
+ // Setup our empty state (how the screen should look while loading)
+ let ellipsis = "..."
+ self.backdropImageView.image = nil
+ self.titleLabel.text = ellipsis
+ self.navigationItem.title = ellipsis
+ self.ratingLabel.text = ellipsis
+ self.summaryLabel.text = ellipsis
+ self.releaseDateLabel.text = ellipsis
+ self.genresLabel.text = ellipsis
+ self.runtimeLabel.text = ellipsis
+
+
+ if let movie = self.movie {
+ self.titleLabel.text = movie.title
+ self.navigationItem.title = movie.title
+ } else {
+ let ellipsis = "Not Available"
+ self.backdropImageView.image = nil
+ self.titleLabel.text = ellipsis
+ self.navigationItem.title = ellipsis
+ self.ratingLabel.text = ellipsis
+ self.summaryLabel.text = ellipsis
+ self.releaseDateLabel.text = ellipsis
+ self.genresLabel.text = ellipsis
+ self.runtimeLabel.text = ellipsis
+ }
+ }
+}
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/FilterViewController.swift b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/FilterViewController.swift
new file mode 100644
index 0000000..341535d
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/FilterViewController.swift
@@ -0,0 +1,61 @@
+//
+// FiltersViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class FilterViewController: UIViewController {
+ @IBOutlet var tableView: UITableView!
+ var delegate: FilterViewDelegate?
+
+
+ @IBAction func cancel(sender: AnyObject) {
+ self.dismiss()
+ }
+
+ func dismiss() {
+ self.navigationController?.dismissViewControllerAnimated(true, completion: nil)
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ }
+}
+
+extension FilterViewController: UITableViewDelegate, UITableViewDataSource {
+ func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return TMDB.MovieList.allLists.count
+ }
+
+ func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
+ let cell = tableView.dequeueReusableCellWithIdentifier("filterCell") as UITableViewCell
+ let movieList: TMDB.MovieList = TMDB.MovieList.allLists[indexPath.row]
+
+ cell.textLabel?.text = movieList.listName
+
+ if movieList == delegate?.activeList {
+ cell.accessoryType = UITableViewCellAccessoryType.Checkmark
+ } else {
+ cell.accessoryType = UITableViewCellAccessoryType.None
+ }
+
+ return cell
+ }
+
+ func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
+ tableView.deselectRowAtIndexPath(indexPath, animated: false) // Fix sticky cells
+ let movieList: TMDB.MovieList = TMDB.MovieList.allLists[indexPath.row]
+ self.delegate?.filterDidChange(movieList)
+ self.dismiss()
+ }
+}
+
+protocol FilterViewDelegate {
+ var activeList: TMDB.MovieList { get }
+ func filterDidChange(list: TMDB.MovieList)
+}
\ No newline at end of file
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store
new file mode 100644
index 0000000..c068369
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..7997783
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,44 @@
+{
+ "images" : [
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-29@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-40@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-60@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-60@3x.png",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png
new file mode 100644
index 0000000..d463ba9
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png
new file mode 100644
index 0000000..e421cfa
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png
new file mode 100644
index 0000000..2be6555
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png
new file mode 100644
index 0000000..efa69d2
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png
new file mode 100644
index 0000000..efa69d2
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png
new file mode 100644
index 0000000..e405742
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..0f84226
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "bt6DhdALyhf90gReozoQ0y3R3vZ.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg
new file mode 100644
index 0000000..1e19bbb
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..5d9e965
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..3124e77
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "umR9aXTxOxQUuDH2DamoJ5fIPB.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg
new file mode 100644
index 0000000..f4c469c
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..ed3e63e
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "eDildzNrm4XJABWkNKtqB29t6mv.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg
new file mode 100644
index 0000000..90ede16
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..8d49e39
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png
new file mode 100644
index 0000000..68aa392
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png
new file mode 100644
index 0000000..bb5d8b4
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png
new file mode 100644
index 0000000..12923f2
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json
new file mode 100644
index 0000000..4e659b8
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "settings.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "settings@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "settings@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png
new file mode 100644
index 0000000..e2d21f0
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png
new file mode 100644
index 0000000..6fd890d
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png
new file mode 100644
index 0000000..d68af6b
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json
new file mode 100644
index 0000000..50564ce
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "star.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "star@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "star@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png
new file mode 100644
index 0000000..2b2b41b
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png
new file mode 100644
index 0000000..f1367c8
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png
new file mode 100644
index 0000000..390ad8e
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json
new file mode 100644
index 0000000..04ea068
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "tag.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "tag@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "tag@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png
new file mode 100644
index 0000000..d46a1af
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png
new file mode 100644
index 0000000..5d176aa
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png
new file mode 100644
index 0000000..bee24d8
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json
new file mode 100644
index 0000000..16f2d86
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json
new file mode 100644
index 0000000..2febbf6
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json
new file mode 100644
index 0000000..37c7f9d
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json
new file mode 100644
index 0000000..8e8af21
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "interview.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "interview-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "interview-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json
new file mode 100644
index 0000000..4b2222a
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "Placeholder.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "Placeholder@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "Placeholder@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png
new file mode 100644
index 0000000..4f45f19
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png
new file mode 100644
index 0000000..e21d629
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png
new file mode 100644
index 0000000..6d89554
Binary files /dev/null and b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png differ
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Info.plist b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Info.plist
new file mode 100644
index 0000000..aab298d
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Info.plist
@@ -0,0 +1,52 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleDisplayName
+ Swift Movies
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ phillycocoa.$(PRODUCT_NAME:rfc1034identifier)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UIStatusBarTintParameters
+
+ UINavigationBar
+
+ Style
+ UIBarStyleDefault
+ Translucent
+
+
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+
+
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Movie.swift b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Movie.swift
new file mode 100644
index 0000000..72f0a7d
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/Movie.swift
@@ -0,0 +1,31 @@
+//
+// Movie.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+final class Movie {
+ let title: String
+ let posterPath: String
+ let rating: Rating
+
+ init(title: String, posterPath: String, rating: Rating) {
+ self.title = title
+ self.posterPath = posterPath
+ self.rating = rating
+ }
+
+ convenience init(title: String, posterPath: String, averageRating: Double, voteCount: Int) {
+ let rating = Rating(averageRating: averageRating, voteCount: voteCount)
+ self.init(title: title, posterPath: posterPath, rating: rating)
+ }
+}
+
+struct Rating {
+ var averageRating: Double
+ var voteCount: Int
+}
\ No newline at end of file
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/SettingsViewController.swift b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/SettingsViewController.swift
new file mode 100644
index 0000000..8ee1257
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/SettingsViewController.swift
@@ -0,0 +1,40 @@
+//
+// SettingsController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/7/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class SettingsViewController: UITableViewController {
+ var urlString: String = ""
+
+ override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
+ let path = (indexPath.section, indexPath.row)
+ switch path {
+ case(0, 0):
+ self.urlString = "http://twitter.com"
+ case(0, 1):
+ self.urlString = "http://facebook.com"
+ case(1, 0):
+ self.urlString = "http://google.com"
+ case(1, 1):
+ self.urlString = "http://apple.com"
+ default:
+ return
+ }
+
+
+ self.performSegueWithIdentifier("showWebView", sender: self)
+ }
+
+ override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
+ if segue.identifier == "showWebView" {
+ let webViewController = segue.destinationViewController as WebViewController
+ webViewController.urlString = self.urlString
+ }
+ }
+}
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift
new file mode 100644
index 0000000..f26c7e7
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift
@@ -0,0 +1,1335 @@
+// SwiftyJSON.swift
+//
+// Copyright (c) 2014 Ruoyu Fu, Pinglin Tang
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+// MARK: - Error
+
+///Error domain
+public let ErrorDomain: String! = "SwiftyJSONErrorDomain"
+
+///Error code
+public let ErrorUnsupportedType: Int! = 999
+public let ErrorIndexOutOfBounds: Int! = 900
+public let ErrorWrongType: Int! = 901
+public let ErrorNotExist: Int! = 500
+
+// MARK: - JSON Type
+
+/**
+JSON's type definitions.
+
+See http://tools.ietf.org/html/rfc7231#section-4.3
+*/
+public enum Type :Int{
+
+ case Number
+ case String
+ case Bool
+ case Array
+ case Dictionary
+ case Null
+ case Unknown
+}
+
+// MARK: - JSON Base
+
+public struct JSON {
+
+ /**
+ Creates a JSON using the data.
+
+ :param: data The NSData used to convert to json.Top level object in data is an NSArray or NSDictionary
+ :param: opt The JSON serialization reading options. `.AllowFragments` by default.
+ :param: error error The NSErrorPointer used to return the error. `nil` by default.
+
+ :returns: The created JSON
+ */
+ public init(data:NSData, options opt: NSJSONReadingOptions = .AllowFragments, error: NSErrorPointer = nil) {
+ if let object: AnyObject = NSJSONSerialization.JSONObjectWithData(data, options: opt, error: error) {
+ self.init(object)
+ } else {
+ self.init(NSNull())
+ }
+ }
+
+ /**
+ Creates a JSON using the object.
+
+ :param: object The object must have the following properties: All objects are NSString/String, NSNumber/Int/Float/Double/Bool, NSArray/Array, NSDictionary/Dictionary, or NSNull; All dictionary keys are NSStrings/String; NSNumbers are not NaN or infinity.
+
+ :returns: The created JSON
+ */
+ public init(_ object: AnyObject) {
+ self.object = object
+ }
+
+ /// Private object
+ private var _object: AnyObject = NSNull()
+ /// Private type
+ private var _type: Type = .Null
+ /// prviate error
+ private var _error: NSError?
+
+ /// Object in JSON
+ public var object: AnyObject {
+ get {
+ return _object
+ }
+ set {
+ _object = newValue
+ switch newValue {
+ case let number as NSNumber:
+ if number.isBool {
+ _type = .Bool
+ } else {
+ _type = .Number
+ }
+ case let string as NSString:
+ _type = .String
+ case let null as NSNull:
+ _type = .Null
+ case let array as [AnyObject]:
+ _type = .Array
+ case let dictionary as [String : AnyObject]:
+ _type = .Dictionary
+ default:
+ _type = .Unknown
+ _object = NSNull()
+ _error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"])
+ }
+ }
+ }
+
+ /// json type
+ public var type: Type { get { return _type } }
+
+ /// Error in JSON
+ public var error: NSError? { get { return self._error } }
+
+ /// The static null json
+ public static var nullJSON: JSON { get { return JSON(NSNull()) } }
+
+}
+
+// MARK: - SequenceType
+extension JSON: SequenceType{
+
+ /// If `type` is `.Array` or `.Dictionary`, return `array.empty` or `dictonary.empty` otherwise return `false`.
+ public var isEmpty: Bool {
+ get {
+ switch self.type {
+ case .Array:
+ return (self.object as [AnyObject]).isEmpty
+ case .Dictionary:
+ return (self.object as [String : AnyObject]).isEmpty
+ default:
+ return false
+ }
+ }
+ }
+
+ /// If `type` is `.Array` or `.Dictionary`, return `array.count` or `dictonary.count` otherwise return `0`.
+ public var count: Int {
+ get {
+ switch self.type {
+ case .Array:
+ return self.arrayValue.count
+ case .Dictionary:
+ return self.dictionaryValue.count
+ default:
+ return 0
+ }
+ }
+ }
+
+ /**
+ If `type` is `.Array` or `.Dictionary`, return a generator over the elements like `Array` or `Dictionary, otherwise return a generator over empty.
+
+ :returns: Return a *generator* over the elements of this *sequence*.
+ */
+ public func generate() -> GeneratorOf <(String, JSON)> {
+ switch self.type {
+ case .Array:
+ let array_ = object as [AnyObject]
+ var generate_ = array_.generate()
+ var index_: Int = 0
+ return GeneratorOf<(String, JSON)> {
+ if let element_: AnyObject = generate_.next() {
+ return ("\(index_++)", JSON(element_))
+ } else {
+ return nil
+ }
+ }
+ case .Dictionary:
+ let dictionary_ = object as [String : AnyObject]
+ var generate_ = dictionary_.generate()
+ return GeneratorOf<(String, JSON)> {
+ if let (key_: String, value_: AnyObject) = generate_.next() {
+ return (key_, JSON(value_))
+ } else {
+ return nil
+ }
+ }
+ default:
+ return GeneratorOf<(String, JSON)> {
+ return nil
+ }
+ }
+ }
+}
+
+// MARK: - Subscript
+
+/**
+* To mark both String and Int can be used in subscript.
+*/
+public protocol SubscriptType {}
+
+extension Int: SubscriptType {}
+
+extension String: SubscriptType {}
+
+extension JSON {
+
+ /// If `type` is `.Array`, return json which's object is `array[index]`, otherwise return null json with error.
+ private subscript(#index: Int) -> JSON {
+ get {
+
+ if self.type != .Array {
+ var errorResult_ = JSON.nullJSON
+ errorResult_._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] failure, It is not an array"])
+ return errorResult_
+ }
+
+ let array_ = self.object as [AnyObject]
+
+ if index >= 0 && index < array_.count {
+ return JSON(array_[index])
+ }
+
+ var errorResult_ = JSON.nullJSON
+ errorResult_._error = NSError(domain: ErrorDomain, code:ErrorIndexOutOfBounds , userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] is out of bounds"])
+ return errorResult_
+ }
+ set {
+ if self.type == .Array {
+ var array_ = self.object as [AnyObject]
+ if array_.count > index {
+ array_[index] = newValue.object
+ self.object = array_
+ }
+ }
+ }
+ }
+
+ /// If `type` is `.Dictionary`, return json which's object is `dictionary[key]` , otherwise return null json with error.
+ private subscript(#key: String) -> JSON {
+ get {
+ var returnJSON = JSON.nullJSON
+ if self.type == .Dictionary {
+ if let object_: AnyObject = self.object[key] {
+ returnJSON = JSON(object_)
+ } else {
+ returnJSON._error = NSError(domain: ErrorDomain, code: ErrorNotExist, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] does not exist"])
+ }
+ } else {
+ returnJSON._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] failure, It is not an dictionary"])
+ }
+ return returnJSON
+ }
+ set {
+ if self.type == .Dictionary {
+ var dictionary_ = self.object as [String : AnyObject]
+ dictionary_[key] = newValue.object
+ self.object = dictionary_
+ }
+ }
+ }
+
+ /// If `sub` is `Int`, return `subscript(index:)`; If `sub` is `String`, return `subscript(key:)`.
+ private subscript(#sub: SubscriptType) -> JSON {
+ get {
+ if sub is String {
+ return self[key:sub as String]
+ } else {
+ return self[index:sub as Int]
+ }
+ }
+ set {
+ if sub is String {
+ self[key:sub as String] = newValue
+ } else {
+ self[index:sub as Int] = newValue
+ }
+ }
+ }
+
+ /**
+ Find a json in the complex data structuresby using the Int/String's array.
+
+ :param: path The target json's path. Example:
+
+ let json = JSON[data]
+ let path = [9,"list","person","name"]
+ let name = json[path]
+
+ The same as: let name = json[9]["list"]["person"]["name"]
+
+ :returns: Return a json found by the path or a null json with error
+ */
+ public subscript(path: [SubscriptType]) -> JSON {
+ get {
+ if path.count == 0 {
+ return JSON.nullJSON
+ }
+
+ var next = self
+ for sub in path {
+ next = next[sub:sub]
+ }
+ return next
+ }
+ set {
+
+ switch path.count {
+ case 0: return
+ case 1: self[sub:path[0]] = newValue
+ default:
+ var last = newValue
+ var newPath = path
+ newPath.removeLast()
+ for sub in path.reverse() {
+ var previousLast = self[newPath]
+ previousLast[sub:sub] = last
+ last = previousLast
+ if newPath.count <= 1 {
+ break
+ }
+ newPath.removeLast()
+ }
+ self[sub:newPath[0]] = last
+ }
+ }
+ }
+
+ /**
+ Find a json in the complex data structuresby using the Int/String's array.
+
+ :param: path The target json's path. Example:
+
+ let name = json[9,"list","person","name"]
+
+ The same as: let name = json[9]["list"]["person"]["name"]
+
+ :returns: Return a json found by the path or a null json with error
+ */
+ public subscript(path: SubscriptType...) -> JSON {
+ get {
+ return self[path]
+ }
+ set {
+ self[path] = newValue
+ }
+ }
+}
+
+// MARK: - LiteralConvertible
+
+extension JSON: StringLiteralConvertible {
+
+ public init(stringLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+
+ public init(extendedGraphemeClusterLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+
+ public init(unicodeScalarLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: IntegerLiteralConvertible {
+
+ public init(integerLiteral value: IntegerLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: BooleanLiteralConvertible {
+
+ public init(booleanLiteral value: BooleanLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: FloatLiteralConvertible {
+
+ public init(floatLiteral value: FloatLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: DictionaryLiteralConvertible {
+
+ public init(dictionaryLiteral elements: (String, AnyObject)...) {
+ var dictionary_ = [String : AnyObject]()
+ for (key_, value) in elements {
+ dictionary_[key_] = value
+ }
+ self.init(dictionary_)
+ }
+}
+
+extension JSON: ArrayLiteralConvertible {
+
+ public init(arrayLiteral elements: AnyObject...) {
+ self.init(elements)
+ }
+}
+
+extension JSON: NilLiteralConvertible {
+
+ public init(nilLiteral: ()) {
+ self.init(NSNull())
+ }
+}
+
+// MARK: - Raw
+
+extension JSON: RawRepresentable {
+
+ public init?(rawValue: AnyObject) {
+ if JSON(rawValue).type == .Unknown {
+ return nil
+ } else {
+ self.init(rawValue)
+ }
+ }
+
+ public var rawValue: AnyObject {
+ return self.object
+ }
+
+ public func rawData(options opt: NSJSONWritingOptions = NSJSONWritingOptions(0), error: NSErrorPointer = nil) -> NSData? {
+ return NSJSONSerialization.dataWithJSONObject(self.object, options: opt, error:error)
+ }
+
+ public func rawString(encoding: UInt = NSUTF8StringEncoding, options opt: NSJSONWritingOptions = .PrettyPrinted) -> String? {
+ switch self.type {
+ case .Array, .Dictionary:
+ if let data = self.rawData(options: opt) {
+ return NSString(data: data, encoding: encoding)
+ } else {
+ return nil
+ }
+ case .String:
+ return (self.object as String)
+ case .Number:
+ return (self.object as NSNumber).stringValue
+ case .Bool:
+ return (self.object as Bool).description
+ case .Null:
+ return "null"
+ default:
+ return nil
+ }
+ }
+}
+
+// MARK: - Printable, DebugPrintable
+
+extension JSON: Printable, DebugPrintable {
+
+ public var description: String {
+ if let string = self.rawString(options:.PrettyPrinted) {
+ return string
+ } else {
+ return "unknown"
+ }
+ }
+
+ public var debugDescription: String {
+ return description
+ }
+}
+
+// MARK: - Array
+
+extension JSON {
+
+ //Optional [JSON]
+ public var array: [JSON]? {
+ get {
+ if self.type == .Array {
+ return map(self.object as [AnyObject]){ JSON($0) }
+ } else {
+ return nil
+ }
+ }
+ }
+
+ //Non-optional [JSON]
+ public var arrayValue: [JSON] {
+ get {
+ return self.array ?? []
+ }
+ }
+
+ //Optional [AnyObject]
+ public var arrayObject: [AnyObject]? {
+ get {
+ switch self.type {
+ case .Array:
+ return self.object as? [AnyObject]
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSMutableArray(array: newValue!, copyItems: true)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+}
+
+// MARK: - Dictionary
+
+extension JSON {
+
+ private func _map(source: [Key: Value], transform: Value -> NewValue) -> [Key: NewValue] {
+ var result = [Key: NewValue](minimumCapacity:source.count)
+ for (key,value) in source {
+ result[key] = transform(value)
+ }
+ return result
+ }
+
+ //Optional [String : JSON]
+ public var dictionary: [String : JSON]? {
+ get {
+ if self.type == .Dictionary {
+ return _map(self.object as [String : AnyObject]){ JSON($0) }
+ } else {
+ return nil
+ }
+ }
+ }
+
+ //Non-optional [String : JSON]
+ public var dictionaryValue: [String : JSON] {
+ get {
+ return self.dictionary ?? [:]
+ }
+ }
+
+ //Optional [String : AnyObject]
+ public var dictionaryObject: [String : AnyObject]? {
+ get {
+ switch self.type {
+ case .Dictionary:
+ return self.object as? [String : AnyObject]
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSMutableDictionary(dictionary: newValue!, copyItems: true)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+}
+
+// MARK: - Bool
+
+extension JSON: BooleanType {
+
+ //Optional bool
+ public var bool: Bool? {
+ get {
+ switch self.type {
+ case .Bool:
+ return self.object.boolValue
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(bool: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ //Non-optional bool
+ public var boolValue: Bool {
+ get {
+ switch self.type {
+ case .Bool, .Number, .String:
+ return self.object.boolValue
+ default:
+ return false
+ }
+ }
+ set {
+ self.object = NSNumber(bool: newValue)
+ }
+ }
+}
+
+// MARK: - String
+
+extension JSON {
+
+ //Optional string
+ public var string: String? {
+ get {
+ switch self.type {
+ case .String:
+ return self.object as? String
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSString(string:newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ //Non-optional string
+ public var stringValue: String {
+ get {
+ switch self.type {
+ case .String:
+ return self.object as String
+ case .Number:
+ return self.object.stringValue
+ case .Bool:
+ return (self.object as Bool).description
+ default:
+ return ""
+ }
+ }
+ set {
+ self.object = NSString(string:newValue)
+ }
+ }
+}
+
+// MARK: - Number
+extension JSON {
+
+ //Optional number
+ public var number: NSNumber? {
+ get {
+ switch self.type {
+ case .Number, .Bool:
+ return self.object as? NSNumber
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = newValue?.copy() ?? NSNull()
+ }
+ }
+
+ //Non-optional number
+ public var numberValue: NSNumber {
+ get {
+ switch self.type {
+ case .String:
+ let scanner = NSScanner(string: self.object as String)
+ if scanner.scanDouble(nil){
+ if (scanner.atEnd) {
+ return NSNumber(double:(self.object as NSString).doubleValue)
+ }
+ }
+ return NSNumber(double: 0.0)
+ case .Number, .Bool:
+ return self.object as NSNumber
+ default:
+ return NSNumber(double: 0.0)
+ }
+ }
+ set {
+ self.object = newValue.copy()
+ }
+ }
+}
+
+//MARK: - Null
+extension JSON {
+
+ public var null: NSNull? {
+ get {
+ switch self.type {
+ case .Null:
+ return NSNull()
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = NSNull()
+ }
+ }
+}
+
+//MARK: - URL
+extension JSON {
+
+ //Optional URL
+ public var URL: NSURL? {
+ get {
+ switch self.type {
+ case .String:
+ if let encodedString_ = self.object.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
+ return NSURL(string: encodedString_)
+ } else {
+ return nil
+ }
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = newValue?.absoluteString ?? NSNull()
+ }
+ }
+}
+
+// MARK: - Int, Double, Float, Int8, Int16, Int32, Int64
+
+extension JSON {
+
+ public var double: Double? {
+ get {
+ return self.number?.doubleValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(double: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var doubleValue: Double {
+ get {
+ return self.numberValue.doubleValue
+ }
+ set {
+ self.object = NSNumber(double: newValue)
+ }
+ }
+
+ public var float: Float? {
+ get {
+ return self.number?.floatValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(float: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var floatValue: Float {
+ get {
+ return self.numberValue.floatValue
+ }
+ set {
+ self.object = NSNumber(float: newValue)
+ }
+ }
+
+ public var int: Int? {
+ get {
+ return self.number?.longValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(integer: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var intValue: Int {
+ get {
+ return self.numberValue.integerValue
+ }
+ set {
+ self.object = NSNumber(integer: newValue)
+ }
+ }
+
+ public var uInt: UInt? {
+ get {
+ return self.number?.unsignedLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uIntValue: UInt {
+ get {
+ return self.numberValue.unsignedLongValue
+ }
+ set {
+ self.object = NSNumber(unsignedLong: newValue)
+ }
+ }
+
+ public var int8: Int8? {
+ get {
+ return self.number?.charValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(char: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int8Value: Int8 {
+ get {
+ return self.numberValue.charValue
+ }
+ set {
+ self.object = NSNumber(char: newValue)
+ }
+ }
+
+ public var uInt8: UInt8? {
+ get {
+ return self.number?.unsignedCharValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedChar: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt8Value: UInt8 {
+ get {
+ return self.numberValue.unsignedCharValue
+ }
+ set {
+ self.object = NSNumber(unsignedChar: newValue)
+ }
+ }
+
+ public var int16: Int16? {
+ get {
+ return self.number?.shortValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(short: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int16Value: Int16 {
+ get {
+ return self.numberValue.shortValue
+ }
+ set {
+ self.object = NSNumber(short: newValue)
+ }
+ }
+
+ public var uInt16: UInt16? {
+ get {
+ return self.number?.unsignedShortValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedShort: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt16Value: UInt16 {
+ get {
+ return self.numberValue.unsignedShortValue
+ }
+ set {
+ self.object = NSNumber(unsignedShort: newValue)
+ }
+ }
+
+ public var int32: Int32? {
+ get {
+ return self.number?.intValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(int: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int32Value: Int32 {
+ get {
+ return self.numberValue.intValue
+ }
+ set {
+ self.object = NSNumber(int: newValue)
+ }
+ }
+
+ public var uInt32: UInt32? {
+ get {
+ return self.number?.unsignedIntValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedInt: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt32Value: UInt32 {
+ get {
+ return self.numberValue.unsignedIntValue
+ }
+ set {
+ self.object = NSNumber(unsignedInt: newValue)
+ }
+ }
+
+ public var int64: Int64? {
+ get {
+ return self.number?.longLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(longLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int64Value: Int64 {
+ get {
+ return self.numberValue.longLongValue
+ }
+ set {
+ self.object = NSNumber(longLong: newValue)
+ }
+ }
+
+ public var uInt64: UInt64? {
+ get {
+ return self.number?.unsignedLongLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedLongLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt64Value: UInt64 {
+ get {
+ return self.numberValue.unsignedLongLongValue
+ }
+ set {
+ self.object = NSNumber(unsignedLongLong: newValue)
+ }
+ }
+}
+
+//MARK: - Comparable
+extension JSON: Comparable {}
+
+public func ==(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) == (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) == (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func <=(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) <= (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) <= (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func >=(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) >= (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) >= (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func >(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) > (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) > (rhs.object as String)
+ default:
+ return false
+ }
+}
+
+public func <(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) < (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) < (rhs.object as String)
+ default:
+ return false
+ }
+}
+
+private let trueNumber = NSNumber(bool: true)
+private let falseNumber = NSNumber(bool: false)
+private let trueObjCType = String.fromCString(trueNumber.objCType)
+private let falseObjCType = String.fromCString(falseNumber.objCType)
+
+// MARK: - NSNumber: Comparable
+
+extension NSNumber: Comparable {
+ var isBool:Bool {
+ get {
+ let objCType = String.fromCString(self.objCType)
+ if (self.compare(trueNumber) == NSComparisonResult.OrderedSame && objCType == trueObjCType) || (self.compare(falseNumber) == NSComparisonResult.OrderedSame && objCType == falseObjCType){
+ return true
+ } else {
+ return false
+ }
+ }
+ }
+}
+
+public func ==(lhs: NSNumber, rhs: NSNumber) -> Bool {
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedSame
+ }
+}
+
+public func !=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+ return !(lhs == rhs)
+}
+
+public func <(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedAscending
+ }
+}
+
+public func >(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedDescending
+ }
+}
+
+public func <=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) != NSComparisonResult.OrderedDescending
+ }
+}
+
+public func >=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) != NSComparisonResult.OrderedAscending
+ }
+}
+
+//MARK:- Unavailable
+
+@availability(*, unavailable, renamed="JSON")
+public typealias JSONValue = JSON
+
+extension JSON {
+
+ @availability(*, unavailable, message="use 'init(_ object:AnyObject)' instead")
+ public init(object: AnyObject) {
+ self = JSON(object)
+ }
+
+ @availability(*, unavailable, renamed="dictionaryObject")
+ public var dictionaryObjects: [String : AnyObject]? {
+ get { return self.dictionaryObject }
+ }
+
+ @availability(*, unavailable, renamed="arrayObject")
+ public var arrayObjects: [AnyObject]? {
+ get { return self.arrayObject }
+ }
+
+ @availability(*, unavailable, renamed="int8")
+ public var char: Int8? {
+ get {
+ return self.number?.charValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int8Value")
+ public var charValue: Int8 {
+ get {
+ return self.numberValue.charValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt8")
+ public var unsignedChar: UInt8? {
+ get{
+ return self.number?.unsignedCharValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt8Value")
+ public var unsignedCharValue: UInt8 {
+ get{
+ return self.numberValue.unsignedCharValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int16")
+ public var short: Int16? {
+ get{
+ return self.number?.shortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int16Value")
+ public var shortValue: Int16 {
+ get{
+ return self.numberValue.shortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt16")
+ public var unsignedShort: UInt16? {
+ get{
+ return self.number?.unsignedShortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt16Value")
+ public var unsignedShortValue: UInt16 {
+ get{
+ return self.numberValue.unsignedShortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int")
+ public var long: Int? {
+ get{
+ return self.number?.longValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="intValue")
+ public var longValue: Int {
+ get{
+ return self.numberValue.longValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt")
+ public var unsignedLong: UInt? {
+ get{
+ return self.number?.unsignedLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uIntValue")
+ public var unsignedLongValue: UInt {
+ get{
+ return self.numberValue.unsignedLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int64")
+ public var longLong: Int64? {
+ get{
+ return self.number?.longLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int64Value")
+ public var longLongValue: Int64 {
+ get{
+ return self.numberValue.longLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt64")
+ public var unsignedLongLong: UInt64? {
+ get{
+ return self.number?.unsignedLongLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt64Value")
+ public var unsignedLongLongValue: UInt64 {
+ get{
+ return self.numberValue.unsignedLongLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int")
+ public var integer: Int? {
+ get {
+ return self.number?.integerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="intValue")
+ public var integerValue: Int {
+ get {
+ return self.numberValue.integerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt")
+ public var unsignedInteger: Int? {
+ get {
+ return self.number?.unsignedIntegerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uIntValue")
+ public var unsignedIntegerValue: Int {
+ get {
+ return self.numberValue.unsignedIntegerValue
+ }
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/TMDB.swift b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/TMDB.swift
new file mode 100644
index 0000000..65f2d82
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/TMDB.swift
@@ -0,0 +1,51 @@
+//
+// TMDB.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import Foundation
+
+let TMDB_API_KEY = "8a4a247d072d9ca4a0072893ab60e277"
+let TMDB_API_BASE_URL = "http://api.themoviedb.org/3"
+let TMDB_IMAGE_BASE_URL = "http://image.tmdb.org/t/p"
+
+
+final class TMDB {
+ enum MovieList {
+ case Popular
+ case Upcoming
+ case NowPlaying
+ case TopRated
+
+ static let allLists = [Popular, Upcoming, NowPlaying, TopRated]
+
+ var queryPath: String {
+ switch self {
+ case .Popular:
+ return "popular"
+ case .Upcoming:
+ return "upcoming"
+ case .NowPlaying:
+ return "now_playing"
+ case .TopRated:
+ return "top_rated"
+ }
+ }
+
+ var listName: String {
+ switch self {
+ case .Popular:
+ return "Popular"
+ case .Upcoming:
+ return "Upcoming"
+ case .NowPlaying:
+ return "Now Playing"
+ case .TopRated:
+ return "Top Rated"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/WebViewController.swift b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/WebViewController.swift
new file mode 100644
index 0000000..25372ba
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMovies/WebViewController.swift
@@ -0,0 +1,37 @@
+//
+// WebViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of WebViewController (optimization)
+final class WebViewController: UIViewController {
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var webView: UIWebView!
+
+ var urlString = "http://twitter.com"
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.webView.delegate = self
+
+ if let url = NSURL(string: urlString) {
+ let request = NSURLRequest(URL: url)
+ self.webView.loadRequest(request)
+ }
+ }
+}
+
+extension WebViewController: UIWebViewDelegate {
+ func webViewDidStartLoad(webView: UIWebView) {
+ self.activityIndicator.startAnimating()
+ }
+
+ func webViewDidFinishLoad(webView: UIWebView) {
+ self.activityIndicator.stopAnimating()
+ }
+}
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMoviesTests/Info.plist b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMoviesTests/Info.plist
new file mode 100644
index 0000000..2afc012
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMoviesTests/Info.plist
@@ -0,0 +1,24 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ phillycocoa.$(PRODUCT_NAME:rfc1034identifier)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ BNDL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+
+
diff --git a/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift
new file mode 100644
index 0000000..3cb0bdc
--- /dev/null
+++ b/2 - Act I/1 - Starting Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift
@@ -0,0 +1,36 @@
+//
+// SwiftMoviesTests.swift
+// SwiftMoviesTests
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+import XCTest
+
+class SwiftMoviesTests: 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/2 - Act I/2 - Finished Project/SwiftMovies/.DS_Store b/2 - Act I/2 - Finished Project/SwiftMovies/.DS_Store
new file mode 100644
index 0000000..59b421f
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/.DS_Store differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..02bd8c2
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj
@@ -0,0 +1,474 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ F45D76761A5FD9FE001807F2 /* SwiftyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */; };
+ F4646C331A5DF40800336DFC /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4646C321A5DF40800336DFC /* SettingsViewController.swift */; };
+ F4678DB91A5A82F1005A33DE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DB81A5A82F1005A33DE /* AppDelegate.swift */; };
+ F4678DC01A5A82F1005A33DE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F4678DBE1A5A82F1005A33DE /* Main.storyboard */; };
+ F4678DC21A5A82F1005A33DE /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F4678DC11A5A82F1005A33DE /* Images.xcassets */; };
+ F4678DC51A5A82F1005A33DE /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */; };
+ F4678DD11A5A82F1005A33DE /* SwiftMoviesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */; };
+ F4678DE11A5A9582005A33DE /* Movie.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DE01A5A9582005A33DE /* Movie.swift */; };
+ F477D6AE1A5F20E2006FD97E /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */; };
+ F477D6B21A5F20FF006FD97E /* FilterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F477D6B11A5F20FF006FD97E /* FilterViewController.swift */; };
+ F49C6F8A1A5F47B200D0C49E /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F49C6F891A5F47B200D0C49E /* WebViewController.swift */; };
+ F4DC98D01A5E5B0C0030CC99 /* CollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */; };
+ F4DC98D21A5E6B460030CC99 /* TMDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4DC98D11A5E6B460030CC99 /* TMDB.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ F4678DCB1A5A82F1005A33DE /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = F4678DAB1A5A82F1005A33DE /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F4678DB21A5A82F1005A33DE;
+ remoteInfo = SwiftMovies;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyJSON.swift; sourceTree = ""; };
+ F4646C321A5DF40800336DFC /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; };
+ F4678DB31A5A82F1005A33DE /* SwiftMovies.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftMovies.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ F4678DB71A5A82F1005A33DE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ F4678DB81A5A82F1005A33DE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ F4678DBF1A5A82F1005A33DE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
+ F4678DC11A5A82F1005A33DE /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
+ F4678DC41A5A82F1005A33DE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
+ F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftMoviesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ F4678DCF1A5A82F1005A33DE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftMoviesTests.swift; sourceTree = ""; };
+ F4678DE01A5A9582005A33DE /* Movie.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Movie.swift; sourceTree = ""; };
+ F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; };
+ F477D6B11A5F20FF006FD97E /* FilterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilterViewController.swift; sourceTree = ""; };
+ F49C6F891A5F47B200D0C49E /* WebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebViewController.swift; sourceTree = ""; };
+ F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewController.swift; sourceTree = ""; };
+ F4DC98D11A5E6B460030CC99 /* TMDB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TMDB.swift; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ F4678DB01A5A82F1005A33DE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC71A5A82F1005A33DE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ F4678DAA1A5A82F1005A33DE = {
+ isa = PBXGroup;
+ children = (
+ F4678DB51A5A82F1005A33DE /* SwiftMovies */,
+ F4678DCD1A5A82F1005A33DE /* SwiftMoviesTests */,
+ F4678DB41A5A82F1005A33DE /* Products */,
+ );
+ sourceTree = "";
+ };
+ F4678DB41A5A82F1005A33DE /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DB31A5A82F1005A33DE /* SwiftMovies.app */,
+ F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ F4678DB51A5A82F1005A33DE /* SwiftMovies */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DB81A5A82F1005A33DE /* AppDelegate.swift */,
+ F4678DC11A5A82F1005A33DE /* Images.xcassets */,
+ F477D6AA1A5F209D006FD97E /* Controllers */,
+ F477D6B31A5F210F006FD97E /* Models */,
+ F477D6B71A5F215E006FD97E /* Networking */,
+ F4678DBE1A5A82F1005A33DE /* Main.storyboard */,
+ F4678DB61A5A82F1005A33DE /* Supporting Files */,
+ );
+ path = SwiftMovies;
+ sourceTree = "";
+ };
+ F4678DB61A5A82F1005A33DE /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */,
+ F4678DB71A5A82F1005A33DE /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ F4678DCD1A5A82F1005A33DE /* SwiftMoviesTests */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */,
+ F4678DCE1A5A82F1005A33DE /* Supporting Files */,
+ );
+ path = SwiftMoviesTests;
+ sourceTree = "";
+ };
+ F4678DCE1A5A82F1005A33DE /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DCF1A5A82F1005A33DE /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ F477D6AA1A5F209D006FD97E /* Controllers */ = {
+ isa = PBXGroup;
+ children = (
+ F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */,
+ F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */,
+ F477D6B11A5F20FF006FD97E /* FilterViewController.swift */,
+ F4646C321A5DF40800336DFC /* SettingsViewController.swift */,
+ F49C6F891A5F47B200D0C49E /* WebViewController.swift */,
+ );
+ name = Controllers;
+ sourceTree = "";
+ };
+ F477D6B31A5F210F006FD97E /* Models */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DE01A5A9582005A33DE /* Movie.swift */,
+ );
+ name = Models;
+ sourceTree = "";
+ };
+ F477D6B71A5F215E006FD97E /* Networking */ = {
+ isa = PBXGroup;
+ children = (
+ F4DC98D11A5E6B460030CC99 /* TMDB.swift */,
+ F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */,
+ );
+ name = Networking;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ F4678DB21A5A82F1005A33DE /* SwiftMovies */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F4678DD41A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMovies" */;
+ buildPhases = (
+ F4678DAF1A5A82F1005A33DE /* Sources */,
+ F4678DB01A5A82F1005A33DE /* Frameworks */,
+ F4678DB11A5A82F1005A33DE /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = SwiftMovies;
+ productName = SwiftMovies;
+ productReference = F4678DB31A5A82F1005A33DE /* SwiftMovies.app */;
+ productType = "com.apple.product-type.application";
+ };
+ F4678DC91A5A82F1005A33DE /* SwiftMoviesTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F4678DD71A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMoviesTests" */;
+ buildPhases = (
+ F4678DC61A5A82F1005A33DE /* Sources */,
+ F4678DC71A5A82F1005A33DE /* Frameworks */,
+ F4678DC81A5A82F1005A33DE /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ F4678DCC1A5A82F1005A33DE /* PBXTargetDependency */,
+ );
+ name = SwiftMoviesTests;
+ productName = SwiftMoviesTests;
+ productReference = F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ F4678DAB1A5A82F1005A33DE /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0610;
+ ORGANIZATIONNAME = "Philly Cocoaheads";
+ TargetAttributes = {
+ F4678DB21A5A82F1005A33DE = {
+ CreatedOnToolsVersion = 6.1.1;
+ };
+ F4678DC91A5A82F1005A33DE = {
+ CreatedOnToolsVersion = 6.1.1;
+ TestTargetID = F4678DB21A5A82F1005A33DE;
+ };
+ };
+ };
+ buildConfigurationList = F4678DAE1A5A82F1005A33DE /* Build configuration list for PBXProject "SwiftMovies" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = F4678DAA1A5A82F1005A33DE;
+ productRefGroup = F4678DB41A5A82F1005A33DE /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ F4678DB21A5A82F1005A33DE /* SwiftMovies */,
+ F4678DC91A5A82F1005A33DE /* SwiftMoviesTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ F4678DB11A5A82F1005A33DE /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4678DC01A5A82F1005A33DE /* Main.storyboard in Resources */,
+ F4678DC51A5A82F1005A33DE /* LaunchScreen.xib in Resources */,
+ F4678DC21A5A82F1005A33DE /* Images.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC81A5A82F1005A33DE /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ F4678DAF1A5A82F1005A33DE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4646C331A5DF40800336DFC /* SettingsViewController.swift in Sources */,
+ F477D6AE1A5F20E2006FD97E /* DetailViewController.swift in Sources */,
+ F49C6F8A1A5F47B200D0C49E /* WebViewController.swift in Sources */,
+ F45D76761A5FD9FE001807F2 /* SwiftyJSON.swift in Sources */,
+ F4DC98D01A5E5B0C0030CC99 /* CollectionViewController.swift in Sources */,
+ F4678DE11A5A9582005A33DE /* Movie.swift in Sources */,
+ F4DC98D21A5E6B460030CC99 /* TMDB.swift in Sources */,
+ F477D6B21A5F20FF006FD97E /* FilterViewController.swift in Sources */,
+ F4678DB91A5A82F1005A33DE /* AppDelegate.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC61A5A82F1005A33DE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4678DD11A5A82F1005A33DE /* SwiftMoviesTests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ F4678DCC1A5A82F1005A33DE /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F4678DB21A5A82F1005A33DE /* SwiftMovies */;
+ targetProxy = F4678DCB1A5A82F1005A33DE /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ F4678DBE1A5A82F1005A33DE /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F4678DBF1A5A82F1005A33DE /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "";
+ };
+ F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F4678DC41A5A82F1005A33DE /* Base */,
+ );
+ name = LaunchScreen.xib;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ F4678DD21A5A82F1005A33DE /* 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.1;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ F4678DD31A5A82F1005A33DE /* 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.1;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ F4678DD51A5A82F1005A33DE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = SwiftMovies/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ F4678DD61A5A82F1005A33DE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = SwiftMovies/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ F4678DD81A5A82F1005A33DE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = SwiftMoviesTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftMovies.app/SwiftMovies";
+ };
+ name = Debug;
+ };
+ F4678DD91A5A82F1005A33DE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = SwiftMoviesTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftMovies.app/SwiftMovies";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ F4678DAE1A5A82F1005A33DE /* Build configuration list for PBXProject "SwiftMovies" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD21A5A82F1005A33DE /* Debug */,
+ F4678DD31A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ F4678DD41A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMovies" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD51A5A82F1005A33DE /* Debug */,
+ F4678DD61A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ F4678DD71A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMoviesTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD81A5A82F1005A33DE /* Debug */,
+ F4678DD91A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = F4678DAB1A5A82F1005A33DE /* Project object */;
+}
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..7890687
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..e582c6f
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
new file mode 100644
index 0000000..fe2b454
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -0,0 +1,5 @@
+
+
+
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme
new file mode 100644
index 0000000..ec387aa
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..dd30f16
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,27 @@
+
+
+
+
+ SchemeUserState
+
+ SwiftMovies.xcscheme
+
+ orderHint
+ 0
+
+
+ SuppressBuildableAutocreation
+
+ F4678DB21A5A82F1005A33DE
+
+ primary
+
+
+ F4678DC91A5A82F1005A33DE
+
+ primary
+
+
+
+
+
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/AppDelegate.swift b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/AppDelegate.swift
new file mode 100644
index 0000000..9c2f2cc
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/AppDelegate.swift
@@ -0,0 +1,46 @@
+//
+// AppDelegate.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+@UIApplicationMain
+class AppDelegate: UIResponder, UIApplicationDelegate {
+
+ var window: UIWindow?
+
+
+ func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> 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/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib
new file mode 100644
index 0000000..9e43426
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..5891448
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard
@@ -0,0 +1,600 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/CollectionViewController.swift b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/CollectionViewController.swift
new file mode 100644
index 0000000..f97efe7
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/CollectionViewController.swift
@@ -0,0 +1,58 @@
+//
+// MovieCollectionController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Since we don't have to worry about headers and imports in Swift
+// It sometimes makes sense to keep multiple classes in the same file
+final class MovieCell: UICollectionViewCell {
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var imageView: UIImageView!
+}
+
+final class CollectionViewController: UIViewController {
+ @IBOutlet weak var collectionView: UICollectionView!
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+
+ // We will later be fetching our movies from the web
+ // so we went to use a var such that we can update our movies after load
+ // We need to have a value, so we default to an empty array
+ var movies: [Movie] = []
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.collectionView.delegate = self
+ self.collectionView.dataSource = self
+ self.loadPlaceholderData()
+ }
+
+ func loadPlaceholderData() {
+ let goneGirl = Movie(title: "Gone Girl", posterPath: "gonePoster", averageRating: 8.1, voteCount: 845)
+ let guardians = Movie(title: "Guardians of the Galaxy", posterPath: "guardiansPoster", averageRating: 9.2, voteCount: 1026)
+ let theHobbit = Movie(title: "The Hobbit", posterPath: "hobbitPoster", averageRating: 7.4, voteCount: 1343)
+ let theInterview = Movie(title: "The Interview", posterPath: "interviewPoster", averageRating: 6.3, voteCount: 824)
+
+ self.movies = [goneGirl, guardians, theHobbit, theInterview]
+ self.collectionView.reloadData()
+ }
+}
+
+// Class extensions make it easy to group functionality, like protocol methods
+extension CollectionViewController: UICollectionViewDelegate, UICollectionViewDataSource {
+ func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+ return self.movies.count
+ }
+
+ func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
+ let movieCell = collectionView.dequeueReusableCellWithReuseIdentifier("movieCell", forIndexPath: indexPath) as MovieCell
+ let movie = self.movies[indexPath.row]
+ movieCell.imageView.image = UIImage(named: movie.posterPath)
+
+ return movieCell
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/DetailViewController.swift b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/DetailViewController.swift
new file mode 100644
index 0000000..9ef785b
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/DetailViewController.swift
@@ -0,0 +1,21 @@
+//
+// MovieViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class DetailViewController: UIViewController {
+ @IBOutlet weak var backdropImageView: UIImageView!
+ @IBOutlet weak var backdropActivityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var titleLabel: UILabel!
+ @IBOutlet weak var ratingLabel: UILabel!
+ @IBOutlet weak var summaryLabel: UILabel!
+ @IBOutlet weak var releaseDateLabel: UILabel!
+ @IBOutlet weak var genresLabel: UILabel!
+ @IBOutlet weak var runtimeLabel: UILabel!
+}
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/FilterViewController.swift b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/FilterViewController.swift
new file mode 100644
index 0000000..853c0bf
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/FilterViewController.swift
@@ -0,0 +1,20 @@
+//
+// FiltersViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class FilterViewController: UIViewController {
+ @IBAction func cancel(sender: AnyObject) {
+ self.dismiss()
+ }
+
+ func dismiss() {
+ self.navigationController?.dismissViewControllerAnimated(true, completion: nil)
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store
new file mode 100644
index 0000000..c068369
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..7997783
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,44 @@
+{
+ "images" : [
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-29@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-40@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-60@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-60@3x.png",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png
new file mode 100644
index 0000000..d463ba9
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png
new file mode 100644
index 0000000..e421cfa
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png
new file mode 100644
index 0000000..2be6555
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png
new file mode 100644
index 0000000..efa69d2
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png
new file mode 100644
index 0000000..efa69d2
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png
new file mode 100644
index 0000000..e405742
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..0f84226
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "bt6DhdALyhf90gReozoQ0y3R3vZ.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg
new file mode 100644
index 0000000..1e19bbb
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..5d9e965
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..3124e77
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "umR9aXTxOxQUuDH2DamoJ5fIPB.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg
new file mode 100644
index 0000000..f4c469c
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..ed3e63e
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "eDildzNrm4XJABWkNKtqB29t6mv.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg
new file mode 100644
index 0000000..90ede16
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..8d49e39
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png
new file mode 100644
index 0000000..68aa392
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png
new file mode 100644
index 0000000..bb5d8b4
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png
new file mode 100644
index 0000000..12923f2
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json
new file mode 100644
index 0000000..4e659b8
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "settings.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "settings@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "settings@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png
new file mode 100644
index 0000000..e2d21f0
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png
new file mode 100644
index 0000000..6fd890d
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png
new file mode 100644
index 0000000..d68af6b
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json
new file mode 100644
index 0000000..50564ce
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "star.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "star@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "star@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png
new file mode 100644
index 0000000..2b2b41b
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png
new file mode 100644
index 0000000..f1367c8
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png
new file mode 100644
index 0000000..390ad8e
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json
new file mode 100644
index 0000000..04ea068
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "tag.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "tag@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "tag@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png
new file mode 100644
index 0000000..d46a1af
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png
new file mode 100644
index 0000000..5d176aa
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png
new file mode 100644
index 0000000..bee24d8
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json
new file mode 100644
index 0000000..16f2d86
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json
new file mode 100644
index 0000000..2febbf6
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json
new file mode 100644
index 0000000..37c7f9d
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json
new file mode 100644
index 0000000..8e8af21
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "interview.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "interview-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "interview-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json
new file mode 100644
index 0000000..4b2222a
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "Placeholder.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "Placeholder@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "Placeholder@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png
new file mode 100644
index 0000000..4f45f19
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png
new file mode 100644
index 0000000..e21d629
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png
new file mode 100644
index 0000000..6d89554
Binary files /dev/null and b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png differ
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Info.plist b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Info.plist
new file mode 100644
index 0000000..aab298d
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Info.plist
@@ -0,0 +1,52 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleDisplayName
+ Swift Movies
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ phillycocoa.$(PRODUCT_NAME:rfc1034identifier)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UIStatusBarTintParameters
+
+ UINavigationBar
+
+ Style
+ UIBarStyleDefault
+ Translucent
+
+
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+
+
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Movie.swift b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Movie.swift
new file mode 100644
index 0000000..dea2208
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/Movie.swift
@@ -0,0 +1,44 @@
+//
+// Movie.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+final class Movie {
+ let title: String
+ let posterPath: String
+ //let averageRating: Double
+ //let voteCount: Int
+ let rating: Rating
+
+ // Swift requires that all properties (except optionals which we will cover later)
+ // be initialized prior to the creation of the object
+ /* init(title: String, posterPath: String, averageRating: Double, voteCount: Int) {
+ // Try commenting one out to see what happens
+ self.title = title
+ self.posterPath = posterPath
+ self.averageRating = averageRating
+ self.voteCount = voteCount
+ }*/
+
+ init(title: String, posterPath: String, rating: Rating) {
+ // Try commenting one out to see what happens
+ self.title = title
+ self.posterPath = posterPath
+ self.rating = rating
+ }
+
+ convenience init(title: String, posterPath: String, averageRating: Double, voteCount: Int) {
+ let rating = Rating(averageRating: averageRating, voteCount: voteCount)
+ self.init(title: title, posterPath: posterPath, rating: rating)
+ }
+}
+
+struct Rating {
+ let averageRating: Double
+ let voteCount: Int
+}
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/SettingsViewController.swift b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/SettingsViewController.swift
new file mode 100644
index 0000000..b4599f1
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/SettingsViewController.swift
@@ -0,0 +1,59 @@
+//
+// SettingsController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/7/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class SettingsViewController: UITableViewController {
+ // Private properties are only available to the instance of the object (can't be called from another object)
+ // Its good practice for things you know will only be used internally
+ private let webViewSegue = "showWebView"
+ private var webViewProperties: (title: String?, urlString: String?)
+
+ override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
+ let path = (indexPath.section, indexPath.row)
+
+ // We can use tuples and a switch to cover our row actions without a big if/else mess
+ // We are also using a tuple to capture the title and url in one variable
+ switch path {
+ case (0, 0):
+ self.webViewProperties = ("@themoviedb", "http://twitter.com/themoviedb")
+ case (0, 1):
+ self.webViewProperties = ("The Movie DB", "http://facebook.com/themoviedb")
+ case (1, 0):
+ self.webViewProperties = ("Terms of Service", "http://themoviedb.org/documentation/website/terms-of-use")
+ case (1, 1):
+ self.webViewProperties = ("Privacy Policy", "http://themoviedb.org/privacy-policy")
+ default:
+ // This should never happen, but lets get in the mindset of handling issues gracefully
+ // Swift will actually give an error if we don't have this default case (must be exhaustive)
+ // We can demonstrate this by commenting out one of our cell handlers then tapping that cell
+ let alertTitle = "Sorry!"
+ let alertMessage = "An unknown error occurred."
+ let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: UIAlertControllerStyle.Alert)
+ alert.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default, handler: nil))
+ self.presentViewController(alert, animated: true, completion: nil)
+ self.tableView.deselectRowAtIndexPath(indexPath, animated: false) // Deselect the cell so it does not "stick"
+
+ // Return so we don't perform the segue
+ return
+ }
+
+ // Since all the various rows are going to the same view controller, we can trigger the
+ // segue manually instead of having to create 4 segues pointing to the same controller
+ self.performSegueWithIdentifier(webViewSegue, sender: self)
+ }
+
+ override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
+ if segue.identifier == webViewSegue {
+ let webViewController = segue.destinationViewController as WebViewController
+ webViewController.titleString = self.webViewProperties.title
+ webViewController.urlString = self.webViewProperties.urlString
+ }
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift
new file mode 100644
index 0000000..f26c7e7
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift
@@ -0,0 +1,1335 @@
+// SwiftyJSON.swift
+//
+// Copyright (c) 2014 Ruoyu Fu, Pinglin Tang
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+// MARK: - Error
+
+///Error domain
+public let ErrorDomain: String! = "SwiftyJSONErrorDomain"
+
+///Error code
+public let ErrorUnsupportedType: Int! = 999
+public let ErrorIndexOutOfBounds: Int! = 900
+public let ErrorWrongType: Int! = 901
+public let ErrorNotExist: Int! = 500
+
+// MARK: - JSON Type
+
+/**
+JSON's type definitions.
+
+See http://tools.ietf.org/html/rfc7231#section-4.3
+*/
+public enum Type :Int{
+
+ case Number
+ case String
+ case Bool
+ case Array
+ case Dictionary
+ case Null
+ case Unknown
+}
+
+// MARK: - JSON Base
+
+public struct JSON {
+
+ /**
+ Creates a JSON using the data.
+
+ :param: data The NSData used to convert to json.Top level object in data is an NSArray or NSDictionary
+ :param: opt The JSON serialization reading options. `.AllowFragments` by default.
+ :param: error error The NSErrorPointer used to return the error. `nil` by default.
+
+ :returns: The created JSON
+ */
+ public init(data:NSData, options opt: NSJSONReadingOptions = .AllowFragments, error: NSErrorPointer = nil) {
+ if let object: AnyObject = NSJSONSerialization.JSONObjectWithData(data, options: opt, error: error) {
+ self.init(object)
+ } else {
+ self.init(NSNull())
+ }
+ }
+
+ /**
+ Creates a JSON using the object.
+
+ :param: object The object must have the following properties: All objects are NSString/String, NSNumber/Int/Float/Double/Bool, NSArray/Array, NSDictionary/Dictionary, or NSNull; All dictionary keys are NSStrings/String; NSNumbers are not NaN or infinity.
+
+ :returns: The created JSON
+ */
+ public init(_ object: AnyObject) {
+ self.object = object
+ }
+
+ /// Private object
+ private var _object: AnyObject = NSNull()
+ /// Private type
+ private var _type: Type = .Null
+ /// prviate error
+ private var _error: NSError?
+
+ /// Object in JSON
+ public var object: AnyObject {
+ get {
+ return _object
+ }
+ set {
+ _object = newValue
+ switch newValue {
+ case let number as NSNumber:
+ if number.isBool {
+ _type = .Bool
+ } else {
+ _type = .Number
+ }
+ case let string as NSString:
+ _type = .String
+ case let null as NSNull:
+ _type = .Null
+ case let array as [AnyObject]:
+ _type = .Array
+ case let dictionary as [String : AnyObject]:
+ _type = .Dictionary
+ default:
+ _type = .Unknown
+ _object = NSNull()
+ _error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"])
+ }
+ }
+ }
+
+ /// json type
+ public var type: Type { get { return _type } }
+
+ /// Error in JSON
+ public var error: NSError? { get { return self._error } }
+
+ /// The static null json
+ public static var nullJSON: JSON { get { return JSON(NSNull()) } }
+
+}
+
+// MARK: - SequenceType
+extension JSON: SequenceType{
+
+ /// If `type` is `.Array` or `.Dictionary`, return `array.empty` or `dictonary.empty` otherwise return `false`.
+ public var isEmpty: Bool {
+ get {
+ switch self.type {
+ case .Array:
+ return (self.object as [AnyObject]).isEmpty
+ case .Dictionary:
+ return (self.object as [String : AnyObject]).isEmpty
+ default:
+ return false
+ }
+ }
+ }
+
+ /// If `type` is `.Array` or `.Dictionary`, return `array.count` or `dictonary.count` otherwise return `0`.
+ public var count: Int {
+ get {
+ switch self.type {
+ case .Array:
+ return self.arrayValue.count
+ case .Dictionary:
+ return self.dictionaryValue.count
+ default:
+ return 0
+ }
+ }
+ }
+
+ /**
+ If `type` is `.Array` or `.Dictionary`, return a generator over the elements like `Array` or `Dictionary, otherwise return a generator over empty.
+
+ :returns: Return a *generator* over the elements of this *sequence*.
+ */
+ public func generate() -> GeneratorOf <(String, JSON)> {
+ switch self.type {
+ case .Array:
+ let array_ = object as [AnyObject]
+ var generate_ = array_.generate()
+ var index_: Int = 0
+ return GeneratorOf<(String, JSON)> {
+ if let element_: AnyObject = generate_.next() {
+ return ("\(index_++)", JSON(element_))
+ } else {
+ return nil
+ }
+ }
+ case .Dictionary:
+ let dictionary_ = object as [String : AnyObject]
+ var generate_ = dictionary_.generate()
+ return GeneratorOf<(String, JSON)> {
+ if let (key_: String, value_: AnyObject) = generate_.next() {
+ return (key_, JSON(value_))
+ } else {
+ return nil
+ }
+ }
+ default:
+ return GeneratorOf<(String, JSON)> {
+ return nil
+ }
+ }
+ }
+}
+
+// MARK: - Subscript
+
+/**
+* To mark both String and Int can be used in subscript.
+*/
+public protocol SubscriptType {}
+
+extension Int: SubscriptType {}
+
+extension String: SubscriptType {}
+
+extension JSON {
+
+ /// If `type` is `.Array`, return json which's object is `array[index]`, otherwise return null json with error.
+ private subscript(#index: Int) -> JSON {
+ get {
+
+ if self.type != .Array {
+ var errorResult_ = JSON.nullJSON
+ errorResult_._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] failure, It is not an array"])
+ return errorResult_
+ }
+
+ let array_ = self.object as [AnyObject]
+
+ if index >= 0 && index < array_.count {
+ return JSON(array_[index])
+ }
+
+ var errorResult_ = JSON.nullJSON
+ errorResult_._error = NSError(domain: ErrorDomain, code:ErrorIndexOutOfBounds , userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] is out of bounds"])
+ return errorResult_
+ }
+ set {
+ if self.type == .Array {
+ var array_ = self.object as [AnyObject]
+ if array_.count > index {
+ array_[index] = newValue.object
+ self.object = array_
+ }
+ }
+ }
+ }
+
+ /// If `type` is `.Dictionary`, return json which's object is `dictionary[key]` , otherwise return null json with error.
+ private subscript(#key: String) -> JSON {
+ get {
+ var returnJSON = JSON.nullJSON
+ if self.type == .Dictionary {
+ if let object_: AnyObject = self.object[key] {
+ returnJSON = JSON(object_)
+ } else {
+ returnJSON._error = NSError(domain: ErrorDomain, code: ErrorNotExist, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] does not exist"])
+ }
+ } else {
+ returnJSON._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] failure, It is not an dictionary"])
+ }
+ return returnJSON
+ }
+ set {
+ if self.type == .Dictionary {
+ var dictionary_ = self.object as [String : AnyObject]
+ dictionary_[key] = newValue.object
+ self.object = dictionary_
+ }
+ }
+ }
+
+ /// If `sub` is `Int`, return `subscript(index:)`; If `sub` is `String`, return `subscript(key:)`.
+ private subscript(#sub: SubscriptType) -> JSON {
+ get {
+ if sub is String {
+ return self[key:sub as String]
+ } else {
+ return self[index:sub as Int]
+ }
+ }
+ set {
+ if sub is String {
+ self[key:sub as String] = newValue
+ } else {
+ self[index:sub as Int] = newValue
+ }
+ }
+ }
+
+ /**
+ Find a json in the complex data structuresby using the Int/String's array.
+
+ :param: path The target json's path. Example:
+
+ let json = JSON[data]
+ let path = [9,"list","person","name"]
+ let name = json[path]
+
+ The same as: let name = json[9]["list"]["person"]["name"]
+
+ :returns: Return a json found by the path or a null json with error
+ */
+ public subscript(path: [SubscriptType]) -> JSON {
+ get {
+ if path.count == 0 {
+ return JSON.nullJSON
+ }
+
+ var next = self
+ for sub in path {
+ next = next[sub:sub]
+ }
+ return next
+ }
+ set {
+
+ switch path.count {
+ case 0: return
+ case 1: self[sub:path[0]] = newValue
+ default:
+ var last = newValue
+ var newPath = path
+ newPath.removeLast()
+ for sub in path.reverse() {
+ var previousLast = self[newPath]
+ previousLast[sub:sub] = last
+ last = previousLast
+ if newPath.count <= 1 {
+ break
+ }
+ newPath.removeLast()
+ }
+ self[sub:newPath[0]] = last
+ }
+ }
+ }
+
+ /**
+ Find a json in the complex data structuresby using the Int/String's array.
+
+ :param: path The target json's path. Example:
+
+ let name = json[9,"list","person","name"]
+
+ The same as: let name = json[9]["list"]["person"]["name"]
+
+ :returns: Return a json found by the path or a null json with error
+ */
+ public subscript(path: SubscriptType...) -> JSON {
+ get {
+ return self[path]
+ }
+ set {
+ self[path] = newValue
+ }
+ }
+}
+
+// MARK: - LiteralConvertible
+
+extension JSON: StringLiteralConvertible {
+
+ public init(stringLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+
+ public init(extendedGraphemeClusterLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+
+ public init(unicodeScalarLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: IntegerLiteralConvertible {
+
+ public init(integerLiteral value: IntegerLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: BooleanLiteralConvertible {
+
+ public init(booleanLiteral value: BooleanLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: FloatLiteralConvertible {
+
+ public init(floatLiteral value: FloatLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: DictionaryLiteralConvertible {
+
+ public init(dictionaryLiteral elements: (String, AnyObject)...) {
+ var dictionary_ = [String : AnyObject]()
+ for (key_, value) in elements {
+ dictionary_[key_] = value
+ }
+ self.init(dictionary_)
+ }
+}
+
+extension JSON: ArrayLiteralConvertible {
+
+ public init(arrayLiteral elements: AnyObject...) {
+ self.init(elements)
+ }
+}
+
+extension JSON: NilLiteralConvertible {
+
+ public init(nilLiteral: ()) {
+ self.init(NSNull())
+ }
+}
+
+// MARK: - Raw
+
+extension JSON: RawRepresentable {
+
+ public init?(rawValue: AnyObject) {
+ if JSON(rawValue).type == .Unknown {
+ return nil
+ } else {
+ self.init(rawValue)
+ }
+ }
+
+ public var rawValue: AnyObject {
+ return self.object
+ }
+
+ public func rawData(options opt: NSJSONWritingOptions = NSJSONWritingOptions(0), error: NSErrorPointer = nil) -> NSData? {
+ return NSJSONSerialization.dataWithJSONObject(self.object, options: opt, error:error)
+ }
+
+ public func rawString(encoding: UInt = NSUTF8StringEncoding, options opt: NSJSONWritingOptions = .PrettyPrinted) -> String? {
+ switch self.type {
+ case .Array, .Dictionary:
+ if let data = self.rawData(options: opt) {
+ return NSString(data: data, encoding: encoding)
+ } else {
+ return nil
+ }
+ case .String:
+ return (self.object as String)
+ case .Number:
+ return (self.object as NSNumber).stringValue
+ case .Bool:
+ return (self.object as Bool).description
+ case .Null:
+ return "null"
+ default:
+ return nil
+ }
+ }
+}
+
+// MARK: - Printable, DebugPrintable
+
+extension JSON: Printable, DebugPrintable {
+
+ public var description: String {
+ if let string = self.rawString(options:.PrettyPrinted) {
+ return string
+ } else {
+ return "unknown"
+ }
+ }
+
+ public var debugDescription: String {
+ return description
+ }
+}
+
+// MARK: - Array
+
+extension JSON {
+
+ //Optional [JSON]
+ public var array: [JSON]? {
+ get {
+ if self.type == .Array {
+ return map(self.object as [AnyObject]){ JSON($0) }
+ } else {
+ return nil
+ }
+ }
+ }
+
+ //Non-optional [JSON]
+ public var arrayValue: [JSON] {
+ get {
+ return self.array ?? []
+ }
+ }
+
+ //Optional [AnyObject]
+ public var arrayObject: [AnyObject]? {
+ get {
+ switch self.type {
+ case .Array:
+ return self.object as? [AnyObject]
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSMutableArray(array: newValue!, copyItems: true)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+}
+
+// MARK: - Dictionary
+
+extension JSON {
+
+ private func _map(source: [Key: Value], transform: Value -> NewValue) -> [Key: NewValue] {
+ var result = [Key: NewValue](minimumCapacity:source.count)
+ for (key,value) in source {
+ result[key] = transform(value)
+ }
+ return result
+ }
+
+ //Optional [String : JSON]
+ public var dictionary: [String : JSON]? {
+ get {
+ if self.type == .Dictionary {
+ return _map(self.object as [String : AnyObject]){ JSON($0) }
+ } else {
+ return nil
+ }
+ }
+ }
+
+ //Non-optional [String : JSON]
+ public var dictionaryValue: [String : JSON] {
+ get {
+ return self.dictionary ?? [:]
+ }
+ }
+
+ //Optional [String : AnyObject]
+ public var dictionaryObject: [String : AnyObject]? {
+ get {
+ switch self.type {
+ case .Dictionary:
+ return self.object as? [String : AnyObject]
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSMutableDictionary(dictionary: newValue!, copyItems: true)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+}
+
+// MARK: - Bool
+
+extension JSON: BooleanType {
+
+ //Optional bool
+ public var bool: Bool? {
+ get {
+ switch self.type {
+ case .Bool:
+ return self.object.boolValue
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(bool: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ //Non-optional bool
+ public var boolValue: Bool {
+ get {
+ switch self.type {
+ case .Bool, .Number, .String:
+ return self.object.boolValue
+ default:
+ return false
+ }
+ }
+ set {
+ self.object = NSNumber(bool: newValue)
+ }
+ }
+}
+
+// MARK: - String
+
+extension JSON {
+
+ //Optional string
+ public var string: String? {
+ get {
+ switch self.type {
+ case .String:
+ return self.object as? String
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSString(string:newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ //Non-optional string
+ public var stringValue: String {
+ get {
+ switch self.type {
+ case .String:
+ return self.object as String
+ case .Number:
+ return self.object.stringValue
+ case .Bool:
+ return (self.object as Bool).description
+ default:
+ return ""
+ }
+ }
+ set {
+ self.object = NSString(string:newValue)
+ }
+ }
+}
+
+// MARK: - Number
+extension JSON {
+
+ //Optional number
+ public var number: NSNumber? {
+ get {
+ switch self.type {
+ case .Number, .Bool:
+ return self.object as? NSNumber
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = newValue?.copy() ?? NSNull()
+ }
+ }
+
+ //Non-optional number
+ public var numberValue: NSNumber {
+ get {
+ switch self.type {
+ case .String:
+ let scanner = NSScanner(string: self.object as String)
+ if scanner.scanDouble(nil){
+ if (scanner.atEnd) {
+ return NSNumber(double:(self.object as NSString).doubleValue)
+ }
+ }
+ return NSNumber(double: 0.0)
+ case .Number, .Bool:
+ return self.object as NSNumber
+ default:
+ return NSNumber(double: 0.0)
+ }
+ }
+ set {
+ self.object = newValue.copy()
+ }
+ }
+}
+
+//MARK: - Null
+extension JSON {
+
+ public var null: NSNull? {
+ get {
+ switch self.type {
+ case .Null:
+ return NSNull()
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = NSNull()
+ }
+ }
+}
+
+//MARK: - URL
+extension JSON {
+
+ //Optional URL
+ public var URL: NSURL? {
+ get {
+ switch self.type {
+ case .String:
+ if let encodedString_ = self.object.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
+ return NSURL(string: encodedString_)
+ } else {
+ return nil
+ }
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = newValue?.absoluteString ?? NSNull()
+ }
+ }
+}
+
+// MARK: - Int, Double, Float, Int8, Int16, Int32, Int64
+
+extension JSON {
+
+ public var double: Double? {
+ get {
+ return self.number?.doubleValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(double: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var doubleValue: Double {
+ get {
+ return self.numberValue.doubleValue
+ }
+ set {
+ self.object = NSNumber(double: newValue)
+ }
+ }
+
+ public var float: Float? {
+ get {
+ return self.number?.floatValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(float: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var floatValue: Float {
+ get {
+ return self.numberValue.floatValue
+ }
+ set {
+ self.object = NSNumber(float: newValue)
+ }
+ }
+
+ public var int: Int? {
+ get {
+ return self.number?.longValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(integer: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var intValue: Int {
+ get {
+ return self.numberValue.integerValue
+ }
+ set {
+ self.object = NSNumber(integer: newValue)
+ }
+ }
+
+ public var uInt: UInt? {
+ get {
+ return self.number?.unsignedLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uIntValue: UInt {
+ get {
+ return self.numberValue.unsignedLongValue
+ }
+ set {
+ self.object = NSNumber(unsignedLong: newValue)
+ }
+ }
+
+ public var int8: Int8? {
+ get {
+ return self.number?.charValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(char: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int8Value: Int8 {
+ get {
+ return self.numberValue.charValue
+ }
+ set {
+ self.object = NSNumber(char: newValue)
+ }
+ }
+
+ public var uInt8: UInt8? {
+ get {
+ return self.number?.unsignedCharValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedChar: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt8Value: UInt8 {
+ get {
+ return self.numberValue.unsignedCharValue
+ }
+ set {
+ self.object = NSNumber(unsignedChar: newValue)
+ }
+ }
+
+ public var int16: Int16? {
+ get {
+ return self.number?.shortValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(short: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int16Value: Int16 {
+ get {
+ return self.numberValue.shortValue
+ }
+ set {
+ self.object = NSNumber(short: newValue)
+ }
+ }
+
+ public var uInt16: UInt16? {
+ get {
+ return self.number?.unsignedShortValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedShort: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt16Value: UInt16 {
+ get {
+ return self.numberValue.unsignedShortValue
+ }
+ set {
+ self.object = NSNumber(unsignedShort: newValue)
+ }
+ }
+
+ public var int32: Int32? {
+ get {
+ return self.number?.intValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(int: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int32Value: Int32 {
+ get {
+ return self.numberValue.intValue
+ }
+ set {
+ self.object = NSNumber(int: newValue)
+ }
+ }
+
+ public var uInt32: UInt32? {
+ get {
+ return self.number?.unsignedIntValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedInt: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt32Value: UInt32 {
+ get {
+ return self.numberValue.unsignedIntValue
+ }
+ set {
+ self.object = NSNumber(unsignedInt: newValue)
+ }
+ }
+
+ public var int64: Int64? {
+ get {
+ return self.number?.longLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(longLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int64Value: Int64 {
+ get {
+ return self.numberValue.longLongValue
+ }
+ set {
+ self.object = NSNumber(longLong: newValue)
+ }
+ }
+
+ public var uInt64: UInt64? {
+ get {
+ return self.number?.unsignedLongLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedLongLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt64Value: UInt64 {
+ get {
+ return self.numberValue.unsignedLongLongValue
+ }
+ set {
+ self.object = NSNumber(unsignedLongLong: newValue)
+ }
+ }
+}
+
+//MARK: - Comparable
+extension JSON: Comparable {}
+
+public func ==(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) == (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) == (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func <=(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) <= (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) <= (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func >=(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) >= (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) >= (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func >(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) > (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) > (rhs.object as String)
+ default:
+ return false
+ }
+}
+
+public func <(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) < (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) < (rhs.object as String)
+ default:
+ return false
+ }
+}
+
+private let trueNumber = NSNumber(bool: true)
+private let falseNumber = NSNumber(bool: false)
+private let trueObjCType = String.fromCString(trueNumber.objCType)
+private let falseObjCType = String.fromCString(falseNumber.objCType)
+
+// MARK: - NSNumber: Comparable
+
+extension NSNumber: Comparable {
+ var isBool:Bool {
+ get {
+ let objCType = String.fromCString(self.objCType)
+ if (self.compare(trueNumber) == NSComparisonResult.OrderedSame && objCType == trueObjCType) || (self.compare(falseNumber) == NSComparisonResult.OrderedSame && objCType == falseObjCType){
+ return true
+ } else {
+ return false
+ }
+ }
+ }
+}
+
+public func ==(lhs: NSNumber, rhs: NSNumber) -> Bool {
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedSame
+ }
+}
+
+public func !=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+ return !(lhs == rhs)
+}
+
+public func <(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedAscending
+ }
+}
+
+public func >(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedDescending
+ }
+}
+
+public func <=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) != NSComparisonResult.OrderedDescending
+ }
+}
+
+public func >=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) != NSComparisonResult.OrderedAscending
+ }
+}
+
+//MARK:- Unavailable
+
+@availability(*, unavailable, renamed="JSON")
+public typealias JSONValue = JSON
+
+extension JSON {
+
+ @availability(*, unavailable, message="use 'init(_ object:AnyObject)' instead")
+ public init(object: AnyObject) {
+ self = JSON(object)
+ }
+
+ @availability(*, unavailable, renamed="dictionaryObject")
+ public var dictionaryObjects: [String : AnyObject]? {
+ get { return self.dictionaryObject }
+ }
+
+ @availability(*, unavailable, renamed="arrayObject")
+ public var arrayObjects: [AnyObject]? {
+ get { return self.arrayObject }
+ }
+
+ @availability(*, unavailable, renamed="int8")
+ public var char: Int8? {
+ get {
+ return self.number?.charValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int8Value")
+ public var charValue: Int8 {
+ get {
+ return self.numberValue.charValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt8")
+ public var unsignedChar: UInt8? {
+ get{
+ return self.number?.unsignedCharValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt8Value")
+ public var unsignedCharValue: UInt8 {
+ get{
+ return self.numberValue.unsignedCharValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int16")
+ public var short: Int16? {
+ get{
+ return self.number?.shortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int16Value")
+ public var shortValue: Int16 {
+ get{
+ return self.numberValue.shortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt16")
+ public var unsignedShort: UInt16? {
+ get{
+ return self.number?.unsignedShortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt16Value")
+ public var unsignedShortValue: UInt16 {
+ get{
+ return self.numberValue.unsignedShortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int")
+ public var long: Int? {
+ get{
+ return self.number?.longValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="intValue")
+ public var longValue: Int {
+ get{
+ return self.numberValue.longValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt")
+ public var unsignedLong: UInt? {
+ get{
+ return self.number?.unsignedLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uIntValue")
+ public var unsignedLongValue: UInt {
+ get{
+ return self.numberValue.unsignedLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int64")
+ public var longLong: Int64? {
+ get{
+ return self.number?.longLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int64Value")
+ public var longLongValue: Int64 {
+ get{
+ return self.numberValue.longLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt64")
+ public var unsignedLongLong: UInt64? {
+ get{
+ return self.number?.unsignedLongLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt64Value")
+ public var unsignedLongLongValue: UInt64 {
+ get{
+ return self.numberValue.unsignedLongLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int")
+ public var integer: Int? {
+ get {
+ return self.number?.integerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="intValue")
+ public var integerValue: Int {
+ get {
+ return self.numberValue.integerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt")
+ public var unsignedInteger: Int? {
+ get {
+ return self.number?.unsignedIntegerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uIntValue")
+ public var unsignedIntegerValue: Int {
+ get {
+ return self.numberValue.unsignedIntegerValue
+ }
+ }
+}
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/TMDB.swift b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/TMDB.swift
new file mode 100644
index 0000000..323a50a
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/TMDB.swift
@@ -0,0 +1,13 @@
+//
+// TMDB.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import Foundation
+
+let TMDB_API_KEY = "8a4a247d072d9ca4a0072893ab60e277"
+let TMDB_API_BASE_URL = "http://api.themoviedb.org/3"
+let TMDB_IMAGE_BASE_URL = "http://image.tmdb.org/t/p"
\ No newline at end of file
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/WebViewController.swift b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/WebViewController.swift
new file mode 100644
index 0000000..8afdbcf
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMovies/WebViewController.swift
@@ -0,0 +1,50 @@
+//
+// WebViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of WebViewController (optimization)
+final class WebViewController: UIViewController {
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var webView: UIWebView!
+
+ var uNrlString: String?
+ var titleString: String?
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.webView.delegate = self
+
+ // Since our titleString and urlString are optionals we have to unwrap them
+ if let title = titleString {
+ self.navigationItem.title = titleString
+ }
+
+ if let urlString = self.urlString {
+ // The NSURL init method returns an optional as well
+ // Its common for Cocoa methods to return optionals (because of Obj-C)
+ if let url = NSURL(string: urlString) {
+ let request = NSURLRequest(URL: url)
+ webView.loadRequest(request)
+ }
+ }
+ }
+}
+
+// Class extensions make it easy to group functionality, like protocol methods
+extension WebViewController: UIWebViewDelegate {
+ // These methods are called automatically when we set the delegate
+ // and adopt the protocol
+ func webViewDidStartLoad(webView: UIWebView) {
+ self.activityIndicator.startAnimating()
+ }
+
+ func webViewDidFinishLoad(webView: UIWebView) {
+ self.activityIndicator.stopAnimating()
+ }
+}
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMoviesTests/Info.plist b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMoviesTests/Info.plist
new file mode 100644
index 0000000..2afc012
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMoviesTests/Info.plist
@@ -0,0 +1,24 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ phillycocoa.$(PRODUCT_NAME:rfc1034identifier)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ BNDL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+
+
diff --git a/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift
new file mode 100644
index 0000000..3cb0bdc
--- /dev/null
+++ b/2 - Act I/2 - Finished Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift
@@ -0,0 +1,36 @@
+//
+// SwiftMoviesTests.swift
+// SwiftMoviesTests
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+import XCTest
+
+class SwiftMoviesTests: 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/2 - Act I/Functions.playground/contents.xcplayground b/2 - Act I/Functions.playground/contents.xcplayground
new file mode 100644
index 0000000..8e39341
--- /dev/null
+++ b/2 - Act I/Functions.playground/contents.xcplayground
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/2 - Act I/Functions.playground/section-1.swift b/2 - Act I/Functions.playground/section-1.swift
new file mode 100644
index 0000000..b26a90f
--- /dev/null
+++ b/2 - Act I/Functions.playground/section-1.swift
@@ -0,0 +1,16 @@
+import Foundation
+
+func sum(number1: Int, number2: Int) -> Int {
+ return number1 + number2
+}
+
+// we can assign functions to constants/variables (first class)
+let operation:(Int, Int) -> Int = sum;
+operation(10, 20)
+
+let mySum = sum(10, 10)
+
+// if we don't specify a return type Swift automatically does -> Void
+func logSomething() {
+ println("something")
+}
\ No newline at end of file
diff --git a/2 - Act I/Functions.playground/timeline.xctimeline b/2 - Act I/Functions.playground/timeline.xctimeline
new file mode 100644
index 0000000..bf468af
--- /dev/null
+++ b/2 - Act I/Functions.playground/timeline.xctimeline
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/2 - Act I/StructVsClass.playground/contents.xcplayground b/2 - Act I/StructVsClass.playground/contents.xcplayground
new file mode 100644
index 0000000..8e39341
--- /dev/null
+++ b/2 - Act I/StructVsClass.playground/contents.xcplayground
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/2 - Act I/StructVsClass.playground/section-1.swift b/2 - Act I/StructVsClass.playground/section-1.swift
new file mode 100644
index 0000000..171dc82
--- /dev/null
+++ b/2 - Act I/StructVsClass.playground/section-1.swift
@@ -0,0 +1,46 @@
+
+class Movie {
+ var averageRating = 5.0
+}
+
+struct Rating {
+ var averageRating = 5.0
+}
+
+var aliens = Movie()
+var referenceToAliens = aliens
+aliens.averageRating = 9.5
+aliens.averageRating
+referenceToAliens.averageRating
+// Values are the same
+
+var aliensRating = Rating()
+var referenceToAliensRating = aliensRating
+aliensRating.averageRating = 9.5
+aliensRating.averageRating
+referenceToAliensRating.averageRating
+// Values are not the same
+// Its not actually referencing the original
+// Its copying the values
+
+/*
+ Another significant difference between classes and structs is how they handle being a constant.
+
+ Classes - a constant can have its properties altered (if they are variables) but the object itself can't be reassigned
+
+ Structs - you can't alter their values or reassign them
+*/
+
+var variableMovie = Movie()
+let constantMovie = Movie()
+constantMovie.averageRating = 10.0 // -> Works
+// constantMovie = variableMovie // -> Error: can't assign to constant value
+
+var variableRating = Rating()
+let constantRating = Rating()
+variableRating.averageRating = 9.0
+// constantRating.averageRating = 9.0 // -> Error: can't assign
+// constantRating = variableRating // -> Error
+
+// With structs the entire struct is constant
+// Swift Arrays and Dictionaries are examples of structs
\ No newline at end of file
diff --git a/2 - Act I/StructVsClass.playground/timeline.xctimeline b/2 - Act I/StructVsClass.playground/timeline.xctimeline
new file mode 100644
index 0000000..bf468af
--- /dev/null
+++ b/2 - Act I/StructVsClass.playground/timeline.xctimeline
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/2 - Act I/Tuples.playground/contents.xcplayground b/2 - Act I/Tuples.playground/contents.xcplayground
new file mode 100644
index 0000000..8e39341
--- /dev/null
+++ b/2 - Act I/Tuples.playground/contents.xcplayground
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/2 - Act I/Tuples.playground/section-1.swift b/2 - Act I/Tuples.playground/section-1.swift
new file mode 100644
index 0000000..0229b14
--- /dev/null
+++ b/2 - Act I/Tuples.playground/section-1.swift
@@ -0,0 +1,15 @@
+// Playground - noun: a place where people can play
+
+import UIKit
+
+let home = (221, "Baker Street")
+println(home.0)
+println(home.1)
+
+let (number, street) = home
+println(number)
+
+let address = (number: 221, street: "Baker Street")
+println(address.street)
+
+let three: (Int, Int, Int) = (1,2,3)
diff --git a/2 - Act I/Tuples.playground/timeline.xctimeline b/2 - Act I/Tuples.playground/timeline.xctimeline
new file mode 100644
index 0000000..bf468af
--- /dev/null
+++ b/2 - Act I/Tuples.playground/timeline.xctimeline
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/3 - Act II/.DS_Store b/3 - Act II/.DS_Store
new file mode 100644
index 0000000..ec17f7a
Binary files /dev/null and b/3 - Act II/.DS_Store differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/.DS_Store b/3 - Act II/1 - Starting Project/SwiftMovies/.DS_Store
new file mode 100644
index 0000000..59b421f
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/.DS_Store differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..02bd8c2
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj
@@ -0,0 +1,474 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ F45D76761A5FD9FE001807F2 /* SwiftyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */; };
+ F4646C331A5DF40800336DFC /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4646C321A5DF40800336DFC /* SettingsViewController.swift */; };
+ F4678DB91A5A82F1005A33DE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DB81A5A82F1005A33DE /* AppDelegate.swift */; };
+ F4678DC01A5A82F1005A33DE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F4678DBE1A5A82F1005A33DE /* Main.storyboard */; };
+ F4678DC21A5A82F1005A33DE /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F4678DC11A5A82F1005A33DE /* Images.xcassets */; };
+ F4678DC51A5A82F1005A33DE /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */; };
+ F4678DD11A5A82F1005A33DE /* SwiftMoviesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */; };
+ F4678DE11A5A9582005A33DE /* Movie.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DE01A5A9582005A33DE /* Movie.swift */; };
+ F477D6AE1A5F20E2006FD97E /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */; };
+ F477D6B21A5F20FF006FD97E /* FilterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F477D6B11A5F20FF006FD97E /* FilterViewController.swift */; };
+ F49C6F8A1A5F47B200D0C49E /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F49C6F891A5F47B200D0C49E /* WebViewController.swift */; };
+ F4DC98D01A5E5B0C0030CC99 /* CollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */; };
+ F4DC98D21A5E6B460030CC99 /* TMDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4DC98D11A5E6B460030CC99 /* TMDB.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ F4678DCB1A5A82F1005A33DE /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = F4678DAB1A5A82F1005A33DE /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F4678DB21A5A82F1005A33DE;
+ remoteInfo = SwiftMovies;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyJSON.swift; sourceTree = ""; };
+ F4646C321A5DF40800336DFC /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; };
+ F4678DB31A5A82F1005A33DE /* SwiftMovies.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftMovies.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ F4678DB71A5A82F1005A33DE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ F4678DB81A5A82F1005A33DE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ F4678DBF1A5A82F1005A33DE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
+ F4678DC11A5A82F1005A33DE /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
+ F4678DC41A5A82F1005A33DE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
+ F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftMoviesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ F4678DCF1A5A82F1005A33DE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftMoviesTests.swift; sourceTree = ""; };
+ F4678DE01A5A9582005A33DE /* Movie.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Movie.swift; sourceTree = ""; };
+ F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; };
+ F477D6B11A5F20FF006FD97E /* FilterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilterViewController.swift; sourceTree = ""; };
+ F49C6F891A5F47B200D0C49E /* WebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebViewController.swift; sourceTree = ""; };
+ F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewController.swift; sourceTree = ""; };
+ F4DC98D11A5E6B460030CC99 /* TMDB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TMDB.swift; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ F4678DB01A5A82F1005A33DE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC71A5A82F1005A33DE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ F4678DAA1A5A82F1005A33DE = {
+ isa = PBXGroup;
+ children = (
+ F4678DB51A5A82F1005A33DE /* SwiftMovies */,
+ F4678DCD1A5A82F1005A33DE /* SwiftMoviesTests */,
+ F4678DB41A5A82F1005A33DE /* Products */,
+ );
+ sourceTree = "";
+ };
+ F4678DB41A5A82F1005A33DE /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DB31A5A82F1005A33DE /* SwiftMovies.app */,
+ F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ F4678DB51A5A82F1005A33DE /* SwiftMovies */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DB81A5A82F1005A33DE /* AppDelegate.swift */,
+ F4678DC11A5A82F1005A33DE /* Images.xcassets */,
+ F477D6AA1A5F209D006FD97E /* Controllers */,
+ F477D6B31A5F210F006FD97E /* Models */,
+ F477D6B71A5F215E006FD97E /* Networking */,
+ F4678DBE1A5A82F1005A33DE /* Main.storyboard */,
+ F4678DB61A5A82F1005A33DE /* Supporting Files */,
+ );
+ path = SwiftMovies;
+ sourceTree = "";
+ };
+ F4678DB61A5A82F1005A33DE /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */,
+ F4678DB71A5A82F1005A33DE /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ F4678DCD1A5A82F1005A33DE /* SwiftMoviesTests */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */,
+ F4678DCE1A5A82F1005A33DE /* Supporting Files */,
+ );
+ path = SwiftMoviesTests;
+ sourceTree = "";
+ };
+ F4678DCE1A5A82F1005A33DE /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DCF1A5A82F1005A33DE /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ F477D6AA1A5F209D006FD97E /* Controllers */ = {
+ isa = PBXGroup;
+ children = (
+ F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */,
+ F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */,
+ F477D6B11A5F20FF006FD97E /* FilterViewController.swift */,
+ F4646C321A5DF40800336DFC /* SettingsViewController.swift */,
+ F49C6F891A5F47B200D0C49E /* WebViewController.swift */,
+ );
+ name = Controllers;
+ sourceTree = "";
+ };
+ F477D6B31A5F210F006FD97E /* Models */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DE01A5A9582005A33DE /* Movie.swift */,
+ );
+ name = Models;
+ sourceTree = "";
+ };
+ F477D6B71A5F215E006FD97E /* Networking */ = {
+ isa = PBXGroup;
+ children = (
+ F4DC98D11A5E6B460030CC99 /* TMDB.swift */,
+ F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */,
+ );
+ name = Networking;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ F4678DB21A5A82F1005A33DE /* SwiftMovies */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F4678DD41A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMovies" */;
+ buildPhases = (
+ F4678DAF1A5A82F1005A33DE /* Sources */,
+ F4678DB01A5A82F1005A33DE /* Frameworks */,
+ F4678DB11A5A82F1005A33DE /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = SwiftMovies;
+ productName = SwiftMovies;
+ productReference = F4678DB31A5A82F1005A33DE /* SwiftMovies.app */;
+ productType = "com.apple.product-type.application";
+ };
+ F4678DC91A5A82F1005A33DE /* SwiftMoviesTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F4678DD71A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMoviesTests" */;
+ buildPhases = (
+ F4678DC61A5A82F1005A33DE /* Sources */,
+ F4678DC71A5A82F1005A33DE /* Frameworks */,
+ F4678DC81A5A82F1005A33DE /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ F4678DCC1A5A82F1005A33DE /* PBXTargetDependency */,
+ );
+ name = SwiftMoviesTests;
+ productName = SwiftMoviesTests;
+ productReference = F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ F4678DAB1A5A82F1005A33DE /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0610;
+ ORGANIZATIONNAME = "Philly Cocoaheads";
+ TargetAttributes = {
+ F4678DB21A5A82F1005A33DE = {
+ CreatedOnToolsVersion = 6.1.1;
+ };
+ F4678DC91A5A82F1005A33DE = {
+ CreatedOnToolsVersion = 6.1.1;
+ TestTargetID = F4678DB21A5A82F1005A33DE;
+ };
+ };
+ };
+ buildConfigurationList = F4678DAE1A5A82F1005A33DE /* Build configuration list for PBXProject "SwiftMovies" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = F4678DAA1A5A82F1005A33DE;
+ productRefGroup = F4678DB41A5A82F1005A33DE /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ F4678DB21A5A82F1005A33DE /* SwiftMovies */,
+ F4678DC91A5A82F1005A33DE /* SwiftMoviesTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ F4678DB11A5A82F1005A33DE /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4678DC01A5A82F1005A33DE /* Main.storyboard in Resources */,
+ F4678DC51A5A82F1005A33DE /* LaunchScreen.xib in Resources */,
+ F4678DC21A5A82F1005A33DE /* Images.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC81A5A82F1005A33DE /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ F4678DAF1A5A82F1005A33DE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4646C331A5DF40800336DFC /* SettingsViewController.swift in Sources */,
+ F477D6AE1A5F20E2006FD97E /* DetailViewController.swift in Sources */,
+ F49C6F8A1A5F47B200D0C49E /* WebViewController.swift in Sources */,
+ F45D76761A5FD9FE001807F2 /* SwiftyJSON.swift in Sources */,
+ F4DC98D01A5E5B0C0030CC99 /* CollectionViewController.swift in Sources */,
+ F4678DE11A5A9582005A33DE /* Movie.swift in Sources */,
+ F4DC98D21A5E6B460030CC99 /* TMDB.swift in Sources */,
+ F477D6B21A5F20FF006FD97E /* FilterViewController.swift in Sources */,
+ F4678DB91A5A82F1005A33DE /* AppDelegate.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC61A5A82F1005A33DE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4678DD11A5A82F1005A33DE /* SwiftMoviesTests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ F4678DCC1A5A82F1005A33DE /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F4678DB21A5A82F1005A33DE /* SwiftMovies */;
+ targetProxy = F4678DCB1A5A82F1005A33DE /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ F4678DBE1A5A82F1005A33DE /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F4678DBF1A5A82F1005A33DE /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "";
+ };
+ F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F4678DC41A5A82F1005A33DE /* Base */,
+ );
+ name = LaunchScreen.xib;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ F4678DD21A5A82F1005A33DE /* 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.1;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ F4678DD31A5A82F1005A33DE /* 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.1;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ F4678DD51A5A82F1005A33DE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = SwiftMovies/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ F4678DD61A5A82F1005A33DE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = SwiftMovies/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ F4678DD81A5A82F1005A33DE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = SwiftMoviesTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftMovies.app/SwiftMovies";
+ };
+ name = Debug;
+ };
+ F4678DD91A5A82F1005A33DE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = SwiftMoviesTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftMovies.app/SwiftMovies";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ F4678DAE1A5A82F1005A33DE /* Build configuration list for PBXProject "SwiftMovies" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD21A5A82F1005A33DE /* Debug */,
+ F4678DD31A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ F4678DD41A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMovies" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD51A5A82F1005A33DE /* Debug */,
+ F4678DD61A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ F4678DD71A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMoviesTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD81A5A82F1005A33DE /* Debug */,
+ F4678DD91A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = F4678DAB1A5A82F1005A33DE /* Project object */;
+}
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..7890687
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..d0978f8
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
new file mode 100644
index 0000000..fe2b454
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -0,0 +1,5 @@
+
+
+
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme
new file mode 100644
index 0000000..ec387aa
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..dd30f16
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,27 @@
+
+
+
+
+ SchemeUserState
+
+ SwiftMovies.xcscheme
+
+ orderHint
+ 0
+
+
+ SuppressBuildableAutocreation
+
+ F4678DB21A5A82F1005A33DE
+
+ primary
+
+
+ F4678DC91A5A82F1005A33DE
+
+ primary
+
+
+
+
+
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/AppDelegate.swift b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/AppDelegate.swift
new file mode 100644
index 0000000..9c2f2cc
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/AppDelegate.swift
@@ -0,0 +1,46 @@
+//
+// AppDelegate.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+@UIApplicationMain
+class AppDelegate: UIResponder, UIApplicationDelegate {
+
+ var window: UIWindow?
+
+
+ func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> 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/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib
new file mode 100644
index 0000000..9e43426
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..5891448
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard
@@ -0,0 +1,600 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/CollectionViewController.swift b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/CollectionViewController.swift
new file mode 100644
index 0000000..f97efe7
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/CollectionViewController.swift
@@ -0,0 +1,58 @@
+//
+// MovieCollectionController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Since we don't have to worry about headers and imports in Swift
+// It sometimes makes sense to keep multiple classes in the same file
+final class MovieCell: UICollectionViewCell {
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var imageView: UIImageView!
+}
+
+final class CollectionViewController: UIViewController {
+ @IBOutlet weak var collectionView: UICollectionView!
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+
+ // We will later be fetching our movies from the web
+ // so we went to use a var such that we can update our movies after load
+ // We need to have a value, so we default to an empty array
+ var movies: [Movie] = []
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.collectionView.delegate = self
+ self.collectionView.dataSource = self
+ self.loadPlaceholderData()
+ }
+
+ func loadPlaceholderData() {
+ let goneGirl = Movie(title: "Gone Girl", posterPath: "gonePoster", averageRating: 8.1, voteCount: 845)
+ let guardians = Movie(title: "Guardians of the Galaxy", posterPath: "guardiansPoster", averageRating: 9.2, voteCount: 1026)
+ let theHobbit = Movie(title: "The Hobbit", posterPath: "hobbitPoster", averageRating: 7.4, voteCount: 1343)
+ let theInterview = Movie(title: "The Interview", posterPath: "interviewPoster", averageRating: 6.3, voteCount: 824)
+
+ self.movies = [goneGirl, guardians, theHobbit, theInterview]
+ self.collectionView.reloadData()
+ }
+}
+
+// Class extensions make it easy to group functionality, like protocol methods
+extension CollectionViewController: UICollectionViewDelegate, UICollectionViewDataSource {
+ func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+ return self.movies.count
+ }
+
+ func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
+ let movieCell = collectionView.dequeueReusableCellWithReuseIdentifier("movieCell", forIndexPath: indexPath) as MovieCell
+ let movie = self.movies[indexPath.row]
+ movieCell.imageView.image = UIImage(named: movie.posterPath)
+
+ return movieCell
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/DetailViewController.swift b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/DetailViewController.swift
new file mode 100644
index 0000000..9ef785b
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/DetailViewController.swift
@@ -0,0 +1,21 @@
+//
+// MovieViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class DetailViewController: UIViewController {
+ @IBOutlet weak var backdropImageView: UIImageView!
+ @IBOutlet weak var backdropActivityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var titleLabel: UILabel!
+ @IBOutlet weak var ratingLabel: UILabel!
+ @IBOutlet weak var summaryLabel: UILabel!
+ @IBOutlet weak var releaseDateLabel: UILabel!
+ @IBOutlet weak var genresLabel: UILabel!
+ @IBOutlet weak var runtimeLabel: UILabel!
+}
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/FilterViewController.swift b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/FilterViewController.swift
new file mode 100644
index 0000000..853c0bf
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/FilterViewController.swift
@@ -0,0 +1,20 @@
+//
+// FiltersViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class FilterViewController: UIViewController {
+ @IBAction func cancel(sender: AnyObject) {
+ self.dismiss()
+ }
+
+ func dismiss() {
+ self.navigationController?.dismissViewControllerAnimated(true, completion: nil)
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store
new file mode 100644
index 0000000..c068369
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..7997783
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,44 @@
+{
+ "images" : [
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-29@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-40@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-60@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-60@3x.png",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png
new file mode 100644
index 0000000..d463ba9
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png
new file mode 100644
index 0000000..e421cfa
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png
new file mode 100644
index 0000000..2be6555
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png
new file mode 100644
index 0000000..efa69d2
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png
new file mode 100644
index 0000000..efa69d2
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png
new file mode 100644
index 0000000..e405742
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..0f84226
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "bt6DhdALyhf90gReozoQ0y3R3vZ.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg
new file mode 100644
index 0000000..1e19bbb
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..5d9e965
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..3124e77
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "umR9aXTxOxQUuDH2DamoJ5fIPB.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg
new file mode 100644
index 0000000..f4c469c
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..ed3e63e
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "eDildzNrm4XJABWkNKtqB29t6mv.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg
new file mode 100644
index 0000000..90ede16
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..8d49e39
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png
new file mode 100644
index 0000000..68aa392
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png
new file mode 100644
index 0000000..bb5d8b4
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png
new file mode 100644
index 0000000..12923f2
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json
new file mode 100644
index 0000000..4e659b8
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "settings.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "settings@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "settings@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png
new file mode 100644
index 0000000..e2d21f0
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png
new file mode 100644
index 0000000..6fd890d
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png
new file mode 100644
index 0000000..d68af6b
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json
new file mode 100644
index 0000000..50564ce
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "star.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "star@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "star@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png
new file mode 100644
index 0000000..2b2b41b
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png
new file mode 100644
index 0000000..f1367c8
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png
new file mode 100644
index 0000000..390ad8e
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json
new file mode 100644
index 0000000..04ea068
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "tag.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "tag@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "tag@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png
new file mode 100644
index 0000000..d46a1af
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png
new file mode 100644
index 0000000..5d176aa
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png
new file mode 100644
index 0000000..bee24d8
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json
new file mode 100644
index 0000000..16f2d86
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json
new file mode 100644
index 0000000..2febbf6
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json
new file mode 100644
index 0000000..37c7f9d
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json
new file mode 100644
index 0000000..8e8af21
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "interview.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "interview-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "interview-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json
new file mode 100644
index 0000000..4b2222a
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "Placeholder.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "Placeholder@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "Placeholder@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png
new file mode 100644
index 0000000..4f45f19
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png
new file mode 100644
index 0000000..e21d629
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png
new file mode 100644
index 0000000..6d89554
Binary files /dev/null and b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png differ
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Info.plist b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Info.plist
new file mode 100644
index 0000000..aab298d
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Info.plist
@@ -0,0 +1,52 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleDisplayName
+ Swift Movies
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ phillycocoa.$(PRODUCT_NAME:rfc1034identifier)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UIStatusBarTintParameters
+
+ UINavigationBar
+
+ Style
+ UIBarStyleDefault
+ Translucent
+
+
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+
+
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Movie.swift b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Movie.swift
new file mode 100644
index 0000000..dea2208
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/Movie.swift
@@ -0,0 +1,44 @@
+//
+// Movie.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+final class Movie {
+ let title: String
+ let posterPath: String
+ //let averageRating: Double
+ //let voteCount: Int
+ let rating: Rating
+
+ // Swift requires that all properties (except optionals which we will cover later)
+ // be initialized prior to the creation of the object
+ /* init(title: String, posterPath: String, averageRating: Double, voteCount: Int) {
+ // Try commenting one out to see what happens
+ self.title = title
+ self.posterPath = posterPath
+ self.averageRating = averageRating
+ self.voteCount = voteCount
+ }*/
+
+ init(title: String, posterPath: String, rating: Rating) {
+ // Try commenting one out to see what happens
+ self.title = title
+ self.posterPath = posterPath
+ self.rating = rating
+ }
+
+ convenience init(title: String, posterPath: String, averageRating: Double, voteCount: Int) {
+ let rating = Rating(averageRating: averageRating, voteCount: voteCount)
+ self.init(title: title, posterPath: posterPath, rating: rating)
+ }
+}
+
+struct Rating {
+ let averageRating: Double
+ let voteCount: Int
+}
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/SettingsViewController.swift b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/SettingsViewController.swift
new file mode 100644
index 0000000..b4599f1
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/SettingsViewController.swift
@@ -0,0 +1,59 @@
+//
+// SettingsController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/7/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class SettingsViewController: UITableViewController {
+ // Private properties are only available to the instance of the object (can't be called from another object)
+ // Its good practice for things you know will only be used internally
+ private let webViewSegue = "showWebView"
+ private var webViewProperties: (title: String?, urlString: String?)
+
+ override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
+ let path = (indexPath.section, indexPath.row)
+
+ // We can use tuples and a switch to cover our row actions without a big if/else mess
+ // We are also using a tuple to capture the title and url in one variable
+ switch path {
+ case (0, 0):
+ self.webViewProperties = ("@themoviedb", "http://twitter.com/themoviedb")
+ case (0, 1):
+ self.webViewProperties = ("The Movie DB", "http://facebook.com/themoviedb")
+ case (1, 0):
+ self.webViewProperties = ("Terms of Service", "http://themoviedb.org/documentation/website/terms-of-use")
+ case (1, 1):
+ self.webViewProperties = ("Privacy Policy", "http://themoviedb.org/privacy-policy")
+ default:
+ // This should never happen, but lets get in the mindset of handling issues gracefully
+ // Swift will actually give an error if we don't have this default case (must be exhaustive)
+ // We can demonstrate this by commenting out one of our cell handlers then tapping that cell
+ let alertTitle = "Sorry!"
+ let alertMessage = "An unknown error occurred."
+ let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: UIAlertControllerStyle.Alert)
+ alert.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default, handler: nil))
+ self.presentViewController(alert, animated: true, completion: nil)
+ self.tableView.deselectRowAtIndexPath(indexPath, animated: false) // Deselect the cell so it does not "stick"
+
+ // Return so we don't perform the segue
+ return
+ }
+
+ // Since all the various rows are going to the same view controller, we can trigger the
+ // segue manually instead of having to create 4 segues pointing to the same controller
+ self.performSegueWithIdentifier(webViewSegue, sender: self)
+ }
+
+ override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
+ if segue.identifier == webViewSegue {
+ let webViewController = segue.destinationViewController as WebViewController
+ webViewController.titleString = self.webViewProperties.title
+ webViewController.urlString = self.webViewProperties.urlString
+ }
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift
new file mode 100644
index 0000000..f26c7e7
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift
@@ -0,0 +1,1335 @@
+// SwiftyJSON.swift
+//
+// Copyright (c) 2014 Ruoyu Fu, Pinglin Tang
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+// MARK: - Error
+
+///Error domain
+public let ErrorDomain: String! = "SwiftyJSONErrorDomain"
+
+///Error code
+public let ErrorUnsupportedType: Int! = 999
+public let ErrorIndexOutOfBounds: Int! = 900
+public let ErrorWrongType: Int! = 901
+public let ErrorNotExist: Int! = 500
+
+// MARK: - JSON Type
+
+/**
+JSON's type definitions.
+
+See http://tools.ietf.org/html/rfc7231#section-4.3
+*/
+public enum Type :Int{
+
+ case Number
+ case String
+ case Bool
+ case Array
+ case Dictionary
+ case Null
+ case Unknown
+}
+
+// MARK: - JSON Base
+
+public struct JSON {
+
+ /**
+ Creates a JSON using the data.
+
+ :param: data The NSData used to convert to json.Top level object in data is an NSArray or NSDictionary
+ :param: opt The JSON serialization reading options. `.AllowFragments` by default.
+ :param: error error The NSErrorPointer used to return the error. `nil` by default.
+
+ :returns: The created JSON
+ */
+ public init(data:NSData, options opt: NSJSONReadingOptions = .AllowFragments, error: NSErrorPointer = nil) {
+ if let object: AnyObject = NSJSONSerialization.JSONObjectWithData(data, options: opt, error: error) {
+ self.init(object)
+ } else {
+ self.init(NSNull())
+ }
+ }
+
+ /**
+ Creates a JSON using the object.
+
+ :param: object The object must have the following properties: All objects are NSString/String, NSNumber/Int/Float/Double/Bool, NSArray/Array, NSDictionary/Dictionary, or NSNull; All dictionary keys are NSStrings/String; NSNumbers are not NaN or infinity.
+
+ :returns: The created JSON
+ */
+ public init(_ object: AnyObject) {
+ self.object = object
+ }
+
+ /// Private object
+ private var _object: AnyObject = NSNull()
+ /// Private type
+ private var _type: Type = .Null
+ /// prviate error
+ private var _error: NSError?
+
+ /// Object in JSON
+ public var object: AnyObject {
+ get {
+ return _object
+ }
+ set {
+ _object = newValue
+ switch newValue {
+ case let number as NSNumber:
+ if number.isBool {
+ _type = .Bool
+ } else {
+ _type = .Number
+ }
+ case let string as NSString:
+ _type = .String
+ case let null as NSNull:
+ _type = .Null
+ case let array as [AnyObject]:
+ _type = .Array
+ case let dictionary as [String : AnyObject]:
+ _type = .Dictionary
+ default:
+ _type = .Unknown
+ _object = NSNull()
+ _error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"])
+ }
+ }
+ }
+
+ /// json type
+ public var type: Type { get { return _type } }
+
+ /// Error in JSON
+ public var error: NSError? { get { return self._error } }
+
+ /// The static null json
+ public static var nullJSON: JSON { get { return JSON(NSNull()) } }
+
+}
+
+// MARK: - SequenceType
+extension JSON: SequenceType{
+
+ /// If `type` is `.Array` or `.Dictionary`, return `array.empty` or `dictonary.empty` otherwise return `false`.
+ public var isEmpty: Bool {
+ get {
+ switch self.type {
+ case .Array:
+ return (self.object as [AnyObject]).isEmpty
+ case .Dictionary:
+ return (self.object as [String : AnyObject]).isEmpty
+ default:
+ return false
+ }
+ }
+ }
+
+ /// If `type` is `.Array` or `.Dictionary`, return `array.count` or `dictonary.count` otherwise return `0`.
+ public var count: Int {
+ get {
+ switch self.type {
+ case .Array:
+ return self.arrayValue.count
+ case .Dictionary:
+ return self.dictionaryValue.count
+ default:
+ return 0
+ }
+ }
+ }
+
+ /**
+ If `type` is `.Array` or `.Dictionary`, return a generator over the elements like `Array` or `Dictionary, otherwise return a generator over empty.
+
+ :returns: Return a *generator* over the elements of this *sequence*.
+ */
+ public func generate() -> GeneratorOf <(String, JSON)> {
+ switch self.type {
+ case .Array:
+ let array_ = object as [AnyObject]
+ var generate_ = array_.generate()
+ var index_: Int = 0
+ return GeneratorOf<(String, JSON)> {
+ if let element_: AnyObject = generate_.next() {
+ return ("\(index_++)", JSON(element_))
+ } else {
+ return nil
+ }
+ }
+ case .Dictionary:
+ let dictionary_ = object as [String : AnyObject]
+ var generate_ = dictionary_.generate()
+ return GeneratorOf<(String, JSON)> {
+ if let (key_: String, value_: AnyObject) = generate_.next() {
+ return (key_, JSON(value_))
+ } else {
+ return nil
+ }
+ }
+ default:
+ return GeneratorOf<(String, JSON)> {
+ return nil
+ }
+ }
+ }
+}
+
+// MARK: - Subscript
+
+/**
+* To mark both String and Int can be used in subscript.
+*/
+public protocol SubscriptType {}
+
+extension Int: SubscriptType {}
+
+extension String: SubscriptType {}
+
+extension JSON {
+
+ /// If `type` is `.Array`, return json which's object is `array[index]`, otherwise return null json with error.
+ private subscript(#index: Int) -> JSON {
+ get {
+
+ if self.type != .Array {
+ var errorResult_ = JSON.nullJSON
+ errorResult_._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] failure, It is not an array"])
+ return errorResult_
+ }
+
+ let array_ = self.object as [AnyObject]
+
+ if index >= 0 && index < array_.count {
+ return JSON(array_[index])
+ }
+
+ var errorResult_ = JSON.nullJSON
+ errorResult_._error = NSError(domain: ErrorDomain, code:ErrorIndexOutOfBounds , userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] is out of bounds"])
+ return errorResult_
+ }
+ set {
+ if self.type == .Array {
+ var array_ = self.object as [AnyObject]
+ if array_.count > index {
+ array_[index] = newValue.object
+ self.object = array_
+ }
+ }
+ }
+ }
+
+ /// If `type` is `.Dictionary`, return json which's object is `dictionary[key]` , otherwise return null json with error.
+ private subscript(#key: String) -> JSON {
+ get {
+ var returnJSON = JSON.nullJSON
+ if self.type == .Dictionary {
+ if let object_: AnyObject = self.object[key] {
+ returnJSON = JSON(object_)
+ } else {
+ returnJSON._error = NSError(domain: ErrorDomain, code: ErrorNotExist, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] does not exist"])
+ }
+ } else {
+ returnJSON._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] failure, It is not an dictionary"])
+ }
+ return returnJSON
+ }
+ set {
+ if self.type == .Dictionary {
+ var dictionary_ = self.object as [String : AnyObject]
+ dictionary_[key] = newValue.object
+ self.object = dictionary_
+ }
+ }
+ }
+
+ /// If `sub` is `Int`, return `subscript(index:)`; If `sub` is `String`, return `subscript(key:)`.
+ private subscript(#sub: SubscriptType) -> JSON {
+ get {
+ if sub is String {
+ return self[key:sub as String]
+ } else {
+ return self[index:sub as Int]
+ }
+ }
+ set {
+ if sub is String {
+ self[key:sub as String] = newValue
+ } else {
+ self[index:sub as Int] = newValue
+ }
+ }
+ }
+
+ /**
+ Find a json in the complex data structuresby using the Int/String's array.
+
+ :param: path The target json's path. Example:
+
+ let json = JSON[data]
+ let path = [9,"list","person","name"]
+ let name = json[path]
+
+ The same as: let name = json[9]["list"]["person"]["name"]
+
+ :returns: Return a json found by the path or a null json with error
+ */
+ public subscript(path: [SubscriptType]) -> JSON {
+ get {
+ if path.count == 0 {
+ return JSON.nullJSON
+ }
+
+ var next = self
+ for sub in path {
+ next = next[sub:sub]
+ }
+ return next
+ }
+ set {
+
+ switch path.count {
+ case 0: return
+ case 1: self[sub:path[0]] = newValue
+ default:
+ var last = newValue
+ var newPath = path
+ newPath.removeLast()
+ for sub in path.reverse() {
+ var previousLast = self[newPath]
+ previousLast[sub:sub] = last
+ last = previousLast
+ if newPath.count <= 1 {
+ break
+ }
+ newPath.removeLast()
+ }
+ self[sub:newPath[0]] = last
+ }
+ }
+ }
+
+ /**
+ Find a json in the complex data structuresby using the Int/String's array.
+
+ :param: path The target json's path. Example:
+
+ let name = json[9,"list","person","name"]
+
+ The same as: let name = json[9]["list"]["person"]["name"]
+
+ :returns: Return a json found by the path or a null json with error
+ */
+ public subscript(path: SubscriptType...) -> JSON {
+ get {
+ return self[path]
+ }
+ set {
+ self[path] = newValue
+ }
+ }
+}
+
+// MARK: - LiteralConvertible
+
+extension JSON: StringLiteralConvertible {
+
+ public init(stringLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+
+ public init(extendedGraphemeClusterLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+
+ public init(unicodeScalarLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: IntegerLiteralConvertible {
+
+ public init(integerLiteral value: IntegerLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: BooleanLiteralConvertible {
+
+ public init(booleanLiteral value: BooleanLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: FloatLiteralConvertible {
+
+ public init(floatLiteral value: FloatLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: DictionaryLiteralConvertible {
+
+ public init(dictionaryLiteral elements: (String, AnyObject)...) {
+ var dictionary_ = [String : AnyObject]()
+ for (key_, value) in elements {
+ dictionary_[key_] = value
+ }
+ self.init(dictionary_)
+ }
+}
+
+extension JSON: ArrayLiteralConvertible {
+
+ public init(arrayLiteral elements: AnyObject...) {
+ self.init(elements)
+ }
+}
+
+extension JSON: NilLiteralConvertible {
+
+ public init(nilLiteral: ()) {
+ self.init(NSNull())
+ }
+}
+
+// MARK: - Raw
+
+extension JSON: RawRepresentable {
+
+ public init?(rawValue: AnyObject) {
+ if JSON(rawValue).type == .Unknown {
+ return nil
+ } else {
+ self.init(rawValue)
+ }
+ }
+
+ public var rawValue: AnyObject {
+ return self.object
+ }
+
+ public func rawData(options opt: NSJSONWritingOptions = NSJSONWritingOptions(0), error: NSErrorPointer = nil) -> NSData? {
+ return NSJSONSerialization.dataWithJSONObject(self.object, options: opt, error:error)
+ }
+
+ public func rawString(encoding: UInt = NSUTF8StringEncoding, options opt: NSJSONWritingOptions = .PrettyPrinted) -> String? {
+ switch self.type {
+ case .Array, .Dictionary:
+ if let data = self.rawData(options: opt) {
+ return NSString(data: data, encoding: encoding)
+ } else {
+ return nil
+ }
+ case .String:
+ return (self.object as String)
+ case .Number:
+ return (self.object as NSNumber).stringValue
+ case .Bool:
+ return (self.object as Bool).description
+ case .Null:
+ return "null"
+ default:
+ return nil
+ }
+ }
+}
+
+// MARK: - Printable, DebugPrintable
+
+extension JSON: Printable, DebugPrintable {
+
+ public var description: String {
+ if let string = self.rawString(options:.PrettyPrinted) {
+ return string
+ } else {
+ return "unknown"
+ }
+ }
+
+ public var debugDescription: String {
+ return description
+ }
+}
+
+// MARK: - Array
+
+extension JSON {
+
+ //Optional [JSON]
+ public var array: [JSON]? {
+ get {
+ if self.type == .Array {
+ return map(self.object as [AnyObject]){ JSON($0) }
+ } else {
+ return nil
+ }
+ }
+ }
+
+ //Non-optional [JSON]
+ public var arrayValue: [JSON] {
+ get {
+ return self.array ?? []
+ }
+ }
+
+ //Optional [AnyObject]
+ public var arrayObject: [AnyObject]? {
+ get {
+ switch self.type {
+ case .Array:
+ return self.object as? [AnyObject]
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSMutableArray(array: newValue!, copyItems: true)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+}
+
+// MARK: - Dictionary
+
+extension JSON {
+
+ private func _map(source: [Key: Value], transform: Value -> NewValue) -> [Key: NewValue] {
+ var result = [Key: NewValue](minimumCapacity:source.count)
+ for (key,value) in source {
+ result[key] = transform(value)
+ }
+ return result
+ }
+
+ //Optional [String : JSON]
+ public var dictionary: [String : JSON]? {
+ get {
+ if self.type == .Dictionary {
+ return _map(self.object as [String : AnyObject]){ JSON($0) }
+ } else {
+ return nil
+ }
+ }
+ }
+
+ //Non-optional [String : JSON]
+ public var dictionaryValue: [String : JSON] {
+ get {
+ return self.dictionary ?? [:]
+ }
+ }
+
+ //Optional [String : AnyObject]
+ public var dictionaryObject: [String : AnyObject]? {
+ get {
+ switch self.type {
+ case .Dictionary:
+ return self.object as? [String : AnyObject]
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSMutableDictionary(dictionary: newValue!, copyItems: true)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+}
+
+// MARK: - Bool
+
+extension JSON: BooleanType {
+
+ //Optional bool
+ public var bool: Bool? {
+ get {
+ switch self.type {
+ case .Bool:
+ return self.object.boolValue
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(bool: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ //Non-optional bool
+ public var boolValue: Bool {
+ get {
+ switch self.type {
+ case .Bool, .Number, .String:
+ return self.object.boolValue
+ default:
+ return false
+ }
+ }
+ set {
+ self.object = NSNumber(bool: newValue)
+ }
+ }
+}
+
+// MARK: - String
+
+extension JSON {
+
+ //Optional string
+ public var string: String? {
+ get {
+ switch self.type {
+ case .String:
+ return self.object as? String
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSString(string:newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ //Non-optional string
+ public var stringValue: String {
+ get {
+ switch self.type {
+ case .String:
+ return self.object as String
+ case .Number:
+ return self.object.stringValue
+ case .Bool:
+ return (self.object as Bool).description
+ default:
+ return ""
+ }
+ }
+ set {
+ self.object = NSString(string:newValue)
+ }
+ }
+}
+
+// MARK: - Number
+extension JSON {
+
+ //Optional number
+ public var number: NSNumber? {
+ get {
+ switch self.type {
+ case .Number, .Bool:
+ return self.object as? NSNumber
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = newValue?.copy() ?? NSNull()
+ }
+ }
+
+ //Non-optional number
+ public var numberValue: NSNumber {
+ get {
+ switch self.type {
+ case .String:
+ let scanner = NSScanner(string: self.object as String)
+ if scanner.scanDouble(nil){
+ if (scanner.atEnd) {
+ return NSNumber(double:(self.object as NSString).doubleValue)
+ }
+ }
+ return NSNumber(double: 0.0)
+ case .Number, .Bool:
+ return self.object as NSNumber
+ default:
+ return NSNumber(double: 0.0)
+ }
+ }
+ set {
+ self.object = newValue.copy()
+ }
+ }
+}
+
+//MARK: - Null
+extension JSON {
+
+ public var null: NSNull? {
+ get {
+ switch self.type {
+ case .Null:
+ return NSNull()
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = NSNull()
+ }
+ }
+}
+
+//MARK: - URL
+extension JSON {
+
+ //Optional URL
+ public var URL: NSURL? {
+ get {
+ switch self.type {
+ case .String:
+ if let encodedString_ = self.object.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
+ return NSURL(string: encodedString_)
+ } else {
+ return nil
+ }
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = newValue?.absoluteString ?? NSNull()
+ }
+ }
+}
+
+// MARK: - Int, Double, Float, Int8, Int16, Int32, Int64
+
+extension JSON {
+
+ public var double: Double? {
+ get {
+ return self.number?.doubleValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(double: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var doubleValue: Double {
+ get {
+ return self.numberValue.doubleValue
+ }
+ set {
+ self.object = NSNumber(double: newValue)
+ }
+ }
+
+ public var float: Float? {
+ get {
+ return self.number?.floatValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(float: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var floatValue: Float {
+ get {
+ return self.numberValue.floatValue
+ }
+ set {
+ self.object = NSNumber(float: newValue)
+ }
+ }
+
+ public var int: Int? {
+ get {
+ return self.number?.longValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(integer: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var intValue: Int {
+ get {
+ return self.numberValue.integerValue
+ }
+ set {
+ self.object = NSNumber(integer: newValue)
+ }
+ }
+
+ public var uInt: UInt? {
+ get {
+ return self.number?.unsignedLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uIntValue: UInt {
+ get {
+ return self.numberValue.unsignedLongValue
+ }
+ set {
+ self.object = NSNumber(unsignedLong: newValue)
+ }
+ }
+
+ public var int8: Int8? {
+ get {
+ return self.number?.charValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(char: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int8Value: Int8 {
+ get {
+ return self.numberValue.charValue
+ }
+ set {
+ self.object = NSNumber(char: newValue)
+ }
+ }
+
+ public var uInt8: UInt8? {
+ get {
+ return self.number?.unsignedCharValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedChar: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt8Value: UInt8 {
+ get {
+ return self.numberValue.unsignedCharValue
+ }
+ set {
+ self.object = NSNumber(unsignedChar: newValue)
+ }
+ }
+
+ public var int16: Int16? {
+ get {
+ return self.number?.shortValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(short: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int16Value: Int16 {
+ get {
+ return self.numberValue.shortValue
+ }
+ set {
+ self.object = NSNumber(short: newValue)
+ }
+ }
+
+ public var uInt16: UInt16? {
+ get {
+ return self.number?.unsignedShortValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedShort: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt16Value: UInt16 {
+ get {
+ return self.numberValue.unsignedShortValue
+ }
+ set {
+ self.object = NSNumber(unsignedShort: newValue)
+ }
+ }
+
+ public var int32: Int32? {
+ get {
+ return self.number?.intValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(int: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int32Value: Int32 {
+ get {
+ return self.numberValue.intValue
+ }
+ set {
+ self.object = NSNumber(int: newValue)
+ }
+ }
+
+ public var uInt32: UInt32? {
+ get {
+ return self.number?.unsignedIntValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedInt: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt32Value: UInt32 {
+ get {
+ return self.numberValue.unsignedIntValue
+ }
+ set {
+ self.object = NSNumber(unsignedInt: newValue)
+ }
+ }
+
+ public var int64: Int64? {
+ get {
+ return self.number?.longLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(longLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int64Value: Int64 {
+ get {
+ return self.numberValue.longLongValue
+ }
+ set {
+ self.object = NSNumber(longLong: newValue)
+ }
+ }
+
+ public var uInt64: UInt64? {
+ get {
+ return self.number?.unsignedLongLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedLongLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt64Value: UInt64 {
+ get {
+ return self.numberValue.unsignedLongLongValue
+ }
+ set {
+ self.object = NSNumber(unsignedLongLong: newValue)
+ }
+ }
+}
+
+//MARK: - Comparable
+extension JSON: Comparable {}
+
+public func ==(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) == (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) == (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func <=(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) <= (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) <= (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func >=(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) >= (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) >= (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func >(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) > (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) > (rhs.object as String)
+ default:
+ return false
+ }
+}
+
+public func <(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) < (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) < (rhs.object as String)
+ default:
+ return false
+ }
+}
+
+private let trueNumber = NSNumber(bool: true)
+private let falseNumber = NSNumber(bool: false)
+private let trueObjCType = String.fromCString(trueNumber.objCType)
+private let falseObjCType = String.fromCString(falseNumber.objCType)
+
+// MARK: - NSNumber: Comparable
+
+extension NSNumber: Comparable {
+ var isBool:Bool {
+ get {
+ let objCType = String.fromCString(self.objCType)
+ if (self.compare(trueNumber) == NSComparisonResult.OrderedSame && objCType == trueObjCType) || (self.compare(falseNumber) == NSComparisonResult.OrderedSame && objCType == falseObjCType){
+ return true
+ } else {
+ return false
+ }
+ }
+ }
+}
+
+public func ==(lhs: NSNumber, rhs: NSNumber) -> Bool {
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedSame
+ }
+}
+
+public func !=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+ return !(lhs == rhs)
+}
+
+public func <(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedAscending
+ }
+}
+
+public func >(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedDescending
+ }
+}
+
+public func <=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) != NSComparisonResult.OrderedDescending
+ }
+}
+
+public func >=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) != NSComparisonResult.OrderedAscending
+ }
+}
+
+//MARK:- Unavailable
+
+@availability(*, unavailable, renamed="JSON")
+public typealias JSONValue = JSON
+
+extension JSON {
+
+ @availability(*, unavailable, message="use 'init(_ object:AnyObject)' instead")
+ public init(object: AnyObject) {
+ self = JSON(object)
+ }
+
+ @availability(*, unavailable, renamed="dictionaryObject")
+ public var dictionaryObjects: [String : AnyObject]? {
+ get { return self.dictionaryObject }
+ }
+
+ @availability(*, unavailable, renamed="arrayObject")
+ public var arrayObjects: [AnyObject]? {
+ get { return self.arrayObject }
+ }
+
+ @availability(*, unavailable, renamed="int8")
+ public var char: Int8? {
+ get {
+ return self.number?.charValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int8Value")
+ public var charValue: Int8 {
+ get {
+ return self.numberValue.charValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt8")
+ public var unsignedChar: UInt8? {
+ get{
+ return self.number?.unsignedCharValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt8Value")
+ public var unsignedCharValue: UInt8 {
+ get{
+ return self.numberValue.unsignedCharValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int16")
+ public var short: Int16? {
+ get{
+ return self.number?.shortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int16Value")
+ public var shortValue: Int16 {
+ get{
+ return self.numberValue.shortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt16")
+ public var unsignedShort: UInt16? {
+ get{
+ return self.number?.unsignedShortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt16Value")
+ public var unsignedShortValue: UInt16 {
+ get{
+ return self.numberValue.unsignedShortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int")
+ public var long: Int? {
+ get{
+ return self.number?.longValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="intValue")
+ public var longValue: Int {
+ get{
+ return self.numberValue.longValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt")
+ public var unsignedLong: UInt? {
+ get{
+ return self.number?.unsignedLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uIntValue")
+ public var unsignedLongValue: UInt {
+ get{
+ return self.numberValue.unsignedLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int64")
+ public var longLong: Int64? {
+ get{
+ return self.number?.longLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int64Value")
+ public var longLongValue: Int64 {
+ get{
+ return self.numberValue.longLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt64")
+ public var unsignedLongLong: UInt64? {
+ get{
+ return self.number?.unsignedLongLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt64Value")
+ public var unsignedLongLongValue: UInt64 {
+ get{
+ return self.numberValue.unsignedLongLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int")
+ public var integer: Int? {
+ get {
+ return self.number?.integerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="intValue")
+ public var integerValue: Int {
+ get {
+ return self.numberValue.integerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt")
+ public var unsignedInteger: Int? {
+ get {
+ return self.number?.unsignedIntegerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uIntValue")
+ public var unsignedIntegerValue: Int {
+ get {
+ return self.numberValue.unsignedIntegerValue
+ }
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/TMDB.swift b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/TMDB.swift
new file mode 100644
index 0000000..323a50a
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/TMDB.swift
@@ -0,0 +1,13 @@
+//
+// TMDB.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import Foundation
+
+let TMDB_API_KEY = "8a4a247d072d9ca4a0072893ab60e277"
+let TMDB_API_BASE_URL = "http://api.themoviedb.org/3"
+let TMDB_IMAGE_BASE_URL = "http://image.tmdb.org/t/p"
\ No newline at end of file
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/WebViewController.swift b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/WebViewController.swift
new file mode 100644
index 0000000..1373d09
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMovies/WebViewController.swift
@@ -0,0 +1,50 @@
+//
+// WebViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of WebViewController (optimization)
+final class WebViewController: UIViewController {
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var webView: UIWebView!
+
+ var urlString: String?
+ var titleString: String?
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.webView.delegate = self
+
+ // Since our titleString and urlString are optionals we have to unwrap them
+ if let title = titleString {
+ self.navigationItem.title = titleString
+ }
+
+ if let urlString = self.urlString {
+ // The NSURL init method returns an optional as well
+ // Its common for Cocoa methods to return optionals (because of Obj-C)
+ if let url = NSURL(string: urlString) {
+ let request = NSURLRequest(URL: url)
+ webView.loadRequest(request)
+ }
+ }
+ }
+}
+
+// Class extensions make it easy to group functionality, like protocol methods
+extension WebViewController: UIWebViewDelegate {
+ // These methods are called automatically when we set the delegate
+ // and adopt the protocol
+ func webViewDidStartLoad(webView: UIWebView) {
+ self.activityIndicator.startAnimating()
+ }
+
+ func webViewDidFinishLoad(webView: UIWebView) {
+ self.activityIndicator.stopAnimating()
+ }
+}
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMoviesTests/Info.plist b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMoviesTests/Info.plist
new file mode 100644
index 0000000..2afc012
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMoviesTests/Info.plist
@@ -0,0 +1,24 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ phillycocoa.$(PRODUCT_NAME:rfc1034identifier)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ BNDL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+
+
diff --git a/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift
new file mode 100644
index 0000000..3cb0bdc
--- /dev/null
+++ b/3 - Act II/1 - Starting Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift
@@ -0,0 +1,36 @@
+//
+// SwiftMoviesTests.swift
+// SwiftMoviesTests
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+import XCTest
+
+class SwiftMoviesTests: 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/3 - Act II/2 - Finished Project/SwiftMovies/.DS_Store b/3 - Act II/2 - Finished Project/SwiftMovies/.DS_Store
new file mode 100644
index 0000000..59b421f
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/.DS_Store differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..02bd8c2
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj
@@ -0,0 +1,474 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ F45D76761A5FD9FE001807F2 /* SwiftyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */; };
+ F4646C331A5DF40800336DFC /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4646C321A5DF40800336DFC /* SettingsViewController.swift */; };
+ F4678DB91A5A82F1005A33DE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DB81A5A82F1005A33DE /* AppDelegate.swift */; };
+ F4678DC01A5A82F1005A33DE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F4678DBE1A5A82F1005A33DE /* Main.storyboard */; };
+ F4678DC21A5A82F1005A33DE /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F4678DC11A5A82F1005A33DE /* Images.xcassets */; };
+ F4678DC51A5A82F1005A33DE /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */; };
+ F4678DD11A5A82F1005A33DE /* SwiftMoviesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */; };
+ F4678DE11A5A9582005A33DE /* Movie.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DE01A5A9582005A33DE /* Movie.swift */; };
+ F477D6AE1A5F20E2006FD97E /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */; };
+ F477D6B21A5F20FF006FD97E /* FilterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F477D6B11A5F20FF006FD97E /* FilterViewController.swift */; };
+ F49C6F8A1A5F47B200D0C49E /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F49C6F891A5F47B200D0C49E /* WebViewController.swift */; };
+ F4DC98D01A5E5B0C0030CC99 /* CollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */; };
+ F4DC98D21A5E6B460030CC99 /* TMDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4DC98D11A5E6B460030CC99 /* TMDB.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ F4678DCB1A5A82F1005A33DE /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = F4678DAB1A5A82F1005A33DE /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F4678DB21A5A82F1005A33DE;
+ remoteInfo = SwiftMovies;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyJSON.swift; sourceTree = ""; };
+ F4646C321A5DF40800336DFC /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; };
+ F4678DB31A5A82F1005A33DE /* SwiftMovies.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftMovies.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ F4678DB71A5A82F1005A33DE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ F4678DB81A5A82F1005A33DE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ F4678DBF1A5A82F1005A33DE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
+ F4678DC11A5A82F1005A33DE /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
+ F4678DC41A5A82F1005A33DE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
+ F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftMoviesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ F4678DCF1A5A82F1005A33DE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftMoviesTests.swift; sourceTree = ""; };
+ F4678DE01A5A9582005A33DE /* Movie.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Movie.swift; sourceTree = ""; };
+ F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; };
+ F477D6B11A5F20FF006FD97E /* FilterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilterViewController.swift; sourceTree = ""; };
+ F49C6F891A5F47B200D0C49E /* WebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebViewController.swift; sourceTree = ""; };
+ F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewController.swift; sourceTree = ""; };
+ F4DC98D11A5E6B460030CC99 /* TMDB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TMDB.swift; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ F4678DB01A5A82F1005A33DE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC71A5A82F1005A33DE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ F4678DAA1A5A82F1005A33DE = {
+ isa = PBXGroup;
+ children = (
+ F4678DB51A5A82F1005A33DE /* SwiftMovies */,
+ F4678DCD1A5A82F1005A33DE /* SwiftMoviesTests */,
+ F4678DB41A5A82F1005A33DE /* Products */,
+ );
+ sourceTree = "";
+ };
+ F4678DB41A5A82F1005A33DE /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DB31A5A82F1005A33DE /* SwiftMovies.app */,
+ F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ F4678DB51A5A82F1005A33DE /* SwiftMovies */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DB81A5A82F1005A33DE /* AppDelegate.swift */,
+ F4678DC11A5A82F1005A33DE /* Images.xcassets */,
+ F477D6AA1A5F209D006FD97E /* Controllers */,
+ F477D6B31A5F210F006FD97E /* Models */,
+ F477D6B71A5F215E006FD97E /* Networking */,
+ F4678DBE1A5A82F1005A33DE /* Main.storyboard */,
+ F4678DB61A5A82F1005A33DE /* Supporting Files */,
+ );
+ path = SwiftMovies;
+ sourceTree = "";
+ };
+ F4678DB61A5A82F1005A33DE /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */,
+ F4678DB71A5A82F1005A33DE /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ F4678DCD1A5A82F1005A33DE /* SwiftMoviesTests */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */,
+ F4678DCE1A5A82F1005A33DE /* Supporting Files */,
+ );
+ path = SwiftMoviesTests;
+ sourceTree = "";
+ };
+ F4678DCE1A5A82F1005A33DE /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DCF1A5A82F1005A33DE /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ F477D6AA1A5F209D006FD97E /* Controllers */ = {
+ isa = PBXGroup;
+ children = (
+ F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */,
+ F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */,
+ F477D6B11A5F20FF006FD97E /* FilterViewController.swift */,
+ F4646C321A5DF40800336DFC /* SettingsViewController.swift */,
+ F49C6F891A5F47B200D0C49E /* WebViewController.swift */,
+ );
+ name = Controllers;
+ sourceTree = "";
+ };
+ F477D6B31A5F210F006FD97E /* Models */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DE01A5A9582005A33DE /* Movie.swift */,
+ );
+ name = Models;
+ sourceTree = "";
+ };
+ F477D6B71A5F215E006FD97E /* Networking */ = {
+ isa = PBXGroup;
+ children = (
+ F4DC98D11A5E6B460030CC99 /* TMDB.swift */,
+ F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */,
+ );
+ name = Networking;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ F4678DB21A5A82F1005A33DE /* SwiftMovies */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F4678DD41A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMovies" */;
+ buildPhases = (
+ F4678DAF1A5A82F1005A33DE /* Sources */,
+ F4678DB01A5A82F1005A33DE /* Frameworks */,
+ F4678DB11A5A82F1005A33DE /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = SwiftMovies;
+ productName = SwiftMovies;
+ productReference = F4678DB31A5A82F1005A33DE /* SwiftMovies.app */;
+ productType = "com.apple.product-type.application";
+ };
+ F4678DC91A5A82F1005A33DE /* SwiftMoviesTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F4678DD71A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMoviesTests" */;
+ buildPhases = (
+ F4678DC61A5A82F1005A33DE /* Sources */,
+ F4678DC71A5A82F1005A33DE /* Frameworks */,
+ F4678DC81A5A82F1005A33DE /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ F4678DCC1A5A82F1005A33DE /* PBXTargetDependency */,
+ );
+ name = SwiftMoviesTests;
+ productName = SwiftMoviesTests;
+ productReference = F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ F4678DAB1A5A82F1005A33DE /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0610;
+ ORGANIZATIONNAME = "Philly Cocoaheads";
+ TargetAttributes = {
+ F4678DB21A5A82F1005A33DE = {
+ CreatedOnToolsVersion = 6.1.1;
+ };
+ F4678DC91A5A82F1005A33DE = {
+ CreatedOnToolsVersion = 6.1.1;
+ TestTargetID = F4678DB21A5A82F1005A33DE;
+ };
+ };
+ };
+ buildConfigurationList = F4678DAE1A5A82F1005A33DE /* Build configuration list for PBXProject "SwiftMovies" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = F4678DAA1A5A82F1005A33DE;
+ productRefGroup = F4678DB41A5A82F1005A33DE /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ F4678DB21A5A82F1005A33DE /* SwiftMovies */,
+ F4678DC91A5A82F1005A33DE /* SwiftMoviesTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ F4678DB11A5A82F1005A33DE /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4678DC01A5A82F1005A33DE /* Main.storyboard in Resources */,
+ F4678DC51A5A82F1005A33DE /* LaunchScreen.xib in Resources */,
+ F4678DC21A5A82F1005A33DE /* Images.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC81A5A82F1005A33DE /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ F4678DAF1A5A82F1005A33DE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4646C331A5DF40800336DFC /* SettingsViewController.swift in Sources */,
+ F477D6AE1A5F20E2006FD97E /* DetailViewController.swift in Sources */,
+ F49C6F8A1A5F47B200D0C49E /* WebViewController.swift in Sources */,
+ F45D76761A5FD9FE001807F2 /* SwiftyJSON.swift in Sources */,
+ F4DC98D01A5E5B0C0030CC99 /* CollectionViewController.swift in Sources */,
+ F4678DE11A5A9582005A33DE /* Movie.swift in Sources */,
+ F4DC98D21A5E6B460030CC99 /* TMDB.swift in Sources */,
+ F477D6B21A5F20FF006FD97E /* FilterViewController.swift in Sources */,
+ F4678DB91A5A82F1005A33DE /* AppDelegate.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC61A5A82F1005A33DE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4678DD11A5A82F1005A33DE /* SwiftMoviesTests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ F4678DCC1A5A82F1005A33DE /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F4678DB21A5A82F1005A33DE /* SwiftMovies */;
+ targetProxy = F4678DCB1A5A82F1005A33DE /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ F4678DBE1A5A82F1005A33DE /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F4678DBF1A5A82F1005A33DE /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "";
+ };
+ F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F4678DC41A5A82F1005A33DE /* Base */,
+ );
+ name = LaunchScreen.xib;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ F4678DD21A5A82F1005A33DE /* 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.1;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ F4678DD31A5A82F1005A33DE /* 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.1;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ F4678DD51A5A82F1005A33DE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = SwiftMovies/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ F4678DD61A5A82F1005A33DE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = SwiftMovies/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ F4678DD81A5A82F1005A33DE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = SwiftMoviesTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftMovies.app/SwiftMovies";
+ };
+ name = Debug;
+ };
+ F4678DD91A5A82F1005A33DE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = SwiftMoviesTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftMovies.app/SwiftMovies";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ F4678DAE1A5A82F1005A33DE /* Build configuration list for PBXProject "SwiftMovies" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD21A5A82F1005A33DE /* Debug */,
+ F4678DD31A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ F4678DD41A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMovies" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD51A5A82F1005A33DE /* Debug */,
+ F4678DD61A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ F4678DD71A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMoviesTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD81A5A82F1005A33DE /* Debug */,
+ F4678DD91A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = F4678DAB1A5A82F1005A33DE /* Project object */;
+}
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..7890687
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..40b54ec
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
new file mode 100644
index 0000000..fe2b454
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -0,0 +1,5 @@
+
+
+
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme
new file mode 100644
index 0000000..ec387aa
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..dd30f16
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,27 @@
+
+
+
+
+ SchemeUserState
+
+ SwiftMovies.xcscheme
+
+ orderHint
+ 0
+
+
+ SuppressBuildableAutocreation
+
+ F4678DB21A5A82F1005A33DE
+
+ primary
+
+
+ F4678DC91A5A82F1005A33DE
+
+ primary
+
+
+
+
+
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/AppDelegate.swift b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/AppDelegate.swift
new file mode 100644
index 0000000..9c2f2cc
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/AppDelegate.swift
@@ -0,0 +1,46 @@
+//
+// AppDelegate.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+@UIApplicationMain
+class AppDelegate: UIResponder, UIApplicationDelegate {
+
+ var window: UIWindow?
+
+
+ func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> 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/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib
new file mode 100644
index 0000000..9e43426
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..13a6325
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard
@@ -0,0 +1,604 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/CollectionViewController.swift b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/CollectionViewController.swift
new file mode 100644
index 0000000..18b8f1f
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/CollectionViewController.swift
@@ -0,0 +1,87 @@
+//
+// MovieCollectionController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Since we don't have to worry about headers and imports in Swift
+// It sometimes makes sense to keep multiple classes in the same file
+final class MovieCell: UICollectionViewCell {
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var imageView: UIImageView!
+}
+
+final class CollectionViewController: UIViewController {
+ @IBOutlet weak var collectionView: UICollectionView!
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+
+ // We will later be fetching our movies from the web
+ // so we went to use a var such that we can update our movies after load
+ // We need to have a value, so we default to an empty array
+ var movies: [Movie] = []
+ var activeList: TMDB.MovieList = .Popular // We can exclude the enum name and just use .Type
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.collectionView.delegate = self
+ self.collectionView.dataSource = self
+ self.loadPlaceholderData()
+ }
+
+ func loadPlaceholderData() {
+ let goneGirl = Movie(title: "Gone Girl", posterPath: "gonePoster", averageRating: 8.1, voteCount: 845)
+ let guardians = Movie(title: "Guardians of the Galaxy", posterPath: "guardiansPoster", averageRating: 9.2, voteCount: 1026)
+ let theHobbit = Movie(title: "The Hobbit", posterPath: "hobbitPoster", averageRating: 7.4, voteCount: 1343)
+ let theInterview = Movie(title: "The Interview", posterPath: "interviewPoster", averageRating: 6.3, voteCount: 824)
+
+ self.movies = [goneGirl, guardians, theHobbit, theInterview]
+ self.collectionView.reloadData()
+ }
+
+ override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
+ if segue.identifier == "showMovieView" {
+ // We use "as" to typecast to a certain object type
+ let movieController = segue.destinationViewController as DetailViewController
+ let indexPath = self.collectionView.indexPathsForSelectedItems().first as NSIndexPath?
+ if let selectedPath = indexPath {
+ // Pass the selected movie to detail view
+ let movie = self.movies[selectedPath.row]
+ movieController.movie = movie
+ }
+ }
+
+ if segue.identifier == "showFilterView" {
+ // We use "as" to typecast to a certain object type
+ let navController = segue.destinationViewController as UINavigationController
+ let filterController = navController.viewControllers.first as FilterViewController
+ // By setting the delegate to this controller we receive updates when the filter changes.
+ filterController.delegate = self
+ }
+ }
+}
+
+// Class extensions make it easy to group functionality, like protocol methods
+extension CollectionViewController: UICollectionViewDelegate, UICollectionViewDataSource {
+ func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+ return self.movies.count
+ }
+
+ func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
+ let movieCell = collectionView.dequeueReusableCellWithReuseIdentifier("movieCell", forIndexPath: indexPath) as MovieCell
+ let movie = self.movies[indexPath.row]
+ movieCell.imageView.image = UIImage(named: movie.posterPath)
+
+ return movieCell
+ }
+}
+
+extension CollectionViewController: FilterViewDelegate {
+ func filterDidChange(list: TMDB.MovieList) {
+ self.activeList = list
+ self.navigationItem.title = list.listName
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/DetailViewController.swift b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/DetailViewController.swift
new file mode 100644
index 0000000..09481c2
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/DetailViewController.swift
@@ -0,0 +1,46 @@
+//
+// MovieViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class DetailViewController: UIViewController {
+ @IBOutlet weak var backdropImageView: UIImageView!
+ @IBOutlet weak var backdropActivityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var titleLabel: UILabel!
+ @IBOutlet weak var ratingLabel: UILabel!
+ @IBOutlet weak var summaryLabel: UILabel!
+ @IBOutlet weak var releaseDateLabel: UILabel!
+ @IBOutlet weak var genresLabel: UILabel!
+ @IBOutlet weak var runtimeLabel: UILabel!
+
+ var movie: Movie?
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.loadMovieInfo()
+ }
+
+ private func loadMovieInfo() {
+ // Setup our empty state (how the screen should look while loading)
+ let ellipsis = "..."
+ self.backdropImageView.image = nil
+ self.titleLabel.text = ellipsis
+ self.navigationItem.title = ellipsis
+ self.ratingLabel.text = ellipsis
+ self.summaryLabel.text = ellipsis
+ self.releaseDateLabel.text = ellipsis
+ self.genresLabel.text = ellipsis
+ self.runtimeLabel.text = ellipsis
+
+ if let movie = self.movie {
+ self.titleLabel.text = movie.title
+ self.navigationItem.title = movie.title
+ }
+ }
+}
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/FilterViewController.swift b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/FilterViewController.swift
new file mode 100644
index 0000000..9f40850
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/FilterViewController.swift
@@ -0,0 +1,60 @@
+//
+// FiltersViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class FilterViewController: UIViewController {
+ // You can use protocols and delegates together to communicate between objects
+ // This will enable us to tell our Collection controller when the filter has changed
+ var delegate: FilterViewDelegate?
+
+ @IBAction func cancel(sender: AnyObject) {
+ self.dismiss()
+ }
+
+ func dismiss() {
+ self.navigationController?.dismissViewControllerAnimated(true, completion: nil)
+ }
+}
+
+// Class extensions make it easy to group functionality, like protocol methods
+extension FilterViewController: UITableViewDelegate, UITableViewDataSource {
+ func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return TMDB.MovieList.allLists.count
+ }
+
+ func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
+ let cell = tableView.dequeueReusableCellWithIdentifier("filterCell") as UITableViewCell
+ let movieList: TMDB.MovieList = TMDB.MovieList.allLists[indexPath.row]
+
+ cell.textLabel?.text = movieList.listName
+
+ if movieList == delegate?.activeList {
+ cell.accessoryType = UITableViewCellAccessoryType.Checkmark
+ } else {
+ cell.accessoryType = UITableViewCellAccessoryType.None
+ }
+
+ return cell
+ }
+
+ func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
+ tableView.deselectRowAtIndexPath(indexPath, animated: false) // Fix sticky cells
+ let movieList: TMDB.MovieList = TMDB.MovieList.allLists[indexPath.row]
+ self.delegate?.filterDidChange(movieList)
+ self.dismiss()
+ }
+}
+
+// Protocols allow us to force an object to adopt certain
+// properties and methods (by adopting the protocol)
+protocol FilterViewDelegate {
+ var activeList: TMDB.MovieList { get }
+ func filterDidChange(list: TMDB.MovieList)
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store
new file mode 100644
index 0000000..c068369
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..7997783
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,44 @@
+{
+ "images" : [
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-29@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-40@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-60@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-60@3x.png",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png
new file mode 100644
index 0000000..d463ba9
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png
new file mode 100644
index 0000000..e421cfa
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png
new file mode 100644
index 0000000..2be6555
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png
new file mode 100644
index 0000000..efa69d2
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png
new file mode 100644
index 0000000..efa69d2
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png
new file mode 100644
index 0000000..e405742
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..0f84226
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "bt6DhdALyhf90gReozoQ0y3R3vZ.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg
new file mode 100644
index 0000000..1e19bbb
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..5d9e965
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..3124e77
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "umR9aXTxOxQUuDH2DamoJ5fIPB.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg
new file mode 100644
index 0000000..f4c469c
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..ed3e63e
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "eDildzNrm4XJABWkNKtqB29t6mv.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg
new file mode 100644
index 0000000..90ede16
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..8d49e39
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png
new file mode 100644
index 0000000..68aa392
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png
new file mode 100644
index 0000000..bb5d8b4
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png
new file mode 100644
index 0000000..12923f2
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json
new file mode 100644
index 0000000..4e659b8
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "settings.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "settings@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "settings@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png
new file mode 100644
index 0000000..e2d21f0
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png
new file mode 100644
index 0000000..6fd890d
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png
new file mode 100644
index 0000000..d68af6b
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json
new file mode 100644
index 0000000..50564ce
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "star.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "star@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "star@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png
new file mode 100644
index 0000000..2b2b41b
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png
new file mode 100644
index 0000000..f1367c8
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png
new file mode 100644
index 0000000..390ad8e
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json
new file mode 100644
index 0000000..04ea068
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "tag.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "tag@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "tag@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png
new file mode 100644
index 0000000..d46a1af
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png
new file mode 100644
index 0000000..5d176aa
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png
new file mode 100644
index 0000000..bee24d8
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json
new file mode 100644
index 0000000..16f2d86
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json
new file mode 100644
index 0000000..2febbf6
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json
new file mode 100644
index 0000000..37c7f9d
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json
new file mode 100644
index 0000000..8e8af21
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "interview.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "interview-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "interview-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json
new file mode 100644
index 0000000..4b2222a
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "Placeholder.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "Placeholder@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "Placeholder@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png
new file mode 100644
index 0000000..4f45f19
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png
new file mode 100644
index 0000000..e21d629
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png
new file mode 100644
index 0000000..6d89554
Binary files /dev/null and b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png differ
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Info.plist b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Info.plist
new file mode 100644
index 0000000..aab298d
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Info.plist
@@ -0,0 +1,52 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleDisplayName
+ Swift Movies
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ phillycocoa.$(PRODUCT_NAME:rfc1034identifier)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UIStatusBarTintParameters
+
+ UINavigationBar
+
+ Style
+ UIBarStyleDefault
+ Translucent
+
+
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+
+
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Movie.swift b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Movie.swift
new file mode 100644
index 0000000..dea2208
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/Movie.swift
@@ -0,0 +1,44 @@
+//
+// Movie.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+final class Movie {
+ let title: String
+ let posterPath: String
+ //let averageRating: Double
+ //let voteCount: Int
+ let rating: Rating
+
+ // Swift requires that all properties (except optionals which we will cover later)
+ // be initialized prior to the creation of the object
+ /* init(title: String, posterPath: String, averageRating: Double, voteCount: Int) {
+ // Try commenting one out to see what happens
+ self.title = title
+ self.posterPath = posterPath
+ self.averageRating = averageRating
+ self.voteCount = voteCount
+ }*/
+
+ init(title: String, posterPath: String, rating: Rating) {
+ // Try commenting one out to see what happens
+ self.title = title
+ self.posterPath = posterPath
+ self.rating = rating
+ }
+
+ convenience init(title: String, posterPath: String, averageRating: Double, voteCount: Int) {
+ let rating = Rating(averageRating: averageRating, voteCount: voteCount)
+ self.init(title: title, posterPath: posterPath, rating: rating)
+ }
+}
+
+struct Rating {
+ let averageRating: Double
+ let voteCount: Int
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/SettingsViewController.swift b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/SettingsViewController.swift
new file mode 100644
index 0000000..b4599f1
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/SettingsViewController.swift
@@ -0,0 +1,59 @@
+//
+// SettingsController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/7/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class SettingsViewController: UITableViewController {
+ // Private properties are only available to the instance of the object (can't be called from another object)
+ // Its good practice for things you know will only be used internally
+ private let webViewSegue = "showWebView"
+ private var webViewProperties: (title: String?, urlString: String?)
+
+ override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
+ let path = (indexPath.section, indexPath.row)
+
+ // We can use tuples and a switch to cover our row actions without a big if/else mess
+ // We are also using a tuple to capture the title and url in one variable
+ switch path {
+ case (0, 0):
+ self.webViewProperties = ("@themoviedb", "http://twitter.com/themoviedb")
+ case (0, 1):
+ self.webViewProperties = ("The Movie DB", "http://facebook.com/themoviedb")
+ case (1, 0):
+ self.webViewProperties = ("Terms of Service", "http://themoviedb.org/documentation/website/terms-of-use")
+ case (1, 1):
+ self.webViewProperties = ("Privacy Policy", "http://themoviedb.org/privacy-policy")
+ default:
+ // This should never happen, but lets get in the mindset of handling issues gracefully
+ // Swift will actually give an error if we don't have this default case (must be exhaustive)
+ // We can demonstrate this by commenting out one of our cell handlers then tapping that cell
+ let alertTitle = "Sorry!"
+ let alertMessage = "An unknown error occurred."
+ let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: UIAlertControllerStyle.Alert)
+ alert.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default, handler: nil))
+ self.presentViewController(alert, animated: true, completion: nil)
+ self.tableView.deselectRowAtIndexPath(indexPath, animated: false) // Deselect the cell so it does not "stick"
+
+ // Return so we don't perform the segue
+ return
+ }
+
+ // Since all the various rows are going to the same view controller, we can trigger the
+ // segue manually instead of having to create 4 segues pointing to the same controller
+ self.performSegueWithIdentifier(webViewSegue, sender: self)
+ }
+
+ override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
+ if segue.identifier == webViewSegue {
+ let webViewController = segue.destinationViewController as WebViewController
+ webViewController.titleString = self.webViewProperties.title
+ webViewController.urlString = self.webViewProperties.urlString
+ }
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift
new file mode 100644
index 0000000..f26c7e7
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift
@@ -0,0 +1,1335 @@
+// SwiftyJSON.swift
+//
+// Copyright (c) 2014 Ruoyu Fu, Pinglin Tang
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+// MARK: - Error
+
+///Error domain
+public let ErrorDomain: String! = "SwiftyJSONErrorDomain"
+
+///Error code
+public let ErrorUnsupportedType: Int! = 999
+public let ErrorIndexOutOfBounds: Int! = 900
+public let ErrorWrongType: Int! = 901
+public let ErrorNotExist: Int! = 500
+
+// MARK: - JSON Type
+
+/**
+JSON's type definitions.
+
+See http://tools.ietf.org/html/rfc7231#section-4.3
+*/
+public enum Type :Int{
+
+ case Number
+ case String
+ case Bool
+ case Array
+ case Dictionary
+ case Null
+ case Unknown
+}
+
+// MARK: - JSON Base
+
+public struct JSON {
+
+ /**
+ Creates a JSON using the data.
+
+ :param: data The NSData used to convert to json.Top level object in data is an NSArray or NSDictionary
+ :param: opt The JSON serialization reading options. `.AllowFragments` by default.
+ :param: error error The NSErrorPointer used to return the error. `nil` by default.
+
+ :returns: The created JSON
+ */
+ public init(data:NSData, options opt: NSJSONReadingOptions = .AllowFragments, error: NSErrorPointer = nil) {
+ if let object: AnyObject = NSJSONSerialization.JSONObjectWithData(data, options: opt, error: error) {
+ self.init(object)
+ } else {
+ self.init(NSNull())
+ }
+ }
+
+ /**
+ Creates a JSON using the object.
+
+ :param: object The object must have the following properties: All objects are NSString/String, NSNumber/Int/Float/Double/Bool, NSArray/Array, NSDictionary/Dictionary, or NSNull; All dictionary keys are NSStrings/String; NSNumbers are not NaN or infinity.
+
+ :returns: The created JSON
+ */
+ public init(_ object: AnyObject) {
+ self.object = object
+ }
+
+ /// Private object
+ private var _object: AnyObject = NSNull()
+ /// Private type
+ private var _type: Type = .Null
+ /// prviate error
+ private var _error: NSError?
+
+ /// Object in JSON
+ public var object: AnyObject {
+ get {
+ return _object
+ }
+ set {
+ _object = newValue
+ switch newValue {
+ case let number as NSNumber:
+ if number.isBool {
+ _type = .Bool
+ } else {
+ _type = .Number
+ }
+ case let string as NSString:
+ _type = .String
+ case let null as NSNull:
+ _type = .Null
+ case let array as [AnyObject]:
+ _type = .Array
+ case let dictionary as [String : AnyObject]:
+ _type = .Dictionary
+ default:
+ _type = .Unknown
+ _object = NSNull()
+ _error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"])
+ }
+ }
+ }
+
+ /// json type
+ public var type: Type { get { return _type } }
+
+ /// Error in JSON
+ public var error: NSError? { get { return self._error } }
+
+ /// The static null json
+ public static var nullJSON: JSON { get { return JSON(NSNull()) } }
+
+}
+
+// MARK: - SequenceType
+extension JSON: SequenceType{
+
+ /// If `type` is `.Array` or `.Dictionary`, return `array.empty` or `dictonary.empty` otherwise return `false`.
+ public var isEmpty: Bool {
+ get {
+ switch self.type {
+ case .Array:
+ return (self.object as [AnyObject]).isEmpty
+ case .Dictionary:
+ return (self.object as [String : AnyObject]).isEmpty
+ default:
+ return false
+ }
+ }
+ }
+
+ /// If `type` is `.Array` or `.Dictionary`, return `array.count` or `dictonary.count` otherwise return `0`.
+ public var count: Int {
+ get {
+ switch self.type {
+ case .Array:
+ return self.arrayValue.count
+ case .Dictionary:
+ return self.dictionaryValue.count
+ default:
+ return 0
+ }
+ }
+ }
+
+ /**
+ If `type` is `.Array` or `.Dictionary`, return a generator over the elements like `Array` or `Dictionary, otherwise return a generator over empty.
+
+ :returns: Return a *generator* over the elements of this *sequence*.
+ */
+ public func generate() -> GeneratorOf <(String, JSON)> {
+ switch self.type {
+ case .Array:
+ let array_ = object as [AnyObject]
+ var generate_ = array_.generate()
+ var index_: Int = 0
+ return GeneratorOf<(String, JSON)> {
+ if let element_: AnyObject = generate_.next() {
+ return ("\(index_++)", JSON(element_))
+ } else {
+ return nil
+ }
+ }
+ case .Dictionary:
+ let dictionary_ = object as [String : AnyObject]
+ var generate_ = dictionary_.generate()
+ return GeneratorOf<(String, JSON)> {
+ if let (key_: String, value_: AnyObject) = generate_.next() {
+ return (key_, JSON(value_))
+ } else {
+ return nil
+ }
+ }
+ default:
+ return GeneratorOf<(String, JSON)> {
+ return nil
+ }
+ }
+ }
+}
+
+// MARK: - Subscript
+
+/**
+* To mark both String and Int can be used in subscript.
+*/
+public protocol SubscriptType {}
+
+extension Int: SubscriptType {}
+
+extension String: SubscriptType {}
+
+extension JSON {
+
+ /// If `type` is `.Array`, return json which's object is `array[index]`, otherwise return null json with error.
+ private subscript(#index: Int) -> JSON {
+ get {
+
+ if self.type != .Array {
+ var errorResult_ = JSON.nullJSON
+ errorResult_._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] failure, It is not an array"])
+ return errorResult_
+ }
+
+ let array_ = self.object as [AnyObject]
+
+ if index >= 0 && index < array_.count {
+ return JSON(array_[index])
+ }
+
+ var errorResult_ = JSON.nullJSON
+ errorResult_._error = NSError(domain: ErrorDomain, code:ErrorIndexOutOfBounds , userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] is out of bounds"])
+ return errorResult_
+ }
+ set {
+ if self.type == .Array {
+ var array_ = self.object as [AnyObject]
+ if array_.count > index {
+ array_[index] = newValue.object
+ self.object = array_
+ }
+ }
+ }
+ }
+
+ /// If `type` is `.Dictionary`, return json which's object is `dictionary[key]` , otherwise return null json with error.
+ private subscript(#key: String) -> JSON {
+ get {
+ var returnJSON = JSON.nullJSON
+ if self.type == .Dictionary {
+ if let object_: AnyObject = self.object[key] {
+ returnJSON = JSON(object_)
+ } else {
+ returnJSON._error = NSError(domain: ErrorDomain, code: ErrorNotExist, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] does not exist"])
+ }
+ } else {
+ returnJSON._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] failure, It is not an dictionary"])
+ }
+ return returnJSON
+ }
+ set {
+ if self.type == .Dictionary {
+ var dictionary_ = self.object as [String : AnyObject]
+ dictionary_[key] = newValue.object
+ self.object = dictionary_
+ }
+ }
+ }
+
+ /// If `sub` is `Int`, return `subscript(index:)`; If `sub` is `String`, return `subscript(key:)`.
+ private subscript(#sub: SubscriptType) -> JSON {
+ get {
+ if sub is String {
+ return self[key:sub as String]
+ } else {
+ return self[index:sub as Int]
+ }
+ }
+ set {
+ if sub is String {
+ self[key:sub as String] = newValue
+ } else {
+ self[index:sub as Int] = newValue
+ }
+ }
+ }
+
+ /**
+ Find a json in the complex data structuresby using the Int/String's array.
+
+ :param: path The target json's path. Example:
+
+ let json = JSON[data]
+ let path = [9,"list","person","name"]
+ let name = json[path]
+
+ The same as: let name = json[9]["list"]["person"]["name"]
+
+ :returns: Return a json found by the path or a null json with error
+ */
+ public subscript(path: [SubscriptType]) -> JSON {
+ get {
+ if path.count == 0 {
+ return JSON.nullJSON
+ }
+
+ var next = self
+ for sub in path {
+ next = next[sub:sub]
+ }
+ return next
+ }
+ set {
+
+ switch path.count {
+ case 0: return
+ case 1: self[sub:path[0]] = newValue
+ default:
+ var last = newValue
+ var newPath = path
+ newPath.removeLast()
+ for sub in path.reverse() {
+ var previousLast = self[newPath]
+ previousLast[sub:sub] = last
+ last = previousLast
+ if newPath.count <= 1 {
+ break
+ }
+ newPath.removeLast()
+ }
+ self[sub:newPath[0]] = last
+ }
+ }
+ }
+
+ /**
+ Find a json in the complex data structuresby using the Int/String's array.
+
+ :param: path The target json's path. Example:
+
+ let name = json[9,"list","person","name"]
+
+ The same as: let name = json[9]["list"]["person"]["name"]
+
+ :returns: Return a json found by the path or a null json with error
+ */
+ public subscript(path: SubscriptType...) -> JSON {
+ get {
+ return self[path]
+ }
+ set {
+ self[path] = newValue
+ }
+ }
+}
+
+// MARK: - LiteralConvertible
+
+extension JSON: StringLiteralConvertible {
+
+ public init(stringLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+
+ public init(extendedGraphemeClusterLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+
+ public init(unicodeScalarLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: IntegerLiteralConvertible {
+
+ public init(integerLiteral value: IntegerLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: BooleanLiteralConvertible {
+
+ public init(booleanLiteral value: BooleanLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: FloatLiteralConvertible {
+
+ public init(floatLiteral value: FloatLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: DictionaryLiteralConvertible {
+
+ public init(dictionaryLiteral elements: (String, AnyObject)...) {
+ var dictionary_ = [String : AnyObject]()
+ for (key_, value) in elements {
+ dictionary_[key_] = value
+ }
+ self.init(dictionary_)
+ }
+}
+
+extension JSON: ArrayLiteralConvertible {
+
+ public init(arrayLiteral elements: AnyObject...) {
+ self.init(elements)
+ }
+}
+
+extension JSON: NilLiteralConvertible {
+
+ public init(nilLiteral: ()) {
+ self.init(NSNull())
+ }
+}
+
+// MARK: - Raw
+
+extension JSON: RawRepresentable {
+
+ public init?(rawValue: AnyObject) {
+ if JSON(rawValue).type == .Unknown {
+ return nil
+ } else {
+ self.init(rawValue)
+ }
+ }
+
+ public var rawValue: AnyObject {
+ return self.object
+ }
+
+ public func rawData(options opt: NSJSONWritingOptions = NSJSONWritingOptions(0), error: NSErrorPointer = nil) -> NSData? {
+ return NSJSONSerialization.dataWithJSONObject(self.object, options: opt, error:error)
+ }
+
+ public func rawString(encoding: UInt = NSUTF8StringEncoding, options opt: NSJSONWritingOptions = .PrettyPrinted) -> String? {
+ switch self.type {
+ case .Array, .Dictionary:
+ if let data = self.rawData(options: opt) {
+ return NSString(data: data, encoding: encoding)
+ } else {
+ return nil
+ }
+ case .String:
+ return (self.object as String)
+ case .Number:
+ return (self.object as NSNumber).stringValue
+ case .Bool:
+ return (self.object as Bool).description
+ case .Null:
+ return "null"
+ default:
+ return nil
+ }
+ }
+}
+
+// MARK: - Printable, DebugPrintable
+
+extension JSON: Printable, DebugPrintable {
+
+ public var description: String {
+ if let string = self.rawString(options:.PrettyPrinted) {
+ return string
+ } else {
+ return "unknown"
+ }
+ }
+
+ public var debugDescription: String {
+ return description
+ }
+}
+
+// MARK: - Array
+
+extension JSON {
+
+ //Optional [JSON]
+ public var array: [JSON]? {
+ get {
+ if self.type == .Array {
+ return map(self.object as [AnyObject]){ JSON($0) }
+ } else {
+ return nil
+ }
+ }
+ }
+
+ //Non-optional [JSON]
+ public var arrayValue: [JSON] {
+ get {
+ return self.array ?? []
+ }
+ }
+
+ //Optional [AnyObject]
+ public var arrayObject: [AnyObject]? {
+ get {
+ switch self.type {
+ case .Array:
+ return self.object as? [AnyObject]
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSMutableArray(array: newValue!, copyItems: true)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+}
+
+// MARK: - Dictionary
+
+extension JSON {
+
+ private func _map(source: [Key: Value], transform: Value -> NewValue) -> [Key: NewValue] {
+ var result = [Key: NewValue](minimumCapacity:source.count)
+ for (key,value) in source {
+ result[key] = transform(value)
+ }
+ return result
+ }
+
+ //Optional [String : JSON]
+ public var dictionary: [String : JSON]? {
+ get {
+ if self.type == .Dictionary {
+ return _map(self.object as [String : AnyObject]){ JSON($0) }
+ } else {
+ return nil
+ }
+ }
+ }
+
+ //Non-optional [String : JSON]
+ public var dictionaryValue: [String : JSON] {
+ get {
+ return self.dictionary ?? [:]
+ }
+ }
+
+ //Optional [String : AnyObject]
+ public var dictionaryObject: [String : AnyObject]? {
+ get {
+ switch self.type {
+ case .Dictionary:
+ return self.object as? [String : AnyObject]
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSMutableDictionary(dictionary: newValue!, copyItems: true)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+}
+
+// MARK: - Bool
+
+extension JSON: BooleanType {
+
+ //Optional bool
+ public var bool: Bool? {
+ get {
+ switch self.type {
+ case .Bool:
+ return self.object.boolValue
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(bool: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ //Non-optional bool
+ public var boolValue: Bool {
+ get {
+ switch self.type {
+ case .Bool, .Number, .String:
+ return self.object.boolValue
+ default:
+ return false
+ }
+ }
+ set {
+ self.object = NSNumber(bool: newValue)
+ }
+ }
+}
+
+// MARK: - String
+
+extension JSON {
+
+ //Optional string
+ public var string: String? {
+ get {
+ switch self.type {
+ case .String:
+ return self.object as? String
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSString(string:newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ //Non-optional string
+ public var stringValue: String {
+ get {
+ switch self.type {
+ case .String:
+ return self.object as String
+ case .Number:
+ return self.object.stringValue
+ case .Bool:
+ return (self.object as Bool).description
+ default:
+ return ""
+ }
+ }
+ set {
+ self.object = NSString(string:newValue)
+ }
+ }
+}
+
+// MARK: - Number
+extension JSON {
+
+ //Optional number
+ public var number: NSNumber? {
+ get {
+ switch self.type {
+ case .Number, .Bool:
+ return self.object as? NSNumber
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = newValue?.copy() ?? NSNull()
+ }
+ }
+
+ //Non-optional number
+ public var numberValue: NSNumber {
+ get {
+ switch self.type {
+ case .String:
+ let scanner = NSScanner(string: self.object as String)
+ if scanner.scanDouble(nil){
+ if (scanner.atEnd) {
+ return NSNumber(double:(self.object as NSString).doubleValue)
+ }
+ }
+ return NSNumber(double: 0.0)
+ case .Number, .Bool:
+ return self.object as NSNumber
+ default:
+ return NSNumber(double: 0.0)
+ }
+ }
+ set {
+ self.object = newValue.copy()
+ }
+ }
+}
+
+//MARK: - Null
+extension JSON {
+
+ public var null: NSNull? {
+ get {
+ switch self.type {
+ case .Null:
+ return NSNull()
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = NSNull()
+ }
+ }
+}
+
+//MARK: - URL
+extension JSON {
+
+ //Optional URL
+ public var URL: NSURL? {
+ get {
+ switch self.type {
+ case .String:
+ if let encodedString_ = self.object.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
+ return NSURL(string: encodedString_)
+ } else {
+ return nil
+ }
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = newValue?.absoluteString ?? NSNull()
+ }
+ }
+}
+
+// MARK: - Int, Double, Float, Int8, Int16, Int32, Int64
+
+extension JSON {
+
+ public var double: Double? {
+ get {
+ return self.number?.doubleValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(double: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var doubleValue: Double {
+ get {
+ return self.numberValue.doubleValue
+ }
+ set {
+ self.object = NSNumber(double: newValue)
+ }
+ }
+
+ public var float: Float? {
+ get {
+ return self.number?.floatValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(float: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var floatValue: Float {
+ get {
+ return self.numberValue.floatValue
+ }
+ set {
+ self.object = NSNumber(float: newValue)
+ }
+ }
+
+ public var int: Int? {
+ get {
+ return self.number?.longValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(integer: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var intValue: Int {
+ get {
+ return self.numberValue.integerValue
+ }
+ set {
+ self.object = NSNumber(integer: newValue)
+ }
+ }
+
+ public var uInt: UInt? {
+ get {
+ return self.number?.unsignedLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uIntValue: UInt {
+ get {
+ return self.numberValue.unsignedLongValue
+ }
+ set {
+ self.object = NSNumber(unsignedLong: newValue)
+ }
+ }
+
+ public var int8: Int8? {
+ get {
+ return self.number?.charValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(char: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int8Value: Int8 {
+ get {
+ return self.numberValue.charValue
+ }
+ set {
+ self.object = NSNumber(char: newValue)
+ }
+ }
+
+ public var uInt8: UInt8? {
+ get {
+ return self.number?.unsignedCharValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedChar: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt8Value: UInt8 {
+ get {
+ return self.numberValue.unsignedCharValue
+ }
+ set {
+ self.object = NSNumber(unsignedChar: newValue)
+ }
+ }
+
+ public var int16: Int16? {
+ get {
+ return self.number?.shortValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(short: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int16Value: Int16 {
+ get {
+ return self.numberValue.shortValue
+ }
+ set {
+ self.object = NSNumber(short: newValue)
+ }
+ }
+
+ public var uInt16: UInt16? {
+ get {
+ return self.number?.unsignedShortValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedShort: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt16Value: UInt16 {
+ get {
+ return self.numberValue.unsignedShortValue
+ }
+ set {
+ self.object = NSNumber(unsignedShort: newValue)
+ }
+ }
+
+ public var int32: Int32? {
+ get {
+ return self.number?.intValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(int: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int32Value: Int32 {
+ get {
+ return self.numberValue.intValue
+ }
+ set {
+ self.object = NSNumber(int: newValue)
+ }
+ }
+
+ public var uInt32: UInt32? {
+ get {
+ return self.number?.unsignedIntValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedInt: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt32Value: UInt32 {
+ get {
+ return self.numberValue.unsignedIntValue
+ }
+ set {
+ self.object = NSNumber(unsignedInt: newValue)
+ }
+ }
+
+ public var int64: Int64? {
+ get {
+ return self.number?.longLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(longLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int64Value: Int64 {
+ get {
+ return self.numberValue.longLongValue
+ }
+ set {
+ self.object = NSNumber(longLong: newValue)
+ }
+ }
+
+ public var uInt64: UInt64? {
+ get {
+ return self.number?.unsignedLongLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedLongLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt64Value: UInt64 {
+ get {
+ return self.numberValue.unsignedLongLongValue
+ }
+ set {
+ self.object = NSNumber(unsignedLongLong: newValue)
+ }
+ }
+}
+
+//MARK: - Comparable
+extension JSON: Comparable {}
+
+public func ==(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) == (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) == (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func <=(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) <= (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) <= (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func >=(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) >= (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) >= (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func >(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) > (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) > (rhs.object as String)
+ default:
+ return false
+ }
+}
+
+public func <(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) < (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) < (rhs.object as String)
+ default:
+ return false
+ }
+}
+
+private let trueNumber = NSNumber(bool: true)
+private let falseNumber = NSNumber(bool: false)
+private let trueObjCType = String.fromCString(trueNumber.objCType)
+private let falseObjCType = String.fromCString(falseNumber.objCType)
+
+// MARK: - NSNumber: Comparable
+
+extension NSNumber: Comparable {
+ var isBool:Bool {
+ get {
+ let objCType = String.fromCString(self.objCType)
+ if (self.compare(trueNumber) == NSComparisonResult.OrderedSame && objCType == trueObjCType) || (self.compare(falseNumber) == NSComparisonResult.OrderedSame && objCType == falseObjCType){
+ return true
+ } else {
+ return false
+ }
+ }
+ }
+}
+
+public func ==(lhs: NSNumber, rhs: NSNumber) -> Bool {
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedSame
+ }
+}
+
+public func !=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+ return !(lhs == rhs)
+}
+
+public func <(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedAscending
+ }
+}
+
+public func >(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedDescending
+ }
+}
+
+public func <=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) != NSComparisonResult.OrderedDescending
+ }
+}
+
+public func >=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) != NSComparisonResult.OrderedAscending
+ }
+}
+
+//MARK:- Unavailable
+
+@availability(*, unavailable, renamed="JSON")
+public typealias JSONValue = JSON
+
+extension JSON {
+
+ @availability(*, unavailable, message="use 'init(_ object:AnyObject)' instead")
+ public init(object: AnyObject) {
+ self = JSON(object)
+ }
+
+ @availability(*, unavailable, renamed="dictionaryObject")
+ public var dictionaryObjects: [String : AnyObject]? {
+ get { return self.dictionaryObject }
+ }
+
+ @availability(*, unavailable, renamed="arrayObject")
+ public var arrayObjects: [AnyObject]? {
+ get { return self.arrayObject }
+ }
+
+ @availability(*, unavailable, renamed="int8")
+ public var char: Int8? {
+ get {
+ return self.number?.charValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int8Value")
+ public var charValue: Int8 {
+ get {
+ return self.numberValue.charValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt8")
+ public var unsignedChar: UInt8? {
+ get{
+ return self.number?.unsignedCharValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt8Value")
+ public var unsignedCharValue: UInt8 {
+ get{
+ return self.numberValue.unsignedCharValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int16")
+ public var short: Int16? {
+ get{
+ return self.number?.shortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int16Value")
+ public var shortValue: Int16 {
+ get{
+ return self.numberValue.shortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt16")
+ public var unsignedShort: UInt16? {
+ get{
+ return self.number?.unsignedShortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt16Value")
+ public var unsignedShortValue: UInt16 {
+ get{
+ return self.numberValue.unsignedShortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int")
+ public var long: Int? {
+ get{
+ return self.number?.longValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="intValue")
+ public var longValue: Int {
+ get{
+ return self.numberValue.longValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt")
+ public var unsignedLong: UInt? {
+ get{
+ return self.number?.unsignedLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uIntValue")
+ public var unsignedLongValue: UInt {
+ get{
+ return self.numberValue.unsignedLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int64")
+ public var longLong: Int64? {
+ get{
+ return self.number?.longLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int64Value")
+ public var longLongValue: Int64 {
+ get{
+ return self.numberValue.longLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt64")
+ public var unsignedLongLong: UInt64? {
+ get{
+ return self.number?.unsignedLongLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt64Value")
+ public var unsignedLongLongValue: UInt64 {
+ get{
+ return self.numberValue.unsignedLongLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int")
+ public var integer: Int? {
+ get {
+ return self.number?.integerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="intValue")
+ public var integerValue: Int {
+ get {
+ return self.numberValue.integerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt")
+ public var unsignedInteger: Int? {
+ get {
+ return self.number?.unsignedIntegerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uIntValue")
+ public var unsignedIntegerValue: Int {
+ get {
+ return self.numberValue.unsignedIntegerValue
+ }
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/TMDB.swift b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/TMDB.swift
new file mode 100644
index 0000000..032e2a8
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/TMDB.swift
@@ -0,0 +1,55 @@
+//
+// TMDB.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import Foundation
+
+let TMDB_API_KEY = "8a4a247d072d9ca4a0072893ab60e277"
+let TMDB_API_BASE_URL = "http://api.themoviedb.org/3"
+let TMDB_IMAGE_BASE_URL = "http://image.tmdb.org/t/p"
+
+final class TMDB {
+ // MARK: MovieList
+
+ // Enums are very powerful in swift
+ // They can have (non-stored) properties and methods
+ // Enum types can also have non-integer values
+ enum MovieList {
+ case Popular
+ case Upcoming
+ case NowPlaying
+ case TopRated
+
+ static let allLists = [Popular, Upcoming, NowPlaying, TopRated]
+
+ var queryPath: String {
+ switch self {
+ case .Popular:
+ return "popular"
+ case .Upcoming:
+ return "upcoming"
+ case .NowPlaying:
+ return "now_playing"
+ case .TopRated:
+ return "top_rated"
+ }
+ }
+
+ var listName: String {
+ switch self {
+ case .Popular:
+ return "Popular"
+ case .Upcoming:
+ return "Upcoming"
+ case .NowPlaying:
+ return "Now Playing"
+ case .TopRated:
+ return "Top Rated"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/WebViewController.swift b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/WebViewController.swift
new file mode 100644
index 0000000..1373d09
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMovies/WebViewController.swift
@@ -0,0 +1,50 @@
+//
+// WebViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of WebViewController (optimization)
+final class WebViewController: UIViewController {
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var webView: UIWebView!
+
+ var urlString: String?
+ var titleString: String?
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.webView.delegate = self
+
+ // Since our titleString and urlString are optionals we have to unwrap them
+ if let title = titleString {
+ self.navigationItem.title = titleString
+ }
+
+ if let urlString = self.urlString {
+ // The NSURL init method returns an optional as well
+ // Its common for Cocoa methods to return optionals (because of Obj-C)
+ if let url = NSURL(string: urlString) {
+ let request = NSURLRequest(URL: url)
+ webView.loadRequest(request)
+ }
+ }
+ }
+}
+
+// Class extensions make it easy to group functionality, like protocol methods
+extension WebViewController: UIWebViewDelegate {
+ // These methods are called automatically when we set the delegate
+ // and adopt the protocol
+ func webViewDidStartLoad(webView: UIWebView) {
+ self.activityIndicator.startAnimating()
+ }
+
+ func webViewDidFinishLoad(webView: UIWebView) {
+ self.activityIndicator.stopAnimating()
+ }
+}
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMoviesTests/Info.plist b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMoviesTests/Info.plist
new file mode 100644
index 0000000..2afc012
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMoviesTests/Info.plist
@@ -0,0 +1,24 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ phillycocoa.$(PRODUCT_NAME:rfc1034identifier)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ BNDL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+
+
diff --git a/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift
new file mode 100644
index 0000000..3cb0bdc
--- /dev/null
+++ b/3 - Act II/2 - Finished Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift
@@ -0,0 +1,36 @@
+//
+// SwiftMoviesTests.swift
+// SwiftMoviesTests
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+import XCTest
+
+class SwiftMoviesTests: 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/3 - Act II/Optionals.playground/contents.xcplayground b/3 - Act II/Optionals.playground/contents.xcplayground
new file mode 100644
index 0000000..8e39341
--- /dev/null
+++ b/3 - Act II/Optionals.playground/contents.xcplayground
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/3 - Act II/Optionals.playground/section-1.swift b/3 - Act II/Optionals.playground/section-1.swift
new file mode 100644
index 0000000..898242e
--- /dev/null
+++ b/3 - Act II/Optionals.playground/section-1.swift
@@ -0,0 +1,30 @@
+// Playground - noun: a place where people can play
+
+import UIKit
+
+// Can't set variables and constants to nil
+// var string: String = nil // Error
+
+// Optional
+var string: String? = nil // Okay
+
+var stringOptional: String? = "Optional" // Value wrapped in optional {Some:"Optional"}
+
+stringOptional = "Changed!"
+
+stringOptional.uppercaseString // Error
+
+// "Safe" way
+if let unwrappedString = stringOptional {
+ unwrappedString.uppercaseString
+}
+
+// "Unsafe" Ways
+stringOptional!.uppercaseString //Forced unwrap
+var unwrappedstring: String! //Implicit unwrap
+
+
+// Optional Chaining
+var anotherString: String? = "Big gulps huh?"
+
+let newString = anotherString?.anotherOptional?.uppercaseString
diff --git a/3 - Act II/Optionals.playground/timeline.xctimeline b/3 - Act II/Optionals.playground/timeline.xctimeline
new file mode 100644
index 0000000..bf468af
--- /dev/null
+++ b/3 - Act II/Optionals.playground/timeline.xctimeline
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/4 - Act III/.DS_Store b/4 - Act III/.DS_Store
new file mode 100644
index 0000000..61475d0
Binary files /dev/null and b/4 - Act III/.DS_Store differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/.DS_Store b/4 - Act III/1 - Starting Project/SwiftMovies/.DS_Store
new file mode 100644
index 0000000..59b421f
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/.DS_Store differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..02bd8c2
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj
@@ -0,0 +1,474 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ F45D76761A5FD9FE001807F2 /* SwiftyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */; };
+ F4646C331A5DF40800336DFC /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4646C321A5DF40800336DFC /* SettingsViewController.swift */; };
+ F4678DB91A5A82F1005A33DE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DB81A5A82F1005A33DE /* AppDelegate.swift */; };
+ F4678DC01A5A82F1005A33DE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F4678DBE1A5A82F1005A33DE /* Main.storyboard */; };
+ F4678DC21A5A82F1005A33DE /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F4678DC11A5A82F1005A33DE /* Images.xcassets */; };
+ F4678DC51A5A82F1005A33DE /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */; };
+ F4678DD11A5A82F1005A33DE /* SwiftMoviesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */; };
+ F4678DE11A5A9582005A33DE /* Movie.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DE01A5A9582005A33DE /* Movie.swift */; };
+ F477D6AE1A5F20E2006FD97E /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */; };
+ F477D6B21A5F20FF006FD97E /* FilterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F477D6B11A5F20FF006FD97E /* FilterViewController.swift */; };
+ F49C6F8A1A5F47B200D0C49E /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F49C6F891A5F47B200D0C49E /* WebViewController.swift */; };
+ F4DC98D01A5E5B0C0030CC99 /* CollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */; };
+ F4DC98D21A5E6B460030CC99 /* TMDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4DC98D11A5E6B460030CC99 /* TMDB.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ F4678DCB1A5A82F1005A33DE /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = F4678DAB1A5A82F1005A33DE /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F4678DB21A5A82F1005A33DE;
+ remoteInfo = SwiftMovies;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyJSON.swift; sourceTree = ""; };
+ F4646C321A5DF40800336DFC /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; };
+ F4678DB31A5A82F1005A33DE /* SwiftMovies.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftMovies.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ F4678DB71A5A82F1005A33DE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ F4678DB81A5A82F1005A33DE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ F4678DBF1A5A82F1005A33DE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
+ F4678DC11A5A82F1005A33DE /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
+ F4678DC41A5A82F1005A33DE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
+ F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftMoviesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ F4678DCF1A5A82F1005A33DE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftMoviesTests.swift; sourceTree = ""; };
+ F4678DE01A5A9582005A33DE /* Movie.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Movie.swift; sourceTree = ""; };
+ F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; };
+ F477D6B11A5F20FF006FD97E /* FilterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilterViewController.swift; sourceTree = ""; };
+ F49C6F891A5F47B200D0C49E /* WebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebViewController.swift; sourceTree = ""; };
+ F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewController.swift; sourceTree = ""; };
+ F4DC98D11A5E6B460030CC99 /* TMDB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TMDB.swift; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ F4678DB01A5A82F1005A33DE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC71A5A82F1005A33DE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ F4678DAA1A5A82F1005A33DE = {
+ isa = PBXGroup;
+ children = (
+ F4678DB51A5A82F1005A33DE /* SwiftMovies */,
+ F4678DCD1A5A82F1005A33DE /* SwiftMoviesTests */,
+ F4678DB41A5A82F1005A33DE /* Products */,
+ );
+ sourceTree = "";
+ };
+ F4678DB41A5A82F1005A33DE /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DB31A5A82F1005A33DE /* SwiftMovies.app */,
+ F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ F4678DB51A5A82F1005A33DE /* SwiftMovies */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DB81A5A82F1005A33DE /* AppDelegate.swift */,
+ F4678DC11A5A82F1005A33DE /* Images.xcassets */,
+ F477D6AA1A5F209D006FD97E /* Controllers */,
+ F477D6B31A5F210F006FD97E /* Models */,
+ F477D6B71A5F215E006FD97E /* Networking */,
+ F4678DBE1A5A82F1005A33DE /* Main.storyboard */,
+ F4678DB61A5A82F1005A33DE /* Supporting Files */,
+ );
+ path = SwiftMovies;
+ sourceTree = "";
+ };
+ F4678DB61A5A82F1005A33DE /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */,
+ F4678DB71A5A82F1005A33DE /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ F4678DCD1A5A82F1005A33DE /* SwiftMoviesTests */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */,
+ F4678DCE1A5A82F1005A33DE /* Supporting Files */,
+ );
+ path = SwiftMoviesTests;
+ sourceTree = "";
+ };
+ F4678DCE1A5A82F1005A33DE /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DCF1A5A82F1005A33DE /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ F477D6AA1A5F209D006FD97E /* Controllers */ = {
+ isa = PBXGroup;
+ children = (
+ F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */,
+ F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */,
+ F477D6B11A5F20FF006FD97E /* FilterViewController.swift */,
+ F4646C321A5DF40800336DFC /* SettingsViewController.swift */,
+ F49C6F891A5F47B200D0C49E /* WebViewController.swift */,
+ );
+ name = Controllers;
+ sourceTree = "";
+ };
+ F477D6B31A5F210F006FD97E /* Models */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DE01A5A9582005A33DE /* Movie.swift */,
+ );
+ name = Models;
+ sourceTree = "";
+ };
+ F477D6B71A5F215E006FD97E /* Networking */ = {
+ isa = PBXGroup;
+ children = (
+ F4DC98D11A5E6B460030CC99 /* TMDB.swift */,
+ F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */,
+ );
+ name = Networking;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ F4678DB21A5A82F1005A33DE /* SwiftMovies */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F4678DD41A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMovies" */;
+ buildPhases = (
+ F4678DAF1A5A82F1005A33DE /* Sources */,
+ F4678DB01A5A82F1005A33DE /* Frameworks */,
+ F4678DB11A5A82F1005A33DE /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = SwiftMovies;
+ productName = SwiftMovies;
+ productReference = F4678DB31A5A82F1005A33DE /* SwiftMovies.app */;
+ productType = "com.apple.product-type.application";
+ };
+ F4678DC91A5A82F1005A33DE /* SwiftMoviesTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F4678DD71A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMoviesTests" */;
+ buildPhases = (
+ F4678DC61A5A82F1005A33DE /* Sources */,
+ F4678DC71A5A82F1005A33DE /* Frameworks */,
+ F4678DC81A5A82F1005A33DE /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ F4678DCC1A5A82F1005A33DE /* PBXTargetDependency */,
+ );
+ name = SwiftMoviesTests;
+ productName = SwiftMoviesTests;
+ productReference = F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ F4678DAB1A5A82F1005A33DE /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0610;
+ ORGANIZATIONNAME = "Philly Cocoaheads";
+ TargetAttributes = {
+ F4678DB21A5A82F1005A33DE = {
+ CreatedOnToolsVersion = 6.1.1;
+ };
+ F4678DC91A5A82F1005A33DE = {
+ CreatedOnToolsVersion = 6.1.1;
+ TestTargetID = F4678DB21A5A82F1005A33DE;
+ };
+ };
+ };
+ buildConfigurationList = F4678DAE1A5A82F1005A33DE /* Build configuration list for PBXProject "SwiftMovies" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = F4678DAA1A5A82F1005A33DE;
+ productRefGroup = F4678DB41A5A82F1005A33DE /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ F4678DB21A5A82F1005A33DE /* SwiftMovies */,
+ F4678DC91A5A82F1005A33DE /* SwiftMoviesTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ F4678DB11A5A82F1005A33DE /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4678DC01A5A82F1005A33DE /* Main.storyboard in Resources */,
+ F4678DC51A5A82F1005A33DE /* LaunchScreen.xib in Resources */,
+ F4678DC21A5A82F1005A33DE /* Images.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC81A5A82F1005A33DE /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ F4678DAF1A5A82F1005A33DE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4646C331A5DF40800336DFC /* SettingsViewController.swift in Sources */,
+ F477D6AE1A5F20E2006FD97E /* DetailViewController.swift in Sources */,
+ F49C6F8A1A5F47B200D0C49E /* WebViewController.swift in Sources */,
+ F45D76761A5FD9FE001807F2 /* SwiftyJSON.swift in Sources */,
+ F4DC98D01A5E5B0C0030CC99 /* CollectionViewController.swift in Sources */,
+ F4678DE11A5A9582005A33DE /* Movie.swift in Sources */,
+ F4DC98D21A5E6B460030CC99 /* TMDB.swift in Sources */,
+ F477D6B21A5F20FF006FD97E /* FilterViewController.swift in Sources */,
+ F4678DB91A5A82F1005A33DE /* AppDelegate.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC61A5A82F1005A33DE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4678DD11A5A82F1005A33DE /* SwiftMoviesTests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ F4678DCC1A5A82F1005A33DE /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F4678DB21A5A82F1005A33DE /* SwiftMovies */;
+ targetProxy = F4678DCB1A5A82F1005A33DE /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ F4678DBE1A5A82F1005A33DE /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F4678DBF1A5A82F1005A33DE /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "";
+ };
+ F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F4678DC41A5A82F1005A33DE /* Base */,
+ );
+ name = LaunchScreen.xib;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ F4678DD21A5A82F1005A33DE /* 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.1;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ F4678DD31A5A82F1005A33DE /* 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.1;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ F4678DD51A5A82F1005A33DE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = SwiftMovies/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ F4678DD61A5A82F1005A33DE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = SwiftMovies/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ F4678DD81A5A82F1005A33DE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = SwiftMoviesTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftMovies.app/SwiftMovies";
+ };
+ name = Debug;
+ };
+ F4678DD91A5A82F1005A33DE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = SwiftMoviesTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftMovies.app/SwiftMovies";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ F4678DAE1A5A82F1005A33DE /* Build configuration list for PBXProject "SwiftMovies" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD21A5A82F1005A33DE /* Debug */,
+ F4678DD31A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ F4678DD41A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMovies" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD51A5A82F1005A33DE /* Debug */,
+ F4678DD61A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ F4678DD71A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMoviesTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD81A5A82F1005A33DE /* Debug */,
+ F4678DD91A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = F4678DAB1A5A82F1005A33DE /* Project object */;
+}
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..7890687
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..40b54ec
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
new file mode 100644
index 0000000..fe2b454
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -0,0 +1,5 @@
+
+
+
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme
new file mode 100644
index 0000000..ec387aa
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..dd30f16
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,27 @@
+
+
+
+
+ SchemeUserState
+
+ SwiftMovies.xcscheme
+
+ orderHint
+ 0
+
+
+ SuppressBuildableAutocreation
+
+ F4678DB21A5A82F1005A33DE
+
+ primary
+
+
+ F4678DC91A5A82F1005A33DE
+
+ primary
+
+
+
+
+
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/AppDelegate.swift b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/AppDelegate.swift
new file mode 100644
index 0000000..9c2f2cc
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/AppDelegate.swift
@@ -0,0 +1,46 @@
+//
+// AppDelegate.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+@UIApplicationMain
+class AppDelegate: UIResponder, UIApplicationDelegate {
+
+ var window: UIWindow?
+
+
+ func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> 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/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib
new file mode 100644
index 0000000..9e43426
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..13a6325
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard
@@ -0,0 +1,604 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/CollectionViewController.swift b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/CollectionViewController.swift
new file mode 100644
index 0000000..18b8f1f
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/CollectionViewController.swift
@@ -0,0 +1,87 @@
+//
+// MovieCollectionController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Since we don't have to worry about headers and imports in Swift
+// It sometimes makes sense to keep multiple classes in the same file
+final class MovieCell: UICollectionViewCell {
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var imageView: UIImageView!
+}
+
+final class CollectionViewController: UIViewController {
+ @IBOutlet weak var collectionView: UICollectionView!
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+
+ // We will later be fetching our movies from the web
+ // so we went to use a var such that we can update our movies after load
+ // We need to have a value, so we default to an empty array
+ var movies: [Movie] = []
+ var activeList: TMDB.MovieList = .Popular // We can exclude the enum name and just use .Type
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.collectionView.delegate = self
+ self.collectionView.dataSource = self
+ self.loadPlaceholderData()
+ }
+
+ func loadPlaceholderData() {
+ let goneGirl = Movie(title: "Gone Girl", posterPath: "gonePoster", averageRating: 8.1, voteCount: 845)
+ let guardians = Movie(title: "Guardians of the Galaxy", posterPath: "guardiansPoster", averageRating: 9.2, voteCount: 1026)
+ let theHobbit = Movie(title: "The Hobbit", posterPath: "hobbitPoster", averageRating: 7.4, voteCount: 1343)
+ let theInterview = Movie(title: "The Interview", posterPath: "interviewPoster", averageRating: 6.3, voteCount: 824)
+
+ self.movies = [goneGirl, guardians, theHobbit, theInterview]
+ self.collectionView.reloadData()
+ }
+
+ override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
+ if segue.identifier == "showMovieView" {
+ // We use "as" to typecast to a certain object type
+ let movieController = segue.destinationViewController as DetailViewController
+ let indexPath = self.collectionView.indexPathsForSelectedItems().first as NSIndexPath?
+ if let selectedPath = indexPath {
+ // Pass the selected movie to detail view
+ let movie = self.movies[selectedPath.row]
+ movieController.movie = movie
+ }
+ }
+
+ if segue.identifier == "showFilterView" {
+ // We use "as" to typecast to a certain object type
+ let navController = segue.destinationViewController as UINavigationController
+ let filterController = navController.viewControllers.first as FilterViewController
+ // By setting the delegate to this controller we receive updates when the filter changes.
+ filterController.delegate = self
+ }
+ }
+}
+
+// Class extensions make it easy to group functionality, like protocol methods
+extension CollectionViewController: UICollectionViewDelegate, UICollectionViewDataSource {
+ func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+ return self.movies.count
+ }
+
+ func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
+ let movieCell = collectionView.dequeueReusableCellWithReuseIdentifier("movieCell", forIndexPath: indexPath) as MovieCell
+ let movie = self.movies[indexPath.row]
+ movieCell.imageView.image = UIImage(named: movie.posterPath)
+
+ return movieCell
+ }
+}
+
+extension CollectionViewController: FilterViewDelegate {
+ func filterDidChange(list: TMDB.MovieList) {
+ self.activeList = list
+ self.navigationItem.title = list.listName
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/DetailViewController.swift b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/DetailViewController.swift
new file mode 100644
index 0000000..09481c2
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/DetailViewController.swift
@@ -0,0 +1,46 @@
+//
+// MovieViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class DetailViewController: UIViewController {
+ @IBOutlet weak var backdropImageView: UIImageView!
+ @IBOutlet weak var backdropActivityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var titleLabel: UILabel!
+ @IBOutlet weak var ratingLabel: UILabel!
+ @IBOutlet weak var summaryLabel: UILabel!
+ @IBOutlet weak var releaseDateLabel: UILabel!
+ @IBOutlet weak var genresLabel: UILabel!
+ @IBOutlet weak var runtimeLabel: UILabel!
+
+ var movie: Movie?
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.loadMovieInfo()
+ }
+
+ private func loadMovieInfo() {
+ // Setup our empty state (how the screen should look while loading)
+ let ellipsis = "..."
+ self.backdropImageView.image = nil
+ self.titleLabel.text = ellipsis
+ self.navigationItem.title = ellipsis
+ self.ratingLabel.text = ellipsis
+ self.summaryLabel.text = ellipsis
+ self.releaseDateLabel.text = ellipsis
+ self.genresLabel.text = ellipsis
+ self.runtimeLabel.text = ellipsis
+
+ if let movie = self.movie {
+ self.titleLabel.text = movie.title
+ self.navigationItem.title = movie.title
+ }
+ }
+}
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/FilterViewController.swift b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/FilterViewController.swift
new file mode 100644
index 0000000..9f40850
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/FilterViewController.swift
@@ -0,0 +1,60 @@
+//
+// FiltersViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class FilterViewController: UIViewController {
+ // You can use protocols and delegates together to communicate between objects
+ // This will enable us to tell our Collection controller when the filter has changed
+ var delegate: FilterViewDelegate?
+
+ @IBAction func cancel(sender: AnyObject) {
+ self.dismiss()
+ }
+
+ func dismiss() {
+ self.navigationController?.dismissViewControllerAnimated(true, completion: nil)
+ }
+}
+
+// Class extensions make it easy to group functionality, like protocol methods
+extension FilterViewController: UITableViewDelegate, UITableViewDataSource {
+ func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return TMDB.MovieList.allLists.count
+ }
+
+ func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
+ let cell = tableView.dequeueReusableCellWithIdentifier("filterCell") as UITableViewCell
+ let movieList: TMDB.MovieList = TMDB.MovieList.allLists[indexPath.row]
+
+ cell.textLabel?.text = movieList.listName
+
+ if movieList == delegate?.activeList {
+ cell.accessoryType = UITableViewCellAccessoryType.Checkmark
+ } else {
+ cell.accessoryType = UITableViewCellAccessoryType.None
+ }
+
+ return cell
+ }
+
+ func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
+ tableView.deselectRowAtIndexPath(indexPath, animated: false) // Fix sticky cells
+ let movieList: TMDB.MovieList = TMDB.MovieList.allLists[indexPath.row]
+ self.delegate?.filterDidChange(movieList)
+ self.dismiss()
+ }
+}
+
+// Protocols allow us to force an object to adopt certain
+// properties and methods (by adopting the protocol)
+protocol FilterViewDelegate {
+ var activeList: TMDB.MovieList { get }
+ func filterDidChange(list: TMDB.MovieList)
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store
new file mode 100644
index 0000000..c068369
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..7997783
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,44 @@
+{
+ "images" : [
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-29@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-40@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-60@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-60@3x.png",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png
new file mode 100644
index 0000000..d463ba9
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png
new file mode 100644
index 0000000..e421cfa
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png
new file mode 100644
index 0000000..2be6555
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png
new file mode 100644
index 0000000..efa69d2
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png
new file mode 100644
index 0000000..efa69d2
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png
new file mode 100644
index 0000000..e405742
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..0f84226
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "bt6DhdALyhf90gReozoQ0y3R3vZ.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg
new file mode 100644
index 0000000..1e19bbb
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..5d9e965
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..3124e77
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "umR9aXTxOxQUuDH2DamoJ5fIPB.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg
new file mode 100644
index 0000000..f4c469c
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..ed3e63e
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "eDildzNrm4XJABWkNKtqB29t6mv.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg
new file mode 100644
index 0000000..90ede16
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..8d49e39
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png
new file mode 100644
index 0000000..68aa392
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png
new file mode 100644
index 0000000..bb5d8b4
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png
new file mode 100644
index 0000000..12923f2
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json
new file mode 100644
index 0000000..4e659b8
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "settings.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "settings@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "settings@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png
new file mode 100644
index 0000000..e2d21f0
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png
new file mode 100644
index 0000000..6fd890d
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png
new file mode 100644
index 0000000..d68af6b
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json
new file mode 100644
index 0000000..50564ce
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "star.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "star@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "star@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png
new file mode 100644
index 0000000..2b2b41b
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png
new file mode 100644
index 0000000..f1367c8
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png
new file mode 100644
index 0000000..390ad8e
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json
new file mode 100644
index 0000000..04ea068
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "tag.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "tag@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "tag@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png
new file mode 100644
index 0000000..d46a1af
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png
new file mode 100644
index 0000000..5d176aa
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png
new file mode 100644
index 0000000..bee24d8
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json
new file mode 100644
index 0000000..16f2d86
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json
new file mode 100644
index 0000000..2febbf6
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json
new file mode 100644
index 0000000..37c7f9d
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json
new file mode 100644
index 0000000..8e8af21
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "interview.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "interview-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "interview-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json
new file mode 100644
index 0000000..4b2222a
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "Placeholder.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "Placeholder@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "Placeholder@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png
new file mode 100644
index 0000000..4f45f19
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png
new file mode 100644
index 0000000..e21d629
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png
new file mode 100644
index 0000000..6d89554
Binary files /dev/null and b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png differ
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Info.plist b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Info.plist
new file mode 100644
index 0000000..aab298d
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Info.plist
@@ -0,0 +1,52 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleDisplayName
+ Swift Movies
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ phillycocoa.$(PRODUCT_NAME:rfc1034identifier)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UIStatusBarTintParameters
+
+ UINavigationBar
+
+ Style
+ UIBarStyleDefault
+ Translucent
+
+
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+
+
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Movie.swift b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Movie.swift
new file mode 100644
index 0000000..dea2208
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/Movie.swift
@@ -0,0 +1,44 @@
+//
+// Movie.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+final class Movie {
+ let title: String
+ let posterPath: String
+ //let averageRating: Double
+ //let voteCount: Int
+ let rating: Rating
+
+ // Swift requires that all properties (except optionals which we will cover later)
+ // be initialized prior to the creation of the object
+ /* init(title: String, posterPath: String, averageRating: Double, voteCount: Int) {
+ // Try commenting one out to see what happens
+ self.title = title
+ self.posterPath = posterPath
+ self.averageRating = averageRating
+ self.voteCount = voteCount
+ }*/
+
+ init(title: String, posterPath: String, rating: Rating) {
+ // Try commenting one out to see what happens
+ self.title = title
+ self.posterPath = posterPath
+ self.rating = rating
+ }
+
+ convenience init(title: String, posterPath: String, averageRating: Double, voteCount: Int) {
+ let rating = Rating(averageRating: averageRating, voteCount: voteCount)
+ self.init(title: title, posterPath: posterPath, rating: rating)
+ }
+}
+
+struct Rating {
+ let averageRating: Double
+ let voteCount: Int
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/SettingsViewController.swift b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/SettingsViewController.swift
new file mode 100644
index 0000000..b4599f1
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/SettingsViewController.swift
@@ -0,0 +1,59 @@
+//
+// SettingsController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/7/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class SettingsViewController: UITableViewController {
+ // Private properties are only available to the instance of the object (can't be called from another object)
+ // Its good practice for things you know will only be used internally
+ private let webViewSegue = "showWebView"
+ private var webViewProperties: (title: String?, urlString: String?)
+
+ override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
+ let path = (indexPath.section, indexPath.row)
+
+ // We can use tuples and a switch to cover our row actions without a big if/else mess
+ // We are also using a tuple to capture the title and url in one variable
+ switch path {
+ case (0, 0):
+ self.webViewProperties = ("@themoviedb", "http://twitter.com/themoviedb")
+ case (0, 1):
+ self.webViewProperties = ("The Movie DB", "http://facebook.com/themoviedb")
+ case (1, 0):
+ self.webViewProperties = ("Terms of Service", "http://themoviedb.org/documentation/website/terms-of-use")
+ case (1, 1):
+ self.webViewProperties = ("Privacy Policy", "http://themoviedb.org/privacy-policy")
+ default:
+ // This should never happen, but lets get in the mindset of handling issues gracefully
+ // Swift will actually give an error if we don't have this default case (must be exhaustive)
+ // We can demonstrate this by commenting out one of our cell handlers then tapping that cell
+ let alertTitle = "Sorry!"
+ let alertMessage = "An unknown error occurred."
+ let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: UIAlertControllerStyle.Alert)
+ alert.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default, handler: nil))
+ self.presentViewController(alert, animated: true, completion: nil)
+ self.tableView.deselectRowAtIndexPath(indexPath, animated: false) // Deselect the cell so it does not "stick"
+
+ // Return so we don't perform the segue
+ return
+ }
+
+ // Since all the various rows are going to the same view controller, we can trigger the
+ // segue manually instead of having to create 4 segues pointing to the same controller
+ self.performSegueWithIdentifier(webViewSegue, sender: self)
+ }
+
+ override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
+ if segue.identifier == webViewSegue {
+ let webViewController = segue.destinationViewController as WebViewController
+ webViewController.titleString = self.webViewProperties.title
+ webViewController.urlString = self.webViewProperties.urlString
+ }
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift
new file mode 100644
index 0000000..f26c7e7
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift
@@ -0,0 +1,1335 @@
+// SwiftyJSON.swift
+//
+// Copyright (c) 2014 Ruoyu Fu, Pinglin Tang
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+// MARK: - Error
+
+///Error domain
+public let ErrorDomain: String! = "SwiftyJSONErrorDomain"
+
+///Error code
+public let ErrorUnsupportedType: Int! = 999
+public let ErrorIndexOutOfBounds: Int! = 900
+public let ErrorWrongType: Int! = 901
+public let ErrorNotExist: Int! = 500
+
+// MARK: - JSON Type
+
+/**
+JSON's type definitions.
+
+See http://tools.ietf.org/html/rfc7231#section-4.3
+*/
+public enum Type :Int{
+
+ case Number
+ case String
+ case Bool
+ case Array
+ case Dictionary
+ case Null
+ case Unknown
+}
+
+// MARK: - JSON Base
+
+public struct JSON {
+
+ /**
+ Creates a JSON using the data.
+
+ :param: data The NSData used to convert to json.Top level object in data is an NSArray or NSDictionary
+ :param: opt The JSON serialization reading options. `.AllowFragments` by default.
+ :param: error error The NSErrorPointer used to return the error. `nil` by default.
+
+ :returns: The created JSON
+ */
+ public init(data:NSData, options opt: NSJSONReadingOptions = .AllowFragments, error: NSErrorPointer = nil) {
+ if let object: AnyObject = NSJSONSerialization.JSONObjectWithData(data, options: opt, error: error) {
+ self.init(object)
+ } else {
+ self.init(NSNull())
+ }
+ }
+
+ /**
+ Creates a JSON using the object.
+
+ :param: object The object must have the following properties: All objects are NSString/String, NSNumber/Int/Float/Double/Bool, NSArray/Array, NSDictionary/Dictionary, or NSNull; All dictionary keys are NSStrings/String; NSNumbers are not NaN or infinity.
+
+ :returns: The created JSON
+ */
+ public init(_ object: AnyObject) {
+ self.object = object
+ }
+
+ /// Private object
+ private var _object: AnyObject = NSNull()
+ /// Private type
+ private var _type: Type = .Null
+ /// prviate error
+ private var _error: NSError?
+
+ /// Object in JSON
+ public var object: AnyObject {
+ get {
+ return _object
+ }
+ set {
+ _object = newValue
+ switch newValue {
+ case let number as NSNumber:
+ if number.isBool {
+ _type = .Bool
+ } else {
+ _type = .Number
+ }
+ case let string as NSString:
+ _type = .String
+ case let null as NSNull:
+ _type = .Null
+ case let array as [AnyObject]:
+ _type = .Array
+ case let dictionary as [String : AnyObject]:
+ _type = .Dictionary
+ default:
+ _type = .Unknown
+ _object = NSNull()
+ _error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"])
+ }
+ }
+ }
+
+ /// json type
+ public var type: Type { get { return _type } }
+
+ /// Error in JSON
+ public var error: NSError? { get { return self._error } }
+
+ /// The static null json
+ public static var nullJSON: JSON { get { return JSON(NSNull()) } }
+
+}
+
+// MARK: - SequenceType
+extension JSON: SequenceType{
+
+ /// If `type` is `.Array` or `.Dictionary`, return `array.empty` or `dictonary.empty` otherwise return `false`.
+ public var isEmpty: Bool {
+ get {
+ switch self.type {
+ case .Array:
+ return (self.object as [AnyObject]).isEmpty
+ case .Dictionary:
+ return (self.object as [String : AnyObject]).isEmpty
+ default:
+ return false
+ }
+ }
+ }
+
+ /// If `type` is `.Array` or `.Dictionary`, return `array.count` or `dictonary.count` otherwise return `0`.
+ public var count: Int {
+ get {
+ switch self.type {
+ case .Array:
+ return self.arrayValue.count
+ case .Dictionary:
+ return self.dictionaryValue.count
+ default:
+ return 0
+ }
+ }
+ }
+
+ /**
+ If `type` is `.Array` or `.Dictionary`, return a generator over the elements like `Array` or `Dictionary, otherwise return a generator over empty.
+
+ :returns: Return a *generator* over the elements of this *sequence*.
+ */
+ public func generate() -> GeneratorOf <(String, JSON)> {
+ switch self.type {
+ case .Array:
+ let array_ = object as [AnyObject]
+ var generate_ = array_.generate()
+ var index_: Int = 0
+ return GeneratorOf<(String, JSON)> {
+ if let element_: AnyObject = generate_.next() {
+ return ("\(index_++)", JSON(element_))
+ } else {
+ return nil
+ }
+ }
+ case .Dictionary:
+ let dictionary_ = object as [String : AnyObject]
+ var generate_ = dictionary_.generate()
+ return GeneratorOf<(String, JSON)> {
+ if let (key_: String, value_: AnyObject) = generate_.next() {
+ return (key_, JSON(value_))
+ } else {
+ return nil
+ }
+ }
+ default:
+ return GeneratorOf<(String, JSON)> {
+ return nil
+ }
+ }
+ }
+}
+
+// MARK: - Subscript
+
+/**
+* To mark both String and Int can be used in subscript.
+*/
+public protocol SubscriptType {}
+
+extension Int: SubscriptType {}
+
+extension String: SubscriptType {}
+
+extension JSON {
+
+ /// If `type` is `.Array`, return json which's object is `array[index]`, otherwise return null json with error.
+ private subscript(#index: Int) -> JSON {
+ get {
+
+ if self.type != .Array {
+ var errorResult_ = JSON.nullJSON
+ errorResult_._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] failure, It is not an array"])
+ return errorResult_
+ }
+
+ let array_ = self.object as [AnyObject]
+
+ if index >= 0 && index < array_.count {
+ return JSON(array_[index])
+ }
+
+ var errorResult_ = JSON.nullJSON
+ errorResult_._error = NSError(domain: ErrorDomain, code:ErrorIndexOutOfBounds , userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] is out of bounds"])
+ return errorResult_
+ }
+ set {
+ if self.type == .Array {
+ var array_ = self.object as [AnyObject]
+ if array_.count > index {
+ array_[index] = newValue.object
+ self.object = array_
+ }
+ }
+ }
+ }
+
+ /// If `type` is `.Dictionary`, return json which's object is `dictionary[key]` , otherwise return null json with error.
+ private subscript(#key: String) -> JSON {
+ get {
+ var returnJSON = JSON.nullJSON
+ if self.type == .Dictionary {
+ if let object_: AnyObject = self.object[key] {
+ returnJSON = JSON(object_)
+ } else {
+ returnJSON._error = NSError(domain: ErrorDomain, code: ErrorNotExist, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] does not exist"])
+ }
+ } else {
+ returnJSON._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] failure, It is not an dictionary"])
+ }
+ return returnJSON
+ }
+ set {
+ if self.type == .Dictionary {
+ var dictionary_ = self.object as [String : AnyObject]
+ dictionary_[key] = newValue.object
+ self.object = dictionary_
+ }
+ }
+ }
+
+ /// If `sub` is `Int`, return `subscript(index:)`; If `sub` is `String`, return `subscript(key:)`.
+ private subscript(#sub: SubscriptType) -> JSON {
+ get {
+ if sub is String {
+ return self[key:sub as String]
+ } else {
+ return self[index:sub as Int]
+ }
+ }
+ set {
+ if sub is String {
+ self[key:sub as String] = newValue
+ } else {
+ self[index:sub as Int] = newValue
+ }
+ }
+ }
+
+ /**
+ Find a json in the complex data structuresby using the Int/String's array.
+
+ :param: path The target json's path. Example:
+
+ let json = JSON[data]
+ let path = [9,"list","person","name"]
+ let name = json[path]
+
+ The same as: let name = json[9]["list"]["person"]["name"]
+
+ :returns: Return a json found by the path or a null json with error
+ */
+ public subscript(path: [SubscriptType]) -> JSON {
+ get {
+ if path.count == 0 {
+ return JSON.nullJSON
+ }
+
+ var next = self
+ for sub in path {
+ next = next[sub:sub]
+ }
+ return next
+ }
+ set {
+
+ switch path.count {
+ case 0: return
+ case 1: self[sub:path[0]] = newValue
+ default:
+ var last = newValue
+ var newPath = path
+ newPath.removeLast()
+ for sub in path.reverse() {
+ var previousLast = self[newPath]
+ previousLast[sub:sub] = last
+ last = previousLast
+ if newPath.count <= 1 {
+ break
+ }
+ newPath.removeLast()
+ }
+ self[sub:newPath[0]] = last
+ }
+ }
+ }
+
+ /**
+ Find a json in the complex data structuresby using the Int/String's array.
+
+ :param: path The target json's path. Example:
+
+ let name = json[9,"list","person","name"]
+
+ The same as: let name = json[9]["list"]["person"]["name"]
+
+ :returns: Return a json found by the path or a null json with error
+ */
+ public subscript(path: SubscriptType...) -> JSON {
+ get {
+ return self[path]
+ }
+ set {
+ self[path] = newValue
+ }
+ }
+}
+
+// MARK: - LiteralConvertible
+
+extension JSON: StringLiteralConvertible {
+
+ public init(stringLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+
+ public init(extendedGraphemeClusterLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+
+ public init(unicodeScalarLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: IntegerLiteralConvertible {
+
+ public init(integerLiteral value: IntegerLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: BooleanLiteralConvertible {
+
+ public init(booleanLiteral value: BooleanLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: FloatLiteralConvertible {
+
+ public init(floatLiteral value: FloatLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: DictionaryLiteralConvertible {
+
+ public init(dictionaryLiteral elements: (String, AnyObject)...) {
+ var dictionary_ = [String : AnyObject]()
+ for (key_, value) in elements {
+ dictionary_[key_] = value
+ }
+ self.init(dictionary_)
+ }
+}
+
+extension JSON: ArrayLiteralConvertible {
+
+ public init(arrayLiteral elements: AnyObject...) {
+ self.init(elements)
+ }
+}
+
+extension JSON: NilLiteralConvertible {
+
+ public init(nilLiteral: ()) {
+ self.init(NSNull())
+ }
+}
+
+// MARK: - Raw
+
+extension JSON: RawRepresentable {
+
+ public init?(rawValue: AnyObject) {
+ if JSON(rawValue).type == .Unknown {
+ return nil
+ } else {
+ self.init(rawValue)
+ }
+ }
+
+ public var rawValue: AnyObject {
+ return self.object
+ }
+
+ public func rawData(options opt: NSJSONWritingOptions = NSJSONWritingOptions(0), error: NSErrorPointer = nil) -> NSData? {
+ return NSJSONSerialization.dataWithJSONObject(self.object, options: opt, error:error)
+ }
+
+ public func rawString(encoding: UInt = NSUTF8StringEncoding, options opt: NSJSONWritingOptions = .PrettyPrinted) -> String? {
+ switch self.type {
+ case .Array, .Dictionary:
+ if let data = self.rawData(options: opt) {
+ return NSString(data: data, encoding: encoding)
+ } else {
+ return nil
+ }
+ case .String:
+ return (self.object as String)
+ case .Number:
+ return (self.object as NSNumber).stringValue
+ case .Bool:
+ return (self.object as Bool).description
+ case .Null:
+ return "null"
+ default:
+ return nil
+ }
+ }
+}
+
+// MARK: - Printable, DebugPrintable
+
+extension JSON: Printable, DebugPrintable {
+
+ public var description: String {
+ if let string = self.rawString(options:.PrettyPrinted) {
+ return string
+ } else {
+ return "unknown"
+ }
+ }
+
+ public var debugDescription: String {
+ return description
+ }
+}
+
+// MARK: - Array
+
+extension JSON {
+
+ //Optional [JSON]
+ public var array: [JSON]? {
+ get {
+ if self.type == .Array {
+ return map(self.object as [AnyObject]){ JSON($0) }
+ } else {
+ return nil
+ }
+ }
+ }
+
+ //Non-optional [JSON]
+ public var arrayValue: [JSON] {
+ get {
+ return self.array ?? []
+ }
+ }
+
+ //Optional [AnyObject]
+ public var arrayObject: [AnyObject]? {
+ get {
+ switch self.type {
+ case .Array:
+ return self.object as? [AnyObject]
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSMutableArray(array: newValue!, copyItems: true)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+}
+
+// MARK: - Dictionary
+
+extension JSON {
+
+ private func _map(source: [Key: Value], transform: Value -> NewValue) -> [Key: NewValue] {
+ var result = [Key: NewValue](minimumCapacity:source.count)
+ for (key,value) in source {
+ result[key] = transform(value)
+ }
+ return result
+ }
+
+ //Optional [String : JSON]
+ public var dictionary: [String : JSON]? {
+ get {
+ if self.type == .Dictionary {
+ return _map(self.object as [String : AnyObject]){ JSON($0) }
+ } else {
+ return nil
+ }
+ }
+ }
+
+ //Non-optional [String : JSON]
+ public var dictionaryValue: [String : JSON] {
+ get {
+ return self.dictionary ?? [:]
+ }
+ }
+
+ //Optional [String : AnyObject]
+ public var dictionaryObject: [String : AnyObject]? {
+ get {
+ switch self.type {
+ case .Dictionary:
+ return self.object as? [String : AnyObject]
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSMutableDictionary(dictionary: newValue!, copyItems: true)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+}
+
+// MARK: - Bool
+
+extension JSON: BooleanType {
+
+ //Optional bool
+ public var bool: Bool? {
+ get {
+ switch self.type {
+ case .Bool:
+ return self.object.boolValue
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(bool: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ //Non-optional bool
+ public var boolValue: Bool {
+ get {
+ switch self.type {
+ case .Bool, .Number, .String:
+ return self.object.boolValue
+ default:
+ return false
+ }
+ }
+ set {
+ self.object = NSNumber(bool: newValue)
+ }
+ }
+}
+
+// MARK: - String
+
+extension JSON {
+
+ //Optional string
+ public var string: String? {
+ get {
+ switch self.type {
+ case .String:
+ return self.object as? String
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSString(string:newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ //Non-optional string
+ public var stringValue: String {
+ get {
+ switch self.type {
+ case .String:
+ return self.object as String
+ case .Number:
+ return self.object.stringValue
+ case .Bool:
+ return (self.object as Bool).description
+ default:
+ return ""
+ }
+ }
+ set {
+ self.object = NSString(string:newValue)
+ }
+ }
+}
+
+// MARK: - Number
+extension JSON {
+
+ //Optional number
+ public var number: NSNumber? {
+ get {
+ switch self.type {
+ case .Number, .Bool:
+ return self.object as? NSNumber
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = newValue?.copy() ?? NSNull()
+ }
+ }
+
+ //Non-optional number
+ public var numberValue: NSNumber {
+ get {
+ switch self.type {
+ case .String:
+ let scanner = NSScanner(string: self.object as String)
+ if scanner.scanDouble(nil){
+ if (scanner.atEnd) {
+ return NSNumber(double:(self.object as NSString).doubleValue)
+ }
+ }
+ return NSNumber(double: 0.0)
+ case .Number, .Bool:
+ return self.object as NSNumber
+ default:
+ return NSNumber(double: 0.0)
+ }
+ }
+ set {
+ self.object = newValue.copy()
+ }
+ }
+}
+
+//MARK: - Null
+extension JSON {
+
+ public var null: NSNull? {
+ get {
+ switch self.type {
+ case .Null:
+ return NSNull()
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = NSNull()
+ }
+ }
+}
+
+//MARK: - URL
+extension JSON {
+
+ //Optional URL
+ public var URL: NSURL? {
+ get {
+ switch self.type {
+ case .String:
+ if let encodedString_ = self.object.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
+ return NSURL(string: encodedString_)
+ } else {
+ return nil
+ }
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = newValue?.absoluteString ?? NSNull()
+ }
+ }
+}
+
+// MARK: - Int, Double, Float, Int8, Int16, Int32, Int64
+
+extension JSON {
+
+ public var double: Double? {
+ get {
+ return self.number?.doubleValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(double: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var doubleValue: Double {
+ get {
+ return self.numberValue.doubleValue
+ }
+ set {
+ self.object = NSNumber(double: newValue)
+ }
+ }
+
+ public var float: Float? {
+ get {
+ return self.number?.floatValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(float: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var floatValue: Float {
+ get {
+ return self.numberValue.floatValue
+ }
+ set {
+ self.object = NSNumber(float: newValue)
+ }
+ }
+
+ public var int: Int? {
+ get {
+ return self.number?.longValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(integer: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var intValue: Int {
+ get {
+ return self.numberValue.integerValue
+ }
+ set {
+ self.object = NSNumber(integer: newValue)
+ }
+ }
+
+ public var uInt: UInt? {
+ get {
+ return self.number?.unsignedLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uIntValue: UInt {
+ get {
+ return self.numberValue.unsignedLongValue
+ }
+ set {
+ self.object = NSNumber(unsignedLong: newValue)
+ }
+ }
+
+ public var int8: Int8? {
+ get {
+ return self.number?.charValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(char: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int8Value: Int8 {
+ get {
+ return self.numberValue.charValue
+ }
+ set {
+ self.object = NSNumber(char: newValue)
+ }
+ }
+
+ public var uInt8: UInt8? {
+ get {
+ return self.number?.unsignedCharValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedChar: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt8Value: UInt8 {
+ get {
+ return self.numberValue.unsignedCharValue
+ }
+ set {
+ self.object = NSNumber(unsignedChar: newValue)
+ }
+ }
+
+ public var int16: Int16? {
+ get {
+ return self.number?.shortValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(short: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int16Value: Int16 {
+ get {
+ return self.numberValue.shortValue
+ }
+ set {
+ self.object = NSNumber(short: newValue)
+ }
+ }
+
+ public var uInt16: UInt16? {
+ get {
+ return self.number?.unsignedShortValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedShort: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt16Value: UInt16 {
+ get {
+ return self.numberValue.unsignedShortValue
+ }
+ set {
+ self.object = NSNumber(unsignedShort: newValue)
+ }
+ }
+
+ public var int32: Int32? {
+ get {
+ return self.number?.intValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(int: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int32Value: Int32 {
+ get {
+ return self.numberValue.intValue
+ }
+ set {
+ self.object = NSNumber(int: newValue)
+ }
+ }
+
+ public var uInt32: UInt32? {
+ get {
+ return self.number?.unsignedIntValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedInt: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt32Value: UInt32 {
+ get {
+ return self.numberValue.unsignedIntValue
+ }
+ set {
+ self.object = NSNumber(unsignedInt: newValue)
+ }
+ }
+
+ public var int64: Int64? {
+ get {
+ return self.number?.longLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(longLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int64Value: Int64 {
+ get {
+ return self.numberValue.longLongValue
+ }
+ set {
+ self.object = NSNumber(longLong: newValue)
+ }
+ }
+
+ public var uInt64: UInt64? {
+ get {
+ return self.number?.unsignedLongLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedLongLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt64Value: UInt64 {
+ get {
+ return self.numberValue.unsignedLongLongValue
+ }
+ set {
+ self.object = NSNumber(unsignedLongLong: newValue)
+ }
+ }
+}
+
+//MARK: - Comparable
+extension JSON: Comparable {}
+
+public func ==(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) == (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) == (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func <=(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) <= (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) <= (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func >=(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) >= (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) >= (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func >(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) > (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) > (rhs.object as String)
+ default:
+ return false
+ }
+}
+
+public func <(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) < (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) < (rhs.object as String)
+ default:
+ return false
+ }
+}
+
+private let trueNumber = NSNumber(bool: true)
+private let falseNumber = NSNumber(bool: false)
+private let trueObjCType = String.fromCString(trueNumber.objCType)
+private let falseObjCType = String.fromCString(falseNumber.objCType)
+
+// MARK: - NSNumber: Comparable
+
+extension NSNumber: Comparable {
+ var isBool:Bool {
+ get {
+ let objCType = String.fromCString(self.objCType)
+ if (self.compare(trueNumber) == NSComparisonResult.OrderedSame && objCType == trueObjCType) || (self.compare(falseNumber) == NSComparisonResult.OrderedSame && objCType == falseObjCType){
+ return true
+ } else {
+ return false
+ }
+ }
+ }
+}
+
+public func ==(lhs: NSNumber, rhs: NSNumber) -> Bool {
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedSame
+ }
+}
+
+public func !=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+ return !(lhs == rhs)
+}
+
+public func <(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedAscending
+ }
+}
+
+public func >(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedDescending
+ }
+}
+
+public func <=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) != NSComparisonResult.OrderedDescending
+ }
+}
+
+public func >=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) != NSComparisonResult.OrderedAscending
+ }
+}
+
+//MARK:- Unavailable
+
+@availability(*, unavailable, renamed="JSON")
+public typealias JSONValue = JSON
+
+extension JSON {
+
+ @availability(*, unavailable, message="use 'init(_ object:AnyObject)' instead")
+ public init(object: AnyObject) {
+ self = JSON(object)
+ }
+
+ @availability(*, unavailable, renamed="dictionaryObject")
+ public var dictionaryObjects: [String : AnyObject]? {
+ get { return self.dictionaryObject }
+ }
+
+ @availability(*, unavailable, renamed="arrayObject")
+ public var arrayObjects: [AnyObject]? {
+ get { return self.arrayObject }
+ }
+
+ @availability(*, unavailable, renamed="int8")
+ public var char: Int8? {
+ get {
+ return self.number?.charValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int8Value")
+ public var charValue: Int8 {
+ get {
+ return self.numberValue.charValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt8")
+ public var unsignedChar: UInt8? {
+ get{
+ return self.number?.unsignedCharValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt8Value")
+ public var unsignedCharValue: UInt8 {
+ get{
+ return self.numberValue.unsignedCharValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int16")
+ public var short: Int16? {
+ get{
+ return self.number?.shortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int16Value")
+ public var shortValue: Int16 {
+ get{
+ return self.numberValue.shortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt16")
+ public var unsignedShort: UInt16? {
+ get{
+ return self.number?.unsignedShortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt16Value")
+ public var unsignedShortValue: UInt16 {
+ get{
+ return self.numberValue.unsignedShortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int")
+ public var long: Int? {
+ get{
+ return self.number?.longValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="intValue")
+ public var longValue: Int {
+ get{
+ return self.numberValue.longValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt")
+ public var unsignedLong: UInt? {
+ get{
+ return self.number?.unsignedLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uIntValue")
+ public var unsignedLongValue: UInt {
+ get{
+ return self.numberValue.unsignedLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int64")
+ public var longLong: Int64? {
+ get{
+ return self.number?.longLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int64Value")
+ public var longLongValue: Int64 {
+ get{
+ return self.numberValue.longLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt64")
+ public var unsignedLongLong: UInt64? {
+ get{
+ return self.number?.unsignedLongLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt64Value")
+ public var unsignedLongLongValue: UInt64 {
+ get{
+ return self.numberValue.unsignedLongLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int")
+ public var integer: Int? {
+ get {
+ return self.number?.integerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="intValue")
+ public var integerValue: Int {
+ get {
+ return self.numberValue.integerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt")
+ public var unsignedInteger: Int? {
+ get {
+ return self.number?.unsignedIntegerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uIntValue")
+ public var unsignedIntegerValue: Int {
+ get {
+ return self.numberValue.unsignedIntegerValue
+ }
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/TMDB.swift b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/TMDB.swift
new file mode 100644
index 0000000..032e2a8
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/TMDB.swift
@@ -0,0 +1,55 @@
+//
+// TMDB.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import Foundation
+
+let TMDB_API_KEY = "8a4a247d072d9ca4a0072893ab60e277"
+let TMDB_API_BASE_URL = "http://api.themoviedb.org/3"
+let TMDB_IMAGE_BASE_URL = "http://image.tmdb.org/t/p"
+
+final class TMDB {
+ // MARK: MovieList
+
+ // Enums are very powerful in swift
+ // They can have (non-stored) properties and methods
+ // Enum types can also have non-integer values
+ enum MovieList {
+ case Popular
+ case Upcoming
+ case NowPlaying
+ case TopRated
+
+ static let allLists = [Popular, Upcoming, NowPlaying, TopRated]
+
+ var queryPath: String {
+ switch self {
+ case .Popular:
+ return "popular"
+ case .Upcoming:
+ return "upcoming"
+ case .NowPlaying:
+ return "now_playing"
+ case .TopRated:
+ return "top_rated"
+ }
+ }
+
+ var listName: String {
+ switch self {
+ case .Popular:
+ return "Popular"
+ case .Upcoming:
+ return "Upcoming"
+ case .NowPlaying:
+ return "Now Playing"
+ case .TopRated:
+ return "Top Rated"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/WebViewController.swift b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/WebViewController.swift
new file mode 100644
index 0000000..1373d09
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMovies/WebViewController.swift
@@ -0,0 +1,50 @@
+//
+// WebViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of WebViewController (optimization)
+final class WebViewController: UIViewController {
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var webView: UIWebView!
+
+ var urlString: String?
+ var titleString: String?
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.webView.delegate = self
+
+ // Since our titleString and urlString are optionals we have to unwrap them
+ if let title = titleString {
+ self.navigationItem.title = titleString
+ }
+
+ if let urlString = self.urlString {
+ // The NSURL init method returns an optional as well
+ // Its common for Cocoa methods to return optionals (because of Obj-C)
+ if let url = NSURL(string: urlString) {
+ let request = NSURLRequest(URL: url)
+ webView.loadRequest(request)
+ }
+ }
+ }
+}
+
+// Class extensions make it easy to group functionality, like protocol methods
+extension WebViewController: UIWebViewDelegate {
+ // These methods are called automatically when we set the delegate
+ // and adopt the protocol
+ func webViewDidStartLoad(webView: UIWebView) {
+ self.activityIndicator.startAnimating()
+ }
+
+ func webViewDidFinishLoad(webView: UIWebView) {
+ self.activityIndicator.stopAnimating()
+ }
+}
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMoviesTests/Info.plist b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMoviesTests/Info.plist
new file mode 100644
index 0000000..2afc012
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMoviesTests/Info.plist
@@ -0,0 +1,24 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ phillycocoa.$(PRODUCT_NAME:rfc1034identifier)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ BNDL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+
+
diff --git a/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift
new file mode 100644
index 0000000..3cb0bdc
--- /dev/null
+++ b/4 - Act III/1 - Starting Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift
@@ -0,0 +1,36 @@
+//
+// SwiftMoviesTests.swift
+// SwiftMoviesTests
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+import XCTest
+
+class SwiftMoviesTests: 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/4 - Act III/2 - Finished Project/SwiftMovies/.DS_Store b/4 - Act III/2 - Finished Project/SwiftMovies/.DS_Store
new file mode 100644
index 0000000..ff72229
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/.DS_Store differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..02bd8c2
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj
@@ -0,0 +1,474 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ F45D76761A5FD9FE001807F2 /* SwiftyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */; };
+ F4646C331A5DF40800336DFC /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4646C321A5DF40800336DFC /* SettingsViewController.swift */; };
+ F4678DB91A5A82F1005A33DE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DB81A5A82F1005A33DE /* AppDelegate.swift */; };
+ F4678DC01A5A82F1005A33DE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F4678DBE1A5A82F1005A33DE /* Main.storyboard */; };
+ F4678DC21A5A82F1005A33DE /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F4678DC11A5A82F1005A33DE /* Images.xcassets */; };
+ F4678DC51A5A82F1005A33DE /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */; };
+ F4678DD11A5A82F1005A33DE /* SwiftMoviesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */; };
+ F4678DE11A5A9582005A33DE /* Movie.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DE01A5A9582005A33DE /* Movie.swift */; };
+ F477D6AE1A5F20E2006FD97E /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */; };
+ F477D6B21A5F20FF006FD97E /* FilterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F477D6B11A5F20FF006FD97E /* FilterViewController.swift */; };
+ F49C6F8A1A5F47B200D0C49E /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F49C6F891A5F47B200D0C49E /* WebViewController.swift */; };
+ F4DC98D01A5E5B0C0030CC99 /* CollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */; };
+ F4DC98D21A5E6B460030CC99 /* TMDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4DC98D11A5E6B460030CC99 /* TMDB.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ F4678DCB1A5A82F1005A33DE /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = F4678DAB1A5A82F1005A33DE /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F4678DB21A5A82F1005A33DE;
+ remoteInfo = SwiftMovies;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyJSON.swift; sourceTree = ""; };
+ F4646C321A5DF40800336DFC /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; };
+ F4678DB31A5A82F1005A33DE /* SwiftMovies.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftMovies.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ F4678DB71A5A82F1005A33DE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ F4678DB81A5A82F1005A33DE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ F4678DBF1A5A82F1005A33DE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
+ F4678DC11A5A82F1005A33DE /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
+ F4678DC41A5A82F1005A33DE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
+ F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftMoviesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ F4678DCF1A5A82F1005A33DE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftMoviesTests.swift; sourceTree = ""; };
+ F4678DE01A5A9582005A33DE /* Movie.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Movie.swift; sourceTree = ""; };
+ F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; };
+ F477D6B11A5F20FF006FD97E /* FilterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilterViewController.swift; sourceTree = ""; };
+ F49C6F891A5F47B200D0C49E /* WebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebViewController.swift; sourceTree = ""; };
+ F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewController.swift; sourceTree = ""; };
+ F4DC98D11A5E6B460030CC99 /* TMDB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TMDB.swift; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ F4678DB01A5A82F1005A33DE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC71A5A82F1005A33DE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ F4678DAA1A5A82F1005A33DE = {
+ isa = PBXGroup;
+ children = (
+ F4678DB51A5A82F1005A33DE /* SwiftMovies */,
+ F4678DCD1A5A82F1005A33DE /* SwiftMoviesTests */,
+ F4678DB41A5A82F1005A33DE /* Products */,
+ );
+ sourceTree = "";
+ };
+ F4678DB41A5A82F1005A33DE /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DB31A5A82F1005A33DE /* SwiftMovies.app */,
+ F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ F4678DB51A5A82F1005A33DE /* SwiftMovies */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DB81A5A82F1005A33DE /* AppDelegate.swift */,
+ F4678DC11A5A82F1005A33DE /* Images.xcassets */,
+ F477D6AA1A5F209D006FD97E /* Controllers */,
+ F477D6B31A5F210F006FD97E /* Models */,
+ F477D6B71A5F215E006FD97E /* Networking */,
+ F4678DBE1A5A82F1005A33DE /* Main.storyboard */,
+ F4678DB61A5A82F1005A33DE /* Supporting Files */,
+ );
+ path = SwiftMovies;
+ sourceTree = "";
+ };
+ F4678DB61A5A82F1005A33DE /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */,
+ F4678DB71A5A82F1005A33DE /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ F4678DCD1A5A82F1005A33DE /* SwiftMoviesTests */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */,
+ F4678DCE1A5A82F1005A33DE /* Supporting Files */,
+ );
+ path = SwiftMoviesTests;
+ sourceTree = "";
+ };
+ F4678DCE1A5A82F1005A33DE /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DCF1A5A82F1005A33DE /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ F477D6AA1A5F209D006FD97E /* Controllers */ = {
+ isa = PBXGroup;
+ children = (
+ F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */,
+ F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */,
+ F477D6B11A5F20FF006FD97E /* FilterViewController.swift */,
+ F4646C321A5DF40800336DFC /* SettingsViewController.swift */,
+ F49C6F891A5F47B200D0C49E /* WebViewController.swift */,
+ );
+ name = Controllers;
+ sourceTree = "";
+ };
+ F477D6B31A5F210F006FD97E /* Models */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DE01A5A9582005A33DE /* Movie.swift */,
+ );
+ name = Models;
+ sourceTree = "";
+ };
+ F477D6B71A5F215E006FD97E /* Networking */ = {
+ isa = PBXGroup;
+ children = (
+ F4DC98D11A5E6B460030CC99 /* TMDB.swift */,
+ F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */,
+ );
+ name = Networking;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ F4678DB21A5A82F1005A33DE /* SwiftMovies */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F4678DD41A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMovies" */;
+ buildPhases = (
+ F4678DAF1A5A82F1005A33DE /* Sources */,
+ F4678DB01A5A82F1005A33DE /* Frameworks */,
+ F4678DB11A5A82F1005A33DE /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = SwiftMovies;
+ productName = SwiftMovies;
+ productReference = F4678DB31A5A82F1005A33DE /* SwiftMovies.app */;
+ productType = "com.apple.product-type.application";
+ };
+ F4678DC91A5A82F1005A33DE /* SwiftMoviesTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F4678DD71A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMoviesTests" */;
+ buildPhases = (
+ F4678DC61A5A82F1005A33DE /* Sources */,
+ F4678DC71A5A82F1005A33DE /* Frameworks */,
+ F4678DC81A5A82F1005A33DE /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ F4678DCC1A5A82F1005A33DE /* PBXTargetDependency */,
+ );
+ name = SwiftMoviesTests;
+ productName = SwiftMoviesTests;
+ productReference = F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ F4678DAB1A5A82F1005A33DE /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0610;
+ ORGANIZATIONNAME = "Philly Cocoaheads";
+ TargetAttributes = {
+ F4678DB21A5A82F1005A33DE = {
+ CreatedOnToolsVersion = 6.1.1;
+ };
+ F4678DC91A5A82F1005A33DE = {
+ CreatedOnToolsVersion = 6.1.1;
+ TestTargetID = F4678DB21A5A82F1005A33DE;
+ };
+ };
+ };
+ buildConfigurationList = F4678DAE1A5A82F1005A33DE /* Build configuration list for PBXProject "SwiftMovies" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = F4678DAA1A5A82F1005A33DE;
+ productRefGroup = F4678DB41A5A82F1005A33DE /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ F4678DB21A5A82F1005A33DE /* SwiftMovies */,
+ F4678DC91A5A82F1005A33DE /* SwiftMoviesTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ F4678DB11A5A82F1005A33DE /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4678DC01A5A82F1005A33DE /* Main.storyboard in Resources */,
+ F4678DC51A5A82F1005A33DE /* LaunchScreen.xib in Resources */,
+ F4678DC21A5A82F1005A33DE /* Images.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC81A5A82F1005A33DE /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ F4678DAF1A5A82F1005A33DE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4646C331A5DF40800336DFC /* SettingsViewController.swift in Sources */,
+ F477D6AE1A5F20E2006FD97E /* DetailViewController.swift in Sources */,
+ F49C6F8A1A5F47B200D0C49E /* WebViewController.swift in Sources */,
+ F45D76761A5FD9FE001807F2 /* SwiftyJSON.swift in Sources */,
+ F4DC98D01A5E5B0C0030CC99 /* CollectionViewController.swift in Sources */,
+ F4678DE11A5A9582005A33DE /* Movie.swift in Sources */,
+ F4DC98D21A5E6B460030CC99 /* TMDB.swift in Sources */,
+ F477D6B21A5F20FF006FD97E /* FilterViewController.swift in Sources */,
+ F4678DB91A5A82F1005A33DE /* AppDelegate.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC61A5A82F1005A33DE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4678DD11A5A82F1005A33DE /* SwiftMoviesTests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ F4678DCC1A5A82F1005A33DE /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F4678DB21A5A82F1005A33DE /* SwiftMovies */;
+ targetProxy = F4678DCB1A5A82F1005A33DE /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ F4678DBE1A5A82F1005A33DE /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F4678DBF1A5A82F1005A33DE /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "";
+ };
+ F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F4678DC41A5A82F1005A33DE /* Base */,
+ );
+ name = LaunchScreen.xib;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ F4678DD21A5A82F1005A33DE /* 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.1;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ F4678DD31A5A82F1005A33DE /* 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.1;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ F4678DD51A5A82F1005A33DE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = SwiftMovies/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ F4678DD61A5A82F1005A33DE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = SwiftMovies/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ F4678DD81A5A82F1005A33DE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = SwiftMoviesTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftMovies.app/SwiftMovies";
+ };
+ name = Debug;
+ };
+ F4678DD91A5A82F1005A33DE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = SwiftMoviesTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftMovies.app/SwiftMovies";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ F4678DAE1A5A82F1005A33DE /* Build configuration list for PBXProject "SwiftMovies" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD21A5A82F1005A33DE /* Debug */,
+ F4678DD31A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ F4678DD41A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMovies" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD51A5A82F1005A33DE /* Debug */,
+ F4678DD61A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ F4678DD71A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMoviesTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD81A5A82F1005A33DE /* Debug */,
+ F4678DD91A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = F4678DAB1A5A82F1005A33DE /* Project object */;
+}
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..7890687
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..26cd047
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
new file mode 100644
index 0000000..fe2b454
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -0,0 +1,5 @@
+
+
+
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme
new file mode 100644
index 0000000..ec387aa
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..dd30f16
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,27 @@
+
+
+
+
+ SchemeUserState
+
+ SwiftMovies.xcscheme
+
+ orderHint
+ 0
+
+
+ SuppressBuildableAutocreation
+
+ F4678DB21A5A82F1005A33DE
+
+ primary
+
+
+ F4678DC91A5A82F1005A33DE
+
+ primary
+
+
+
+
+
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/AppDelegate.swift b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/AppDelegate.swift
new file mode 100644
index 0000000..9c2f2cc
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/AppDelegate.swift
@@ -0,0 +1,46 @@
+//
+// AppDelegate.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+@UIApplicationMain
+class AppDelegate: UIResponder, UIApplicationDelegate {
+
+ var window: UIWindow?
+
+
+ func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> 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/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib
new file mode 100644
index 0000000..9e43426
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..d2a2f64
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard
@@ -0,0 +1,612 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/CollectionViewController.swift b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/CollectionViewController.swift
new file mode 100644
index 0000000..2f6474c
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/CollectionViewController.swift
@@ -0,0 +1,114 @@
+//
+// MovieCollectionController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Since we don't have to worry about headers and imports in Swift
+// It sometimes makes sense to keep multiple classes in the same file
+final class MovieCell: UICollectionViewCell {
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var imageView: UIImageView!
+}
+
+final class CollectionViewController: UIViewController {
+ @IBOutlet weak var collectionView: UICollectionView!
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+
+ var movies: [Movie] = []
+ var activeList: TMDB.MovieList = .Popular // We can exclude the enum name and just use .Type
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.navigationItem.title = self.activeList.listName
+ self.refreshMovieResults()
+ }
+
+ func refreshMovieResults() {
+ self.activityIndicator.startAnimating()
+
+ // Swift allows a shorthand if a closure is the last parameter
+ // of a function, as seen here
+ TMDB.fetchMovieList(self.activeList) {
+ self.activityIndicator.stopAnimating()
+
+ // When we use the shorthand we don't have a named result
+ // so we need to reference parameters by position $0, $1, etc.
+ // these are automatic shorthand argument names generated by Swift
+ switch $0 {
+ case .Success(let results):
+ self.movies = results
+ self.collectionView.reloadData()
+ case .Failure:
+ let errorMessage = "There was an issue refreshing movies. Please check your connection or try again later."
+ let alert = UIAlertController(title: "Sorry", message: errorMessage, preferredStyle: UIAlertControllerStyle.Alert)
+ alert.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default, handler: nil))
+ self.presentViewController(alert, animated: true, completion: nil)
+ }
+ }
+ }
+
+ override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
+ if segue.identifier == "showMovieView" {
+ // We use "as" to typecast to a certain object type
+ let movieController = segue.destinationViewController as DetailViewController
+ let indexPath = self.collectionView.indexPathsForSelectedItems().first as NSIndexPath?
+ if let selectedPath = indexPath {
+ // Pass the selected movie to detail view
+ let movie = self.movies[selectedPath.row]
+ movieController.movie = movie
+ }
+ }
+
+ if segue.identifier == "showFilterView" {
+ // We use "as" to typecast to a certain object type
+ let navController = segue.destinationViewController as UINavigationController
+ let filterController = navController.viewControllers.first as FilterViewController
+ // By setting the delegate to this controller we receive updates when the filter changes.
+ filterController.delegate = self
+ }
+ }
+}
+
+// Class extensions make it easy to group functionality, like protocol methods
+extension CollectionViewController: UICollectionViewDelegate, UICollectionViewDataSource {
+ func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+ return self.movies.count
+ }
+
+ func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
+ let movieCell = collectionView.dequeueReusableCellWithReuseIdentifier("movieCell", forIndexPath: indexPath) as MovieCell
+ let movie = self.movies[indexPath.row]
+
+ // Set poster to nil while loading
+ movieCell.imageView.image = nil
+ movieCell.activityIndicator.startAnimating()
+
+ movie.loadPosterImage() {
+ switch $0 {
+ case .Success(let posterImage):
+ movieCell.imageView.image = posterImage
+ case .Failure:
+ movieCell.imageView.image = UIImage(named: "noPoster")
+ }
+
+ movieCell.activityIndicator.stopAnimating()
+ }
+
+ return movieCell
+ }
+}
+
+extension CollectionViewController: FilterViewDelegate {
+ func filterDidChange(list: TMDB.MovieList) {
+ self.activeList = list
+ self.navigationItem.title = list.listName
+ // We want the collectionview to scroll back to the top instantly on list change
+ self.collectionView.setContentOffset(CGPoint(x: 0, y:-self.collectionView.contentInset.top), animated: false)
+ self.refreshMovieResults()
+ }
+}
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/DetailViewController.swift b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/DetailViewController.swift
new file mode 100644
index 0000000..43954dc
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/DetailViewController.swift
@@ -0,0 +1,150 @@
+//
+// MovieViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class DetailViewController: UIViewController {
+ @IBOutlet weak var backdropImageView: UIImageView!
+ @IBOutlet weak var backdropActivityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var titleLabel: UILabel!
+ @IBOutlet weak var ratingLabel: UILabel!
+ @IBOutlet weak var summaryLabel: UILabel!
+ @IBOutlet weak var releaseDateLabel: UILabel!
+ @IBOutlet weak var genresLabel: UILabel!
+ @IBOutlet weak var runtimeLabel: UILabel!
+
+ var movie: Movie?
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.loadMovieInfo()
+ }
+
+ private func loadMovieInfo() {
+ // Setup our empty state (how the screen should look while loading)
+ self.backdropImageView.image = nil
+ self.titleLabel.text = ""
+ self.navigationItem.title = ""
+ self.ratingLabel.text = ""
+ self.summaryLabel.text = ""
+ self.releaseDateLabel.text = ""
+ self.genresLabel.text = ""
+ self.runtimeLabel.text = ""
+
+ if let movie = self.movie {
+ // Since title is not an optional, we know we will always
+ // have one as long as the movie exists
+ self.titleLabel.text = movie.title
+ self.navigationItem.title = movie.title
+
+ // Swift allows a shorthand if a closure is the last parameter
+ // of a function, as seen here
+ TMDB.fetchMovie(movie.tmdbId) {
+ // When we use the shorthand we don't have a named result
+ // so we need to reference parameters by position $0, $1, etc.
+ // these are automatic shorthand argument names generated by Swift
+ switch $0 {
+ case .Success(let movie):
+ self.movie = movie
+ case .Failure:
+ self.displayNetworkError()
+ }
+
+ // We always want to update the inferface, because the function is designed
+ // to handle missing values appropriately
+ self.updateInterface()
+ }
+ } else {
+ // If we don't have a movie to load skip fetching, display error message
+ self.displayNetworkError()
+ self.updateInterface()
+ }
+ }
+
+ private func updateInterface() {
+ let na = "Not Available"
+
+ // We can use optional chaining and the Nil Coalescing operater to avoid a long list of if/let/else statements
+ self.titleLabel.text = self.movie?.title ?? na
+ self.ratingLabel.text = self.ratingString(self.movie?.rating) ?? "N/A"
+ self.summaryLabel.text = self.movie?.summary ?? "No Synopsis Available."
+ self.releaseDateLabel.text = self.movie?.releaseDate ?? na
+ self.genresLabel.text = self.genresString(self.movie?.genres) ?? na
+ self.runtimeLabel.text = self.minutesString(self.movie?.runtime) ?? na
+
+ self.loadBackdropImage()
+ }
+
+ // Since we use it in multiple locations, it makes sense to seperate our error display into a function
+ private func displayNetworkError() {
+ let errorMessage = "We were unable to fetch movie information. Please check your connection or try again later."
+ let alert = UIAlertController(title: "Sorry", message: errorMessage, preferredStyle: UIAlertControllerStyle.Alert)
+ alert.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default, handler: nil))
+ self.presentViewController(alert, animated: true, completion: nil)
+ }
+
+ private func loadBackdropImage() {
+ let emptyImage = UIImage(named: "noBackdrop")
+
+ if let movie = self.movie {
+ self.backdropActivityIndicator.startAnimating()
+
+ movie.loadBackdropImage() {
+ switch $0 {
+ case .Success(let backdropImage):
+ self.backdropImageView.image = backdropImage
+ case .Failure:
+ self.backdropImageView.image = emptyImage
+ }
+
+ self.backdropActivityIndicator.stopAnimating()
+ }
+ } else {
+ // Being extra safe
+ self.backdropImageView.image = emptyImage
+ }
+ }
+
+ // When we see isolated chunks of code cluttering a function
+ // it often makes sense to seperate it into its own function
+ private func genresString(genres: [String]?) -> String? {
+ if let genresArray = genres {
+ var genreString = ""
+
+ for (index, genre) in enumerate(genresArray) {
+ genreString += genre
+
+ // index starts at 0 so we need count - 1
+ if index != genresArray.count - 1 {
+ genreString += ", "
+ }
+ }
+
+ return genreString
+ }
+
+ return nil
+ }
+
+ private func minutesString(minutes: Int?) -> String? {
+ if let m = minutes {
+ return "\(m) minutes"
+ }
+
+ return nil
+ }
+
+ private func ratingString(rating: Rating?) -> String? {
+ if let r = rating {
+ return "\(r.averageRating) (\(r.voteCount))"
+ }
+
+ return nil
+ }
+}
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/FilterViewController.swift b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/FilterViewController.swift
new file mode 100644
index 0000000..ee189c2
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/FilterViewController.swift
@@ -0,0 +1,64 @@
+//
+// FiltersViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// ? is shorthand for unwrapping an optional then performing a method on the result
+// If the result is nil, everything after the ? is ignored
+// Its called Optional chaining and its used throughout this class
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class FilterViewController: UIViewController {
+ // You can use protocols and delegates together to communicate between objects
+ // This will enable us to tell our Collection controller when the filter has changed
+ var delegate: FilterViewDelegate?
+
+ @IBAction func cancel(sender: AnyObject) {
+ self.dismiss()
+ }
+
+ func dismiss() {
+ self.navigationController?.dismissViewControllerAnimated(true, completion: nil)
+ }
+}
+
+// Class extensions make it easy to group functionality, like protocol methods
+extension FilterViewController: UITableViewDelegate, UITableViewDataSource {
+ func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return TMDB.MovieList.allLists.count
+ }
+
+ func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
+ let cell = tableView.dequeueReusableCellWithIdentifier("filterCell") as UITableViewCell
+ let movieList: TMDB.MovieList = TMDB.MovieList.allLists[indexPath.row]
+
+ cell.textLabel?.text = movieList.listName
+
+ if movieList == delegate?.activeList {
+ cell.accessoryType = UITableViewCellAccessoryType.Checkmark
+ } else {
+ cell.accessoryType = UITableViewCellAccessoryType.None
+ }
+
+ return cell
+ }
+
+ func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
+ tableView.deselectRowAtIndexPath(indexPath, animated: false) // Fix sticky cells
+ let movieList: TMDB.MovieList = TMDB.MovieList.allLists[indexPath.row]
+ self.delegate?.filterDidChange(movieList)
+ self.dismiss()
+ }
+}
+
+// Protocols allow us to force an object to adopt certain
+// properties and methods (by adopting the protocol)
+protocol FilterViewDelegate {
+ var activeList: TMDB.MovieList { get }
+ func filterDidChange(list: TMDB.MovieList)
+}
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store
new file mode 100644
index 0000000..c068369
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..7997783
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,44 @@
+{
+ "images" : [
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-29@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-40@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-60@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-60@3x.png",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png
new file mode 100644
index 0000000..d463ba9
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png
new file mode 100644
index 0000000..e421cfa
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png
new file mode 100644
index 0000000..2be6555
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png
new file mode 100644
index 0000000..efa69d2
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png
new file mode 100644
index 0000000..efa69d2
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png
new file mode 100644
index 0000000..e405742
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..0f84226
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "bt6DhdALyhf90gReozoQ0y3R3vZ.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg
new file mode 100644
index 0000000..1e19bbb
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..5d9e965
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..3124e77
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "umR9aXTxOxQUuDH2DamoJ5fIPB.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg
new file mode 100644
index 0000000..f4c469c
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..ed3e63e
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "eDildzNrm4XJABWkNKtqB29t6mv.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg
new file mode 100644
index 0000000..90ede16
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..8d49e39
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png
new file mode 100644
index 0000000..68aa392
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png
new file mode 100644
index 0000000..bb5d8b4
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png
new file mode 100644
index 0000000..12923f2
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json
new file mode 100644
index 0000000..4e659b8
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "settings.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "settings@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "settings@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png
new file mode 100644
index 0000000..e2d21f0
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png
new file mode 100644
index 0000000..6fd890d
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png
new file mode 100644
index 0000000..d68af6b
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json
new file mode 100644
index 0000000..50564ce
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "star.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "star@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "star@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png
new file mode 100644
index 0000000..2b2b41b
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png
new file mode 100644
index 0000000..f1367c8
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png
new file mode 100644
index 0000000..390ad8e
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json
new file mode 100644
index 0000000..04ea068
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "tag.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "tag@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "tag@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png
new file mode 100644
index 0000000..d46a1af
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png
new file mode 100644
index 0000000..5d176aa
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png
new file mode 100644
index 0000000..bee24d8
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json
new file mode 100644
index 0000000..16f2d86
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json
new file mode 100644
index 0000000..2febbf6
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json
new file mode 100644
index 0000000..37c7f9d
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json
new file mode 100644
index 0000000..8e8af21
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "interview.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "interview-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "interview-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json
new file mode 100644
index 0000000..4b2222a
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "Placeholder.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "Placeholder@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "Placeholder@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png
new file mode 100644
index 0000000..4f45f19
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png
new file mode 100644
index 0000000..e21d629
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png
new file mode 100644
index 0000000..6d89554
Binary files /dev/null and b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png differ
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Info.plist b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Info.plist
new file mode 100644
index 0000000..aab298d
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Info.plist
@@ -0,0 +1,52 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleDisplayName
+ Swift Movies
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ phillycocoa.$(PRODUCT_NAME:rfc1034identifier)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UIStatusBarTintParameters
+
+ UINavigationBar
+
+ Style
+ UIBarStyleDefault
+ Translucent
+
+
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+
+
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Movie.swift b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Movie.swift
new file mode 100644
index 0000000..d5d55b6
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/Movie.swift
@@ -0,0 +1,110 @@
+//
+// Movie.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+final class Movie {
+ // The pattern we've adopted lets us use constants throughout
+ // and optionals only for properties that are truly optional
+ let tmdbId: Int
+ let title: String
+ let summary: String?
+ let rating: Rating?
+ let releaseDate: String?
+ let genres: [String]?
+ let runtime: Int?
+ let posterPath: String?
+ let backdropPath: String?
+
+ // We could use an init with JSON function or similar here
+ // but doing it this way insulates our Movie class from our API service
+ // We could now just as easily add a RottenTomatoes initializer for example
+ init(TMDBResponse: TMDB.MovieResponse) {
+ self.tmdbId = TMDBResponse.tmdbId
+ self.title = TMDBResponse.title
+ self.summary = TMDBResponse.overview
+
+ // We only consider a rating valid if we have both the average and the vote count
+ if let averageRating = TMDBResponse.averageRating {
+ if let voteCount = TMDBResponse.voteCount {
+ self.rating = Rating(averageRating: averageRating, voteCount: voteCount)
+ }
+ }
+
+ self.releaseDate = TMDBResponse.releaseDate
+ self.genres = TMDBResponse.genres
+ self.runtime = TMDBResponse.runtime
+ self.posterPath = TMDBResponse.posterPath
+ self.backdropPath = TMDBResponse.backdropPath
+ }
+
+ // A Type Alias is just like it sounds - its a shorthand name for a specific type
+ // It comes in handy for blocks where the syntax is a bit unruly, especially
+ // when the block is a function parameter
+ typealias ImageCompletion = (result: Result) -> Void
+
+ func loadPosterImage(completion: ImageCompletion) {
+ if let posterPath = self.posterPath {
+ // For the sake of this workshop we are passing a hardcoded image size parameter
+ // In reality we would want to query the TMDB config endpoint to fetch all of the sizes
+ // and have them in a strongly typed form - like an enum
+ self.loadImage("w500", path: posterPath, completion: completion)
+ // returns can be handy for avoiding a lot of nesting and if/else statements
+ return
+ }
+
+ completion(result: Result.Failure)
+ }
+
+ func loadBackdropImage(completion: ImageCompletion) {
+ if let backdropPath = self.backdropPath {
+ self.loadImage("w780", path: backdropPath, completion: completion)
+ return
+ }
+
+ completion(result: Result.Failure)
+ }
+
+ // Since we have two different images we have to fetch, it makes sense to keep some
+ // shared logic in a seperate function to keep things DRY
+ // Note that we make it a private function so there is no risk of it being called outside its own instance
+ private func loadImage(size: String, path: String, completion: ImageCompletion) {
+ let url = NSURL(string: "\(TMDB_IMAGE_BASE_URL)/\(size)/\(path)")
+ // Another option:
+ // let url = NSURL(string: TMDB_IMAGE_BASE_URL + "/" + size + "/" + path")
+ if url == nil {
+ completion(result: Result.Failure)
+ return
+ }
+
+ // This method when passed the Main Queue will execute the completion closure on the Main Thread
+ // Otherwise we would want to get the Main Thread before executing our completion closure
+ // As we are going to be doing our interfaced updates in the completion
+ NSURLConnection.sendAsynchronousRequest(NSURLRequest(URL: url!), queue: NSOperationQueue.mainQueue()) {
+ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
+
+ if data != nil {
+ if let image = UIImage(data: data) {
+ completion(result: Result.Success(image))
+ return
+ }
+ }
+
+ // If we make it here something went wrong
+ completion(result: Result.Failure)
+ }
+ }
+}
+
+// A struct is similar to a class except that it cannot inherit
+// and it is a value type (as opposed to a reference type)
+// They are often used for objects that just hold data
+struct Rating {
+ var averageRating: Double
+ var voteCount: Int
+}
\ No newline at end of file
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/SettingsViewController.swift b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/SettingsViewController.swift
new file mode 100644
index 0000000..5eb50ef
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/SettingsViewController.swift
@@ -0,0 +1,59 @@
+//
+// SettingsController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/7/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class SettingsViewController: UITableViewController {
+ // Private properties are only available to the instance of the object (can't be called from another object)
+ // Its good practice for things you know will only be used internally
+ private let webViewSegue = "showWebView"
+ private var webViewProperties: (title: String?, urlString: String?)
+
+ override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
+ let path = (indexPath.section, indexPath.row)
+
+ // We can use tuples and a switch to cover our row actions without a big if/else mess
+ // We are also using a tuple to capture the title and url in one variable
+ switch path {
+ case (0, 0):
+ self.webViewProperties = ("@themoviedb", "http://twitter.com/themoviedb")
+ case (0, 1):
+ self.webViewProperties = ("The Movie DB", "http://facebook.com/themoviedb")
+ case (1, 0):
+ self.webViewProperties = ("Terms of Service", "http://themoviedb.org/documentation/website/terms-of-use")
+ case (1, 1):
+ self.webViewProperties = ("Privacy Policy", "http://themoviedb.org/privacy-policy")
+ default:
+ // This should never happen, but lets get in the mindset of handling issues gracefully
+ // Swift will actually give an error if we don't have this default case (must be exhaustive)
+ // We can demonstrate this by commenting out one of our cell handlers then tapping that cell
+ let alertTitle = "Sorry!"
+ let alertMessage = "An unknown error occurred."
+ let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: UIAlertControllerStyle.Alert)
+ alert.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default, handler: nil))
+ self.presentViewController(alert, animated: true, completion: nil)
+ self.tableView.deselectRowAtIndexPath(indexPath, animated: false) // Deselect the cell so it does not "stick"
+
+ // Return so we don't perform the segue
+ return
+ }
+
+ // Since all the various rows are going to the same view controller, we can trigger the
+ // segue manually instead of having to create 4 segues pointing to the same controller
+ self.performSegueWithIdentifier(webViewSegue, sender: self)
+ }
+
+ override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
+ if segue.identifier == webViewSegue {
+ let webViewController = segue.destinationViewController as WebViewController
+ webViewController.titleString = self.webViewProperties.title
+ webViewController.urlString = self.webViewProperties.urlString
+ }
+ }
+}
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift
new file mode 100644
index 0000000..f26c7e7
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift
@@ -0,0 +1,1335 @@
+// SwiftyJSON.swift
+//
+// Copyright (c) 2014 Ruoyu Fu, Pinglin Tang
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+// MARK: - Error
+
+///Error domain
+public let ErrorDomain: String! = "SwiftyJSONErrorDomain"
+
+///Error code
+public let ErrorUnsupportedType: Int! = 999
+public let ErrorIndexOutOfBounds: Int! = 900
+public let ErrorWrongType: Int! = 901
+public let ErrorNotExist: Int! = 500
+
+// MARK: - JSON Type
+
+/**
+JSON's type definitions.
+
+See http://tools.ietf.org/html/rfc7231#section-4.3
+*/
+public enum Type :Int{
+
+ case Number
+ case String
+ case Bool
+ case Array
+ case Dictionary
+ case Null
+ case Unknown
+}
+
+// MARK: - JSON Base
+
+public struct JSON {
+
+ /**
+ Creates a JSON using the data.
+
+ :param: data The NSData used to convert to json.Top level object in data is an NSArray or NSDictionary
+ :param: opt The JSON serialization reading options. `.AllowFragments` by default.
+ :param: error error The NSErrorPointer used to return the error. `nil` by default.
+
+ :returns: The created JSON
+ */
+ public init(data:NSData, options opt: NSJSONReadingOptions = .AllowFragments, error: NSErrorPointer = nil) {
+ if let object: AnyObject = NSJSONSerialization.JSONObjectWithData(data, options: opt, error: error) {
+ self.init(object)
+ } else {
+ self.init(NSNull())
+ }
+ }
+
+ /**
+ Creates a JSON using the object.
+
+ :param: object The object must have the following properties: All objects are NSString/String, NSNumber/Int/Float/Double/Bool, NSArray/Array, NSDictionary/Dictionary, or NSNull; All dictionary keys are NSStrings/String; NSNumbers are not NaN or infinity.
+
+ :returns: The created JSON
+ */
+ public init(_ object: AnyObject) {
+ self.object = object
+ }
+
+ /// Private object
+ private var _object: AnyObject = NSNull()
+ /// Private type
+ private var _type: Type = .Null
+ /// prviate error
+ private var _error: NSError?
+
+ /// Object in JSON
+ public var object: AnyObject {
+ get {
+ return _object
+ }
+ set {
+ _object = newValue
+ switch newValue {
+ case let number as NSNumber:
+ if number.isBool {
+ _type = .Bool
+ } else {
+ _type = .Number
+ }
+ case let string as NSString:
+ _type = .String
+ case let null as NSNull:
+ _type = .Null
+ case let array as [AnyObject]:
+ _type = .Array
+ case let dictionary as [String : AnyObject]:
+ _type = .Dictionary
+ default:
+ _type = .Unknown
+ _object = NSNull()
+ _error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"])
+ }
+ }
+ }
+
+ /// json type
+ public var type: Type { get { return _type } }
+
+ /// Error in JSON
+ public var error: NSError? { get { return self._error } }
+
+ /// The static null json
+ public static var nullJSON: JSON { get { return JSON(NSNull()) } }
+
+}
+
+// MARK: - SequenceType
+extension JSON: SequenceType{
+
+ /// If `type` is `.Array` or `.Dictionary`, return `array.empty` or `dictonary.empty` otherwise return `false`.
+ public var isEmpty: Bool {
+ get {
+ switch self.type {
+ case .Array:
+ return (self.object as [AnyObject]).isEmpty
+ case .Dictionary:
+ return (self.object as [String : AnyObject]).isEmpty
+ default:
+ return false
+ }
+ }
+ }
+
+ /// If `type` is `.Array` or `.Dictionary`, return `array.count` or `dictonary.count` otherwise return `0`.
+ public var count: Int {
+ get {
+ switch self.type {
+ case .Array:
+ return self.arrayValue.count
+ case .Dictionary:
+ return self.dictionaryValue.count
+ default:
+ return 0
+ }
+ }
+ }
+
+ /**
+ If `type` is `.Array` or `.Dictionary`, return a generator over the elements like `Array` or `Dictionary, otherwise return a generator over empty.
+
+ :returns: Return a *generator* over the elements of this *sequence*.
+ */
+ public func generate() -> GeneratorOf <(String, JSON)> {
+ switch self.type {
+ case .Array:
+ let array_ = object as [AnyObject]
+ var generate_ = array_.generate()
+ var index_: Int = 0
+ return GeneratorOf<(String, JSON)> {
+ if let element_: AnyObject = generate_.next() {
+ return ("\(index_++)", JSON(element_))
+ } else {
+ return nil
+ }
+ }
+ case .Dictionary:
+ let dictionary_ = object as [String : AnyObject]
+ var generate_ = dictionary_.generate()
+ return GeneratorOf<(String, JSON)> {
+ if let (key_: String, value_: AnyObject) = generate_.next() {
+ return (key_, JSON(value_))
+ } else {
+ return nil
+ }
+ }
+ default:
+ return GeneratorOf<(String, JSON)> {
+ return nil
+ }
+ }
+ }
+}
+
+// MARK: - Subscript
+
+/**
+* To mark both String and Int can be used in subscript.
+*/
+public protocol SubscriptType {}
+
+extension Int: SubscriptType {}
+
+extension String: SubscriptType {}
+
+extension JSON {
+
+ /// If `type` is `.Array`, return json which's object is `array[index]`, otherwise return null json with error.
+ private subscript(#index: Int) -> JSON {
+ get {
+
+ if self.type != .Array {
+ var errorResult_ = JSON.nullJSON
+ errorResult_._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] failure, It is not an array"])
+ return errorResult_
+ }
+
+ let array_ = self.object as [AnyObject]
+
+ if index >= 0 && index < array_.count {
+ return JSON(array_[index])
+ }
+
+ var errorResult_ = JSON.nullJSON
+ errorResult_._error = NSError(domain: ErrorDomain, code:ErrorIndexOutOfBounds , userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] is out of bounds"])
+ return errorResult_
+ }
+ set {
+ if self.type == .Array {
+ var array_ = self.object as [AnyObject]
+ if array_.count > index {
+ array_[index] = newValue.object
+ self.object = array_
+ }
+ }
+ }
+ }
+
+ /// If `type` is `.Dictionary`, return json which's object is `dictionary[key]` , otherwise return null json with error.
+ private subscript(#key: String) -> JSON {
+ get {
+ var returnJSON = JSON.nullJSON
+ if self.type == .Dictionary {
+ if let object_: AnyObject = self.object[key] {
+ returnJSON = JSON(object_)
+ } else {
+ returnJSON._error = NSError(domain: ErrorDomain, code: ErrorNotExist, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] does not exist"])
+ }
+ } else {
+ returnJSON._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] failure, It is not an dictionary"])
+ }
+ return returnJSON
+ }
+ set {
+ if self.type == .Dictionary {
+ var dictionary_ = self.object as [String : AnyObject]
+ dictionary_[key] = newValue.object
+ self.object = dictionary_
+ }
+ }
+ }
+
+ /// If `sub` is `Int`, return `subscript(index:)`; If `sub` is `String`, return `subscript(key:)`.
+ private subscript(#sub: SubscriptType) -> JSON {
+ get {
+ if sub is String {
+ return self[key:sub as String]
+ } else {
+ return self[index:sub as Int]
+ }
+ }
+ set {
+ if sub is String {
+ self[key:sub as String] = newValue
+ } else {
+ self[index:sub as Int] = newValue
+ }
+ }
+ }
+
+ /**
+ Find a json in the complex data structuresby using the Int/String's array.
+
+ :param: path The target json's path. Example:
+
+ let json = JSON[data]
+ let path = [9,"list","person","name"]
+ let name = json[path]
+
+ The same as: let name = json[9]["list"]["person"]["name"]
+
+ :returns: Return a json found by the path or a null json with error
+ */
+ public subscript(path: [SubscriptType]) -> JSON {
+ get {
+ if path.count == 0 {
+ return JSON.nullJSON
+ }
+
+ var next = self
+ for sub in path {
+ next = next[sub:sub]
+ }
+ return next
+ }
+ set {
+
+ switch path.count {
+ case 0: return
+ case 1: self[sub:path[0]] = newValue
+ default:
+ var last = newValue
+ var newPath = path
+ newPath.removeLast()
+ for sub in path.reverse() {
+ var previousLast = self[newPath]
+ previousLast[sub:sub] = last
+ last = previousLast
+ if newPath.count <= 1 {
+ break
+ }
+ newPath.removeLast()
+ }
+ self[sub:newPath[0]] = last
+ }
+ }
+ }
+
+ /**
+ Find a json in the complex data structuresby using the Int/String's array.
+
+ :param: path The target json's path. Example:
+
+ let name = json[9,"list","person","name"]
+
+ The same as: let name = json[9]["list"]["person"]["name"]
+
+ :returns: Return a json found by the path or a null json with error
+ */
+ public subscript(path: SubscriptType...) -> JSON {
+ get {
+ return self[path]
+ }
+ set {
+ self[path] = newValue
+ }
+ }
+}
+
+// MARK: - LiteralConvertible
+
+extension JSON: StringLiteralConvertible {
+
+ public init(stringLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+
+ public init(extendedGraphemeClusterLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+
+ public init(unicodeScalarLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: IntegerLiteralConvertible {
+
+ public init(integerLiteral value: IntegerLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: BooleanLiteralConvertible {
+
+ public init(booleanLiteral value: BooleanLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: FloatLiteralConvertible {
+
+ public init(floatLiteral value: FloatLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: DictionaryLiteralConvertible {
+
+ public init(dictionaryLiteral elements: (String, AnyObject)...) {
+ var dictionary_ = [String : AnyObject]()
+ for (key_, value) in elements {
+ dictionary_[key_] = value
+ }
+ self.init(dictionary_)
+ }
+}
+
+extension JSON: ArrayLiteralConvertible {
+
+ public init(arrayLiteral elements: AnyObject...) {
+ self.init(elements)
+ }
+}
+
+extension JSON: NilLiteralConvertible {
+
+ public init(nilLiteral: ()) {
+ self.init(NSNull())
+ }
+}
+
+// MARK: - Raw
+
+extension JSON: RawRepresentable {
+
+ public init?(rawValue: AnyObject) {
+ if JSON(rawValue).type == .Unknown {
+ return nil
+ } else {
+ self.init(rawValue)
+ }
+ }
+
+ public var rawValue: AnyObject {
+ return self.object
+ }
+
+ public func rawData(options opt: NSJSONWritingOptions = NSJSONWritingOptions(0), error: NSErrorPointer = nil) -> NSData? {
+ return NSJSONSerialization.dataWithJSONObject(self.object, options: opt, error:error)
+ }
+
+ public func rawString(encoding: UInt = NSUTF8StringEncoding, options opt: NSJSONWritingOptions = .PrettyPrinted) -> String? {
+ switch self.type {
+ case .Array, .Dictionary:
+ if let data = self.rawData(options: opt) {
+ return NSString(data: data, encoding: encoding)
+ } else {
+ return nil
+ }
+ case .String:
+ return (self.object as String)
+ case .Number:
+ return (self.object as NSNumber).stringValue
+ case .Bool:
+ return (self.object as Bool).description
+ case .Null:
+ return "null"
+ default:
+ return nil
+ }
+ }
+}
+
+// MARK: - Printable, DebugPrintable
+
+extension JSON: Printable, DebugPrintable {
+
+ public var description: String {
+ if let string = self.rawString(options:.PrettyPrinted) {
+ return string
+ } else {
+ return "unknown"
+ }
+ }
+
+ public var debugDescription: String {
+ return description
+ }
+}
+
+// MARK: - Array
+
+extension JSON {
+
+ //Optional [JSON]
+ public var array: [JSON]? {
+ get {
+ if self.type == .Array {
+ return map(self.object as [AnyObject]){ JSON($0) }
+ } else {
+ return nil
+ }
+ }
+ }
+
+ //Non-optional [JSON]
+ public var arrayValue: [JSON] {
+ get {
+ return self.array ?? []
+ }
+ }
+
+ //Optional [AnyObject]
+ public var arrayObject: [AnyObject]? {
+ get {
+ switch self.type {
+ case .Array:
+ return self.object as? [AnyObject]
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSMutableArray(array: newValue!, copyItems: true)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+}
+
+// MARK: - Dictionary
+
+extension JSON {
+
+ private func _map(source: [Key: Value], transform: Value -> NewValue) -> [Key: NewValue] {
+ var result = [Key: NewValue](minimumCapacity:source.count)
+ for (key,value) in source {
+ result[key] = transform(value)
+ }
+ return result
+ }
+
+ //Optional [String : JSON]
+ public var dictionary: [String : JSON]? {
+ get {
+ if self.type == .Dictionary {
+ return _map(self.object as [String : AnyObject]){ JSON($0) }
+ } else {
+ return nil
+ }
+ }
+ }
+
+ //Non-optional [String : JSON]
+ public var dictionaryValue: [String : JSON] {
+ get {
+ return self.dictionary ?? [:]
+ }
+ }
+
+ //Optional [String : AnyObject]
+ public var dictionaryObject: [String : AnyObject]? {
+ get {
+ switch self.type {
+ case .Dictionary:
+ return self.object as? [String : AnyObject]
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSMutableDictionary(dictionary: newValue!, copyItems: true)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+}
+
+// MARK: - Bool
+
+extension JSON: BooleanType {
+
+ //Optional bool
+ public var bool: Bool? {
+ get {
+ switch self.type {
+ case .Bool:
+ return self.object.boolValue
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(bool: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ //Non-optional bool
+ public var boolValue: Bool {
+ get {
+ switch self.type {
+ case .Bool, .Number, .String:
+ return self.object.boolValue
+ default:
+ return false
+ }
+ }
+ set {
+ self.object = NSNumber(bool: newValue)
+ }
+ }
+}
+
+// MARK: - String
+
+extension JSON {
+
+ //Optional string
+ public var string: String? {
+ get {
+ switch self.type {
+ case .String:
+ return self.object as? String
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSString(string:newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ //Non-optional string
+ public var stringValue: String {
+ get {
+ switch self.type {
+ case .String:
+ return self.object as String
+ case .Number:
+ return self.object.stringValue
+ case .Bool:
+ return (self.object as Bool).description
+ default:
+ return ""
+ }
+ }
+ set {
+ self.object = NSString(string:newValue)
+ }
+ }
+}
+
+// MARK: - Number
+extension JSON {
+
+ //Optional number
+ public var number: NSNumber? {
+ get {
+ switch self.type {
+ case .Number, .Bool:
+ return self.object as? NSNumber
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = newValue?.copy() ?? NSNull()
+ }
+ }
+
+ //Non-optional number
+ public var numberValue: NSNumber {
+ get {
+ switch self.type {
+ case .String:
+ let scanner = NSScanner(string: self.object as String)
+ if scanner.scanDouble(nil){
+ if (scanner.atEnd) {
+ return NSNumber(double:(self.object as NSString).doubleValue)
+ }
+ }
+ return NSNumber(double: 0.0)
+ case .Number, .Bool:
+ return self.object as NSNumber
+ default:
+ return NSNumber(double: 0.0)
+ }
+ }
+ set {
+ self.object = newValue.copy()
+ }
+ }
+}
+
+//MARK: - Null
+extension JSON {
+
+ public var null: NSNull? {
+ get {
+ switch self.type {
+ case .Null:
+ return NSNull()
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = NSNull()
+ }
+ }
+}
+
+//MARK: - URL
+extension JSON {
+
+ //Optional URL
+ public var URL: NSURL? {
+ get {
+ switch self.type {
+ case .String:
+ if let encodedString_ = self.object.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
+ return NSURL(string: encodedString_)
+ } else {
+ return nil
+ }
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = newValue?.absoluteString ?? NSNull()
+ }
+ }
+}
+
+// MARK: - Int, Double, Float, Int8, Int16, Int32, Int64
+
+extension JSON {
+
+ public var double: Double? {
+ get {
+ return self.number?.doubleValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(double: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var doubleValue: Double {
+ get {
+ return self.numberValue.doubleValue
+ }
+ set {
+ self.object = NSNumber(double: newValue)
+ }
+ }
+
+ public var float: Float? {
+ get {
+ return self.number?.floatValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(float: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var floatValue: Float {
+ get {
+ return self.numberValue.floatValue
+ }
+ set {
+ self.object = NSNumber(float: newValue)
+ }
+ }
+
+ public var int: Int? {
+ get {
+ return self.number?.longValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(integer: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var intValue: Int {
+ get {
+ return self.numberValue.integerValue
+ }
+ set {
+ self.object = NSNumber(integer: newValue)
+ }
+ }
+
+ public var uInt: UInt? {
+ get {
+ return self.number?.unsignedLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uIntValue: UInt {
+ get {
+ return self.numberValue.unsignedLongValue
+ }
+ set {
+ self.object = NSNumber(unsignedLong: newValue)
+ }
+ }
+
+ public var int8: Int8? {
+ get {
+ return self.number?.charValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(char: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int8Value: Int8 {
+ get {
+ return self.numberValue.charValue
+ }
+ set {
+ self.object = NSNumber(char: newValue)
+ }
+ }
+
+ public var uInt8: UInt8? {
+ get {
+ return self.number?.unsignedCharValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedChar: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt8Value: UInt8 {
+ get {
+ return self.numberValue.unsignedCharValue
+ }
+ set {
+ self.object = NSNumber(unsignedChar: newValue)
+ }
+ }
+
+ public var int16: Int16? {
+ get {
+ return self.number?.shortValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(short: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int16Value: Int16 {
+ get {
+ return self.numberValue.shortValue
+ }
+ set {
+ self.object = NSNumber(short: newValue)
+ }
+ }
+
+ public var uInt16: UInt16? {
+ get {
+ return self.number?.unsignedShortValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedShort: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt16Value: UInt16 {
+ get {
+ return self.numberValue.unsignedShortValue
+ }
+ set {
+ self.object = NSNumber(unsignedShort: newValue)
+ }
+ }
+
+ public var int32: Int32? {
+ get {
+ return self.number?.intValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(int: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int32Value: Int32 {
+ get {
+ return self.numberValue.intValue
+ }
+ set {
+ self.object = NSNumber(int: newValue)
+ }
+ }
+
+ public var uInt32: UInt32? {
+ get {
+ return self.number?.unsignedIntValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedInt: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt32Value: UInt32 {
+ get {
+ return self.numberValue.unsignedIntValue
+ }
+ set {
+ self.object = NSNumber(unsignedInt: newValue)
+ }
+ }
+
+ public var int64: Int64? {
+ get {
+ return self.number?.longLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(longLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int64Value: Int64 {
+ get {
+ return self.numberValue.longLongValue
+ }
+ set {
+ self.object = NSNumber(longLong: newValue)
+ }
+ }
+
+ public var uInt64: UInt64? {
+ get {
+ return self.number?.unsignedLongLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedLongLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt64Value: UInt64 {
+ get {
+ return self.numberValue.unsignedLongLongValue
+ }
+ set {
+ self.object = NSNumber(unsignedLongLong: newValue)
+ }
+ }
+}
+
+//MARK: - Comparable
+extension JSON: Comparable {}
+
+public func ==(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) == (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) == (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func <=(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) <= (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) <= (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func >=(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) >= (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) >= (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func >(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) > (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) > (rhs.object as String)
+ default:
+ return false
+ }
+}
+
+public func <(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) < (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) < (rhs.object as String)
+ default:
+ return false
+ }
+}
+
+private let trueNumber = NSNumber(bool: true)
+private let falseNumber = NSNumber(bool: false)
+private let trueObjCType = String.fromCString(trueNumber.objCType)
+private let falseObjCType = String.fromCString(falseNumber.objCType)
+
+// MARK: - NSNumber: Comparable
+
+extension NSNumber: Comparable {
+ var isBool:Bool {
+ get {
+ let objCType = String.fromCString(self.objCType)
+ if (self.compare(trueNumber) == NSComparisonResult.OrderedSame && objCType == trueObjCType) || (self.compare(falseNumber) == NSComparisonResult.OrderedSame && objCType == falseObjCType){
+ return true
+ } else {
+ return false
+ }
+ }
+ }
+}
+
+public func ==(lhs: NSNumber, rhs: NSNumber) -> Bool {
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedSame
+ }
+}
+
+public func !=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+ return !(lhs == rhs)
+}
+
+public func <(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedAscending
+ }
+}
+
+public func >(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedDescending
+ }
+}
+
+public func <=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) != NSComparisonResult.OrderedDescending
+ }
+}
+
+public func >=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) != NSComparisonResult.OrderedAscending
+ }
+}
+
+//MARK:- Unavailable
+
+@availability(*, unavailable, renamed="JSON")
+public typealias JSONValue = JSON
+
+extension JSON {
+
+ @availability(*, unavailable, message="use 'init(_ object:AnyObject)' instead")
+ public init(object: AnyObject) {
+ self = JSON(object)
+ }
+
+ @availability(*, unavailable, renamed="dictionaryObject")
+ public var dictionaryObjects: [String : AnyObject]? {
+ get { return self.dictionaryObject }
+ }
+
+ @availability(*, unavailable, renamed="arrayObject")
+ public var arrayObjects: [AnyObject]? {
+ get { return self.arrayObject }
+ }
+
+ @availability(*, unavailable, renamed="int8")
+ public var char: Int8? {
+ get {
+ return self.number?.charValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int8Value")
+ public var charValue: Int8 {
+ get {
+ return self.numberValue.charValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt8")
+ public var unsignedChar: UInt8? {
+ get{
+ return self.number?.unsignedCharValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt8Value")
+ public var unsignedCharValue: UInt8 {
+ get{
+ return self.numberValue.unsignedCharValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int16")
+ public var short: Int16? {
+ get{
+ return self.number?.shortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int16Value")
+ public var shortValue: Int16 {
+ get{
+ return self.numberValue.shortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt16")
+ public var unsignedShort: UInt16? {
+ get{
+ return self.number?.unsignedShortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt16Value")
+ public var unsignedShortValue: UInt16 {
+ get{
+ return self.numberValue.unsignedShortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int")
+ public var long: Int? {
+ get{
+ return self.number?.longValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="intValue")
+ public var longValue: Int {
+ get{
+ return self.numberValue.longValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt")
+ public var unsignedLong: UInt? {
+ get{
+ return self.number?.unsignedLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uIntValue")
+ public var unsignedLongValue: UInt {
+ get{
+ return self.numberValue.unsignedLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int64")
+ public var longLong: Int64? {
+ get{
+ return self.number?.longLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int64Value")
+ public var longLongValue: Int64 {
+ get{
+ return self.numberValue.longLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt64")
+ public var unsignedLongLong: UInt64? {
+ get{
+ return self.number?.unsignedLongLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt64Value")
+ public var unsignedLongLongValue: UInt64 {
+ get{
+ return self.numberValue.unsignedLongLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int")
+ public var integer: Int? {
+ get {
+ return self.number?.integerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="intValue")
+ public var integerValue: Int {
+ get {
+ return self.numberValue.integerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt")
+ public var unsignedInteger: Int? {
+ get {
+ return self.number?.unsignedIntegerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uIntValue")
+ public var unsignedIntegerValue: Int {
+ get {
+ return self.numberValue.unsignedIntegerValue
+ }
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/TMDB.swift b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/TMDB.swift
new file mode 100644
index 0000000..617084d
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/TMDB.swift
@@ -0,0 +1,212 @@
+//
+// TMDB.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import Foundation
+
+let TMDB_API_KEY = "8a4a247d072d9ca4a0072893ab60e277"
+let TMDB_API_BASE_URL = "http://api.themoviedb.org/3"
+let TMDB_IMAGE_BASE_URL = "http://image.tmdb.org/t/p"
+
+// A generic is like a placeholder for type
+// Here we are saying that Result will have an object
+// of some type associated with the Success case
+// but we don't need to specify what type until we use it
+// This lets us reuse the result enum for any object type!
+enum Result {
+ case Success(T)
+ case Failure
+}
+
+// Here we are using a protocol to say that
+// an APIResponse should have a failable initializer
+// that takes in a JSON object (provided by SwiftyJSON)
+protocol APIResponse {
+ init?(json:JSON)
+}
+
+final class TMDB {
+ // The new syntax for #pragma mark gives us a bookmark in the path bar
+ // MARK: MovieResponse
+
+ // We can nest the struct inside the class and access it like TMDB.MovieResponse
+ struct MovieResponse: APIResponse {
+ // We specify the properties we want to be required as constants
+ // And properties we consider optional as optionals
+ let tmdbId: Int
+ let title: String
+ let overview: String?
+ let averageRating: Double?
+ let voteCount: Int?
+ let releaseDate: String?
+ let genres: [String]?
+ let runtime: Int?
+ let posterPath: String?
+ let backdropPath: String?
+
+ // Adding ? to an initializer makes it failable
+ // This means that just like an optional the init
+ // function can return nil
+ // We are doing this here because we don't want it to
+ // be possible to have a Movie without an id and title
+ // this way we never return invalid results
+ init?(json: JSON) {
+ let jsonId = json["id"]
+ let jsonTitle = json["title"]
+ let jsonOverview = json["overview"]
+ let jsonVoteAverage = json["vote_average"]
+ let jsonVoteCount = json["vote_count"]
+ let jsonReleaseDate = json["release_date"]
+ let jsonRuntime = json["runtime"]
+ let jsonPosterPath = json["poster_path"]
+ let jsonBackdropPath = json["backdrop_path"]
+ let jsonGenres = json["genres"]
+
+ // Required fields
+ // If any require fields are missing we want to fail
+ if let id = jsonId.int {
+ self.tmdbId = id
+ } else {
+ return nil
+ }
+
+ if let title = jsonTitle.string {
+ self.title = title
+ } else {
+ return nil
+ }
+
+ // Optional fields
+ // The TMDB api returns "" for a missing string, 0 for a missing int, 0.0 for missing double
+ // As a result we need to process these as we want to be able to set our interface
+ // based on whether these values are really present (and we want those to be invalid)
+ // This could be a bunch of if statements but the ternary operator condenses it
+ // However this is not very readable - this should be replaced with a function that processes the results
+ self.overview = (jsonOverview.stringValue.isEmpty ? nil: jsonOverview.string)
+ self.averageRating = (jsonVoteAverage.doubleValue.isZero ? nil: jsonVoteAverage.double)
+ self.voteCount = (jsonVoteCount.intValue == 0 ? nil: jsonVoteCount.int)
+ self.releaseDate = (jsonReleaseDate.stringValue.isEmpty ? nil: jsonReleaseDate.string)
+ self.runtime = (jsonRuntime.intValue == 0 ? nil: jsonRuntime.int)
+ self.posterPath = (jsonPosterPath.stringValue.isEmpty ? nil: jsonPosterPath.string)
+ self.backdropPath = (jsonBackdropPath.stringValue.isEmpty ? nil: jsonBackdropPath.string)
+
+ if let jsonArray = jsonGenres.array {
+ var genreArray: [String] = []
+
+ for jsonGenre in jsonArray {
+ if let genreString = jsonGenre["name"].string {
+ genreArray.append(genreString)
+ }
+ }
+
+ if !genreArray.isEmpty {
+ self.genres = genreArray
+ }
+ }
+
+ }
+ }
+
+ // MARK: MovieList
+
+ // Enums are very powerful in swift
+ // They can have (non-stored) properties and methods
+ // Enum types can also have non-integer values
+ enum MovieList {
+ case Popular
+ case Upcoming
+ case NowPlaying
+ case TopRated
+
+ static let allLists = [Popular, Upcoming, NowPlaying, TopRated]
+
+ var queryPath: String {
+ switch self {
+ case .Popular:
+ return "popular"
+ case .Upcoming:
+ return "upcoming"
+ case .NowPlaying:
+ return "now_playing"
+ case .TopRated:
+ return "top_rated"
+ }
+ }
+
+ var listName: String {
+ switch self {
+ case .Popular:
+ return "Popular"
+ case .Upcoming:
+ return "Upcoming"
+ case .NowPlaying:
+ return "Now Playing"
+ case .TopRated:
+ return "Top Rated"
+ }
+ }
+ }
+
+ // We use typealiases to avoid typing out long code blocks and to make our parameters more readable
+ typealias MoviesCompletion = (result: Result<[Movie]>) -> Void
+ typealias MovieCompletion = (result: Result) -> Void
+
+ // MARK: Query Methods
+
+ class func fetchMovieList(list: MovieList, completion: MoviesCompletion) {
+ let urlString = "\(TMDB_API_BASE_URL)/movie/\(list.queryPath)?api_key=\(TMDB_API_KEY)"
+ let request = NSURLRequest(URL: NSURL(string: urlString)!)
+
+ // This method when passed the Main Queue will execute the completion closure on the Main Thread
+ // Otherwise we would want to get the Main Thread before executing our completion closure
+ // As we are going to be doing our interfaced updates in the completion
+ NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
+ (response:NSURLResponse!, data:NSData!, error:NSError!) -> Void in
+ // SwiftyJSON makes JSON parsing much easier
+ // Otherwise we would need a huge nest of if/let statements
+ // Or we would need to use a more advanced approach (creating our own JSON parser)
+ let json = JSON(data: data)
+
+ if let results = json["results"].array {
+ var moviesArray: [Movie] = []
+
+ for jsonMovie in results {
+ if let movieResponse = MovieResponse(json: jsonMovie) {
+ let movie = Movie(TMDBResponse: movieResponse)
+ moviesArray.append(movie)
+ }
+ }
+
+ // Our result enum makes error handling a breeze
+ completion(result: Result.Success(moviesArray))
+ return
+ }
+
+ // If we make it here something went wrong
+ completion(result: Result.Failure)
+ }
+ }
+
+ class func fetchMovie(id: Int, completion: MovieCompletion) {
+ let urlString = "\(TMDB_API_BASE_URL)/movie/\(id)?api_key=\(TMDB_API_KEY)"
+ let request = NSURLRequest(URL: NSURL(string: urlString)!)
+
+ NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
+ (response:NSURLResponse!, data:NSData!, error:NSError!) -> Void in
+ let jsonMovie = JSON(data: data)
+
+ if let movieResponse = MovieResponse(json: jsonMovie) {
+ let movie = Movie(TMDBResponse: movieResponse)
+ completion(result: Result.Success(movie))
+ return
+ }
+
+ // If we make it here something went wrong
+ completion(result: Result.Failure)
+ }
+ }
+}
\ No newline at end of file
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/WebViewController.swift b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/WebViewController.swift
new file mode 100644
index 0000000..d4d8d93
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMovies/WebViewController.swift
@@ -0,0 +1,49 @@
+//
+// WebViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of WebViewController (optimization)
+final class WebViewController: UIViewController {
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var webView: UIWebView!
+
+ var urlString: String?
+ var titleString: String?
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ // Since our titleString and urlString are optionals we have to unwrap them
+ if let title = titleString {
+ self.navigationItem.title = titleString
+ }
+
+ if let urlString = self.urlString {
+ // The NSURL init method returns an optional as well
+ // Its common for Cocoa methods to return optionals (because of Obj-C)
+ if let url = NSURL(string: urlString) {
+ let request = NSURLRequest(URL: url)
+ webView.loadRequest(request)
+ }
+ }
+ }
+}
+
+// Class extensions make it easy to group functionality, like protocol methods
+extension WebViewController: UIWebViewDelegate {
+ // These methods are called automatically when we set the delegate
+ // and adopt the protocol (delegate here is set in storyboard)
+ func webViewDidStartLoad(webView: UIWebView) {
+ self.activityIndicator.startAnimating()
+ }
+
+ func webViewDidFinishLoad(webView: UIWebView) {
+ self.activityIndicator.stopAnimating()
+ }
+}
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMoviesTests/Info.plist b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMoviesTests/Info.plist
new file mode 100644
index 0000000..2afc012
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMoviesTests/Info.plist
@@ -0,0 +1,24 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ phillycocoa.$(PRODUCT_NAME:rfc1034identifier)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ BNDL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+
+
diff --git a/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift
new file mode 100644
index 0000000..3cb0bdc
--- /dev/null
+++ b/4 - Act III/2 - Finished Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift
@@ -0,0 +1,36 @@
+//
+// SwiftMoviesTests.swift
+// SwiftMoviesTests
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+import XCTest
+
+class SwiftMoviesTests: 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/4 - Act III/Closures.playground/contents.xcplayground b/4 - Act III/Closures.playground/contents.xcplayground
new file mode 100644
index 0000000..8e39341
--- /dev/null
+++ b/4 - Act III/Closures.playground/contents.xcplayground
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/4 - Act III/Closures.playground/section-1.swift b/4 - Act III/Closures.playground/section-1.swift
new file mode 100644
index 0000000..a3c2200
--- /dev/null
+++ b/4 - Act III/Closures.playground/section-1.swift
@@ -0,0 +1,30 @@
+// Playground - noun: a place where people can play
+
+import UIKit
+
+/*{ (params) -> returnType in
+ statements
+}*/
+
+let padawans = ["Knox", "Avitla", "Mennaus"]
+
+let closure = {(padawan: String) -> String in
+ "\(padawan) has been trained!"
+}
+
+padawans.map()
+
+// Known arguments (common use case)
+func applyMultiplication(value: Int, multFunction: Int -> Int) -> Int {
+ return multFunction(value)
+}
+
+applyMultiplication(2, {value in
+ value * 3
+})
+
+// Using shorthand we reference by position
+applyMultiplication(2, {$0 * 3})
+
+// When last parameter we can omit )
+applyMultiplication(2) {$0 * 3}
diff --git a/4 - Act III/Closures.playground/timeline.xctimeline b/4 - Act III/Closures.playground/timeline.xctimeline
new file mode 100644
index 0000000..bf468af
--- /dev/null
+++ b/4 - Act III/Closures.playground/timeline.xctimeline
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/5 - Completed Project/SwiftMovies/.DS_Store b/5 - Completed Project/SwiftMovies/.DS_Store
new file mode 100644
index 0000000..79d39e9
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/.DS_Store differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj b/5 - Completed Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..02bd8c2
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies.xcodeproj/project.pbxproj
@@ -0,0 +1,474 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ F45D76761A5FD9FE001807F2 /* SwiftyJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */; };
+ F4646C331A5DF40800336DFC /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4646C321A5DF40800336DFC /* SettingsViewController.swift */; };
+ F4678DB91A5A82F1005A33DE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DB81A5A82F1005A33DE /* AppDelegate.swift */; };
+ F4678DC01A5A82F1005A33DE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F4678DBE1A5A82F1005A33DE /* Main.storyboard */; };
+ F4678DC21A5A82F1005A33DE /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F4678DC11A5A82F1005A33DE /* Images.xcassets */; };
+ F4678DC51A5A82F1005A33DE /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */; };
+ F4678DD11A5A82F1005A33DE /* SwiftMoviesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */; };
+ F4678DE11A5A9582005A33DE /* Movie.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4678DE01A5A9582005A33DE /* Movie.swift */; };
+ F477D6AE1A5F20E2006FD97E /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */; };
+ F477D6B21A5F20FF006FD97E /* FilterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F477D6B11A5F20FF006FD97E /* FilterViewController.swift */; };
+ F49C6F8A1A5F47B200D0C49E /* WebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F49C6F891A5F47B200D0C49E /* WebViewController.swift */; };
+ F4DC98D01A5E5B0C0030CC99 /* CollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */; };
+ F4DC98D21A5E6B460030CC99 /* TMDB.swift in Sources */ = {isa = PBXBuildFile; fileRef = F4DC98D11A5E6B460030CC99 /* TMDB.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ F4678DCB1A5A82F1005A33DE /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = F4678DAB1A5A82F1005A33DE /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = F4678DB21A5A82F1005A33DE;
+ remoteInfo = SwiftMovies;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftyJSON.swift; sourceTree = ""; };
+ F4646C321A5DF40800336DFC /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; };
+ F4678DB31A5A82F1005A33DE /* SwiftMovies.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftMovies.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ F4678DB71A5A82F1005A33DE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ F4678DB81A5A82F1005A33DE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ F4678DBF1A5A82F1005A33DE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
+ F4678DC11A5A82F1005A33DE /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
+ F4678DC41A5A82F1005A33DE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; };
+ F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftMoviesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ F4678DCF1A5A82F1005A33DE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftMoviesTests.swift; sourceTree = ""; };
+ F4678DE01A5A9582005A33DE /* Movie.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Movie.swift; sourceTree = ""; };
+ F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; };
+ F477D6B11A5F20FF006FD97E /* FilterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FilterViewController.swift; sourceTree = ""; };
+ F49C6F891A5F47B200D0C49E /* WebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebViewController.swift; sourceTree = ""; };
+ F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewController.swift; sourceTree = ""; };
+ F4DC98D11A5E6B460030CC99 /* TMDB.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TMDB.swift; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ F4678DB01A5A82F1005A33DE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC71A5A82F1005A33DE /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ F4678DAA1A5A82F1005A33DE = {
+ isa = PBXGroup;
+ children = (
+ F4678DB51A5A82F1005A33DE /* SwiftMovies */,
+ F4678DCD1A5A82F1005A33DE /* SwiftMoviesTests */,
+ F4678DB41A5A82F1005A33DE /* Products */,
+ );
+ sourceTree = "";
+ };
+ F4678DB41A5A82F1005A33DE /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DB31A5A82F1005A33DE /* SwiftMovies.app */,
+ F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ F4678DB51A5A82F1005A33DE /* SwiftMovies */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DB81A5A82F1005A33DE /* AppDelegate.swift */,
+ F4678DC11A5A82F1005A33DE /* Images.xcassets */,
+ F477D6AA1A5F209D006FD97E /* Controllers */,
+ F477D6B31A5F210F006FD97E /* Models */,
+ F477D6B71A5F215E006FD97E /* Networking */,
+ F4678DBE1A5A82F1005A33DE /* Main.storyboard */,
+ F4678DB61A5A82F1005A33DE /* Supporting Files */,
+ );
+ path = SwiftMovies;
+ sourceTree = "";
+ };
+ F4678DB61A5A82F1005A33DE /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */,
+ F4678DB71A5A82F1005A33DE /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ F4678DCD1A5A82F1005A33DE /* SwiftMoviesTests */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DD01A5A82F1005A33DE /* SwiftMoviesTests.swift */,
+ F4678DCE1A5A82F1005A33DE /* Supporting Files */,
+ );
+ path = SwiftMoviesTests;
+ sourceTree = "";
+ };
+ F4678DCE1A5A82F1005A33DE /* Supporting Files */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DCF1A5A82F1005A33DE /* Info.plist */,
+ );
+ name = "Supporting Files";
+ sourceTree = "";
+ };
+ F477D6AA1A5F209D006FD97E /* Controllers */ = {
+ isa = PBXGroup;
+ children = (
+ F4DC98CF1A5E5B0C0030CC99 /* CollectionViewController.swift */,
+ F477D6AD1A5F20E2006FD97E /* DetailViewController.swift */,
+ F477D6B11A5F20FF006FD97E /* FilterViewController.swift */,
+ F4646C321A5DF40800336DFC /* SettingsViewController.swift */,
+ F49C6F891A5F47B200D0C49E /* WebViewController.swift */,
+ );
+ name = Controllers;
+ sourceTree = "";
+ };
+ F477D6B31A5F210F006FD97E /* Models */ = {
+ isa = PBXGroup;
+ children = (
+ F4678DE01A5A9582005A33DE /* Movie.swift */,
+ );
+ name = Models;
+ sourceTree = "";
+ };
+ F477D6B71A5F215E006FD97E /* Networking */ = {
+ isa = PBXGroup;
+ children = (
+ F4DC98D11A5E6B460030CC99 /* TMDB.swift */,
+ F45D76751A5FD9FE001807F2 /* SwiftyJSON.swift */,
+ );
+ name = Networking;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ F4678DB21A5A82F1005A33DE /* SwiftMovies */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F4678DD41A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMovies" */;
+ buildPhases = (
+ F4678DAF1A5A82F1005A33DE /* Sources */,
+ F4678DB01A5A82F1005A33DE /* Frameworks */,
+ F4678DB11A5A82F1005A33DE /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = SwiftMovies;
+ productName = SwiftMovies;
+ productReference = F4678DB31A5A82F1005A33DE /* SwiftMovies.app */;
+ productType = "com.apple.product-type.application";
+ };
+ F4678DC91A5A82F1005A33DE /* SwiftMoviesTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = F4678DD71A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMoviesTests" */;
+ buildPhases = (
+ F4678DC61A5A82F1005A33DE /* Sources */,
+ F4678DC71A5A82F1005A33DE /* Frameworks */,
+ F4678DC81A5A82F1005A33DE /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ F4678DCC1A5A82F1005A33DE /* PBXTargetDependency */,
+ );
+ name = SwiftMoviesTests;
+ productName = SwiftMoviesTests;
+ productReference = F4678DCA1A5A82F1005A33DE /* SwiftMoviesTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ F4678DAB1A5A82F1005A33DE /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0610;
+ ORGANIZATIONNAME = "Philly Cocoaheads";
+ TargetAttributes = {
+ F4678DB21A5A82F1005A33DE = {
+ CreatedOnToolsVersion = 6.1.1;
+ };
+ F4678DC91A5A82F1005A33DE = {
+ CreatedOnToolsVersion = 6.1.1;
+ TestTargetID = F4678DB21A5A82F1005A33DE;
+ };
+ };
+ };
+ buildConfigurationList = F4678DAE1A5A82F1005A33DE /* Build configuration list for PBXProject "SwiftMovies" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = F4678DAA1A5A82F1005A33DE;
+ productRefGroup = F4678DB41A5A82F1005A33DE /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ F4678DB21A5A82F1005A33DE /* SwiftMovies */,
+ F4678DC91A5A82F1005A33DE /* SwiftMoviesTests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ F4678DB11A5A82F1005A33DE /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4678DC01A5A82F1005A33DE /* Main.storyboard in Resources */,
+ F4678DC51A5A82F1005A33DE /* LaunchScreen.xib in Resources */,
+ F4678DC21A5A82F1005A33DE /* Images.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC81A5A82F1005A33DE /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ F4678DAF1A5A82F1005A33DE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4646C331A5DF40800336DFC /* SettingsViewController.swift in Sources */,
+ F477D6AE1A5F20E2006FD97E /* DetailViewController.swift in Sources */,
+ F49C6F8A1A5F47B200D0C49E /* WebViewController.swift in Sources */,
+ F45D76761A5FD9FE001807F2 /* SwiftyJSON.swift in Sources */,
+ F4DC98D01A5E5B0C0030CC99 /* CollectionViewController.swift in Sources */,
+ F4678DE11A5A9582005A33DE /* Movie.swift in Sources */,
+ F4DC98D21A5E6B460030CC99 /* TMDB.swift in Sources */,
+ F477D6B21A5F20FF006FD97E /* FilterViewController.swift in Sources */,
+ F4678DB91A5A82F1005A33DE /* AppDelegate.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ F4678DC61A5A82F1005A33DE /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F4678DD11A5A82F1005A33DE /* SwiftMoviesTests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ F4678DCC1A5A82F1005A33DE /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = F4678DB21A5A82F1005A33DE /* SwiftMovies */;
+ targetProxy = F4678DCB1A5A82F1005A33DE /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ F4678DBE1A5A82F1005A33DE /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F4678DBF1A5A82F1005A33DE /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "";
+ };
+ F4678DC31A5A82F1005A33DE /* LaunchScreen.xib */ = {
+ isa = PBXVariantGroup;
+ children = (
+ F4678DC41A5A82F1005A33DE /* Base */,
+ );
+ name = LaunchScreen.xib;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ F4678DD21A5A82F1005A33DE /* 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.1;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ F4678DD31A5A82F1005A33DE /* 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.1;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ F4678DD51A5A82F1005A33DE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = SwiftMovies/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Debug;
+ };
+ F4678DD61A5A82F1005A33DE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ INFOPLIST_FILE = SwiftMovies/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ F4678DD81A5A82F1005A33DE /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = SwiftMoviesTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftMovies.app/SwiftMovies";
+ };
+ name = Debug;
+ };
+ F4678DD91A5A82F1005A33DE /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(SDKROOT)/Developer/Library/Frameworks",
+ "$(inherited)",
+ );
+ INFOPLIST_FILE = SwiftMoviesTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftMovies.app/SwiftMovies";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ F4678DAE1A5A82F1005A33DE /* Build configuration list for PBXProject "SwiftMovies" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD21A5A82F1005A33DE /* Debug */,
+ F4678DD31A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ F4678DD41A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMovies" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD51A5A82F1005A33DE /* Debug */,
+ F4678DD61A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ F4678DD71A5A82F1005A33DE /* Build configuration list for PBXNativeTarget "SwiftMoviesTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ F4678DD81A5A82F1005A33DE /* Debug */,
+ F4678DD91A5A82F1005A33DE /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = F4678DAB1A5A82F1005A33DE /* Project object */;
+}
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/5 - Completed Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..7890687
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate b/5 - Completed Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..d3800ec
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies.xcodeproj/project.xcworkspace/xcuserdata/Home.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/5 - Completed Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
new file mode 100644
index 0000000..fe2b454
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -0,0 +1,5 @@
+
+
+
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme b/5 - Completed Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme
new file mode 100644
index 0000000..ec387aa
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/SwiftMovies.xcscheme
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist b/5 - Completed Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..dd30f16
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies.xcodeproj/xcuserdata/Home.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,27 @@
+
+
+
+
+ SchemeUserState
+
+ SwiftMovies.xcscheme
+
+ orderHint
+ 0
+
+
+ SuppressBuildableAutocreation
+
+ F4678DB21A5A82F1005A33DE
+
+ primary
+
+
+ F4678DC91A5A82F1005A33DE
+
+ primary
+
+
+
+
+
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/AppDelegate.swift b/5 - Completed Project/SwiftMovies/SwiftMovies/AppDelegate.swift
new file mode 100644
index 0000000..9c2f2cc
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/AppDelegate.swift
@@ -0,0 +1,46 @@
+//
+// AppDelegate.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+@UIApplicationMain
+class AppDelegate: UIResponder, UIApplicationDelegate {
+
+ var window: UIWindow?
+
+
+ func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> 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/5 - Completed Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib b/5 - Completed Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib
new file mode 100644
index 0000000..9e43426
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/Base.lproj/LaunchScreen.xib
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard b/5 - Completed Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..d2a2f64
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/Base.lproj/Main.storyboard
@@ -0,0 +1,612 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/CollectionViewController.swift b/5 - Completed Project/SwiftMovies/SwiftMovies/CollectionViewController.swift
new file mode 100644
index 0000000..2f6474c
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/CollectionViewController.swift
@@ -0,0 +1,114 @@
+//
+// MovieCollectionController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Since we don't have to worry about headers and imports in Swift
+// It sometimes makes sense to keep multiple classes in the same file
+final class MovieCell: UICollectionViewCell {
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var imageView: UIImageView!
+}
+
+final class CollectionViewController: UIViewController {
+ @IBOutlet weak var collectionView: UICollectionView!
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+
+ var movies: [Movie] = []
+ var activeList: TMDB.MovieList = .Popular // We can exclude the enum name and just use .Type
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.navigationItem.title = self.activeList.listName
+ self.refreshMovieResults()
+ }
+
+ func refreshMovieResults() {
+ self.activityIndicator.startAnimating()
+
+ // Swift allows a shorthand if a closure is the last parameter
+ // of a function, as seen here
+ TMDB.fetchMovieList(self.activeList) {
+ self.activityIndicator.stopAnimating()
+
+ // When we use the shorthand we don't have a named result
+ // so we need to reference parameters by position $0, $1, etc.
+ // these are automatic shorthand argument names generated by Swift
+ switch $0 {
+ case .Success(let results):
+ self.movies = results
+ self.collectionView.reloadData()
+ case .Failure:
+ let errorMessage = "There was an issue refreshing movies. Please check your connection or try again later."
+ let alert = UIAlertController(title: "Sorry", message: errorMessage, preferredStyle: UIAlertControllerStyle.Alert)
+ alert.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default, handler: nil))
+ self.presentViewController(alert, animated: true, completion: nil)
+ }
+ }
+ }
+
+ override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
+ if segue.identifier == "showMovieView" {
+ // We use "as" to typecast to a certain object type
+ let movieController = segue.destinationViewController as DetailViewController
+ let indexPath = self.collectionView.indexPathsForSelectedItems().first as NSIndexPath?
+ if let selectedPath = indexPath {
+ // Pass the selected movie to detail view
+ let movie = self.movies[selectedPath.row]
+ movieController.movie = movie
+ }
+ }
+
+ if segue.identifier == "showFilterView" {
+ // We use "as" to typecast to a certain object type
+ let navController = segue.destinationViewController as UINavigationController
+ let filterController = navController.viewControllers.first as FilterViewController
+ // By setting the delegate to this controller we receive updates when the filter changes.
+ filterController.delegate = self
+ }
+ }
+}
+
+// Class extensions make it easy to group functionality, like protocol methods
+extension CollectionViewController: UICollectionViewDelegate, UICollectionViewDataSource {
+ func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
+ return self.movies.count
+ }
+
+ func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
+ let movieCell = collectionView.dequeueReusableCellWithReuseIdentifier("movieCell", forIndexPath: indexPath) as MovieCell
+ let movie = self.movies[indexPath.row]
+
+ // Set poster to nil while loading
+ movieCell.imageView.image = nil
+ movieCell.activityIndicator.startAnimating()
+
+ movie.loadPosterImage() {
+ switch $0 {
+ case .Success(let posterImage):
+ movieCell.imageView.image = posterImage
+ case .Failure:
+ movieCell.imageView.image = UIImage(named: "noPoster")
+ }
+
+ movieCell.activityIndicator.stopAnimating()
+ }
+
+ return movieCell
+ }
+}
+
+extension CollectionViewController: FilterViewDelegate {
+ func filterDidChange(list: TMDB.MovieList) {
+ self.activeList = list
+ self.navigationItem.title = list.listName
+ // We want the collectionview to scroll back to the top instantly on list change
+ self.collectionView.setContentOffset(CGPoint(x: 0, y:-self.collectionView.contentInset.top), animated: false)
+ self.refreshMovieResults()
+ }
+}
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/DetailViewController.swift b/5 - Completed Project/SwiftMovies/SwiftMovies/DetailViewController.swift
new file mode 100644
index 0000000..be9d222
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/DetailViewController.swift
@@ -0,0 +1,153 @@
+//
+// MovieViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class DetailViewController: UIViewController {
+ @IBOutlet weak var backdropImageView: UIImageView!
+ @IBOutlet weak var backdropActivityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var titleLabel: UILabel!
+ @IBOutlet weak var ratingLabel: UILabel!
+ @IBOutlet weak var summaryLabel: UILabel!
+ @IBOutlet weak var releaseDateLabel: UILabel!
+ @IBOutlet weak var genresLabel: UILabel!
+ @IBOutlet weak var runtimeLabel: UILabel!
+
+ var movie: Movie?
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ self.movie = nil
+ self.loadMovieInfo()
+ }
+
+ private func loadMovieInfo() {
+ let ellipsis = "..."
+
+ // Setup our empty state (how the screen should look while loading)
+ self.backdropImageView.image = nil
+ self.titleLabel.text = ellipsis
+ self.navigationItem.title = ellipsis
+ self.ratingLabel.text = ellipsis
+ self.summaryLabel.text = ellipsis
+ self.releaseDateLabel.text = ellipsis
+ self.genresLabel.text = ellipsis
+ self.runtimeLabel.text = ellipsis
+
+ if let movie = self.movie {
+ // Since title is not an optional, we know we will always
+ // have one as long as the movie exists
+ self.titleLabel.text = movie.title
+ self.navigationItem.title = movie.title
+
+ // Swift allows a shorthand if a closure is the last parameter
+ // of a function, as seen here
+ TMDB.fetchMovie(movie.tmdbId) {
+ // When we use the shorthand we don't have a named result
+ // so we need to reference parameters by position $0, $1, etc.
+ // these are automatic shorthand argument names generated by Swift
+ switch $0 {
+ case .Success(let movie):
+ self.movie = movie
+ case .Failure:
+ self.displayNetworkError()
+ }
+
+ // We always want to update the inferface, because the function is designed
+ // to handle missing values appropriately
+ self.updateInterface()
+ }
+ } else {
+ // If we don't have a movie to load skip fetching, display error message
+ self.displayNetworkError()
+ self.updateInterface()
+ }
+ }
+
+ private func updateInterface() {
+ let na = "Not Available"
+
+ // We can use optional chaining and the Nil Coalescing operater to avoid a long list of if/let/else statements
+ self.titleLabel.text = self.movie?.title ?? na
+ self.ratingLabel.text = self.ratingString(self.movie?.rating) ?? "N/A"
+ self.summaryLabel.text = self.movie?.summary ?? "No Synopsis Available."
+ self.releaseDateLabel.text = self.movie?.releaseDate ?? na
+ self.genresLabel.text = self.genresString(self.movie?.genres) ?? na
+ self.runtimeLabel.text = self.minutesString(self.movie?.runtime) ?? na
+
+ self.loadBackdropImage()
+ }
+
+ // Since we use it in multiple locations, it makes sense to seperate our error display into a function
+ private func displayNetworkError() {
+ let errorMessage = "We were unable to fetch movie information. Please check your connection or try again later."
+ let alert = UIAlertController(title: "Sorry", message: errorMessage, preferredStyle: UIAlertControllerStyle.Alert)
+ alert.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default, handler: nil))
+ self.presentViewController(alert, animated: true, completion: nil)
+ }
+
+ private func loadBackdropImage() {
+ let emptyImage = UIImage(named: "noBackdrop")
+
+ if let movie = self.movie {
+ self.backdropActivityIndicator.startAnimating()
+
+ movie.loadBackdropImage() {
+ switch $0 {
+ case .Success(let backdropImage):
+ self.backdropImageView.image = backdropImage
+ case .Failure:
+ self.backdropImageView.image = emptyImage
+ }
+
+ self.backdropActivityIndicator.stopAnimating()
+ }
+ } else {
+ // Being extra safe
+ self.backdropImageView.image = emptyImage
+ }
+ }
+
+ // When we see isolated chunks of code cluttering a function
+ // it often makes sense to seperate it into its own function
+ private func genresString(genres: [String]?) -> String? {
+ if let genresArray = genres {
+ var genreString = ""
+
+ for (index, genre) in enumerate(genresArray) {
+ genreString += genre
+
+ // index starts at 0 so we need count - 1
+ if index != genresArray.count - 1 {
+ genreString += ", "
+ }
+ }
+
+ return genreString
+ }
+
+ return nil
+ }
+
+ private func minutesString(minutes: Int?) -> String? {
+ if let m = minutes {
+ return "\(m) minutes"
+ }
+
+ return nil
+ }
+
+ private func ratingString(rating: Rating?) -> String? {
+ if let r = rating {
+ return "\(r.averageRating) (\(r.voteCount))"
+ }
+
+ return nil
+ }
+}
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/FilterViewController.swift b/5 - Completed Project/SwiftMovies/SwiftMovies/FilterViewController.swift
new file mode 100644
index 0000000..ee189c2
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/FilterViewController.swift
@@ -0,0 +1,64 @@
+//
+// FiltersViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// ? is shorthand for unwrapping an optional then performing a method on the result
+// If the result is nil, everything after the ? is ignored
+// Its called Optional chaining and its used throughout this class
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class FilterViewController: UIViewController {
+ // You can use protocols and delegates together to communicate between objects
+ // This will enable us to tell our Collection controller when the filter has changed
+ var delegate: FilterViewDelegate?
+
+ @IBAction func cancel(sender: AnyObject) {
+ self.dismiss()
+ }
+
+ func dismiss() {
+ self.navigationController?.dismissViewControllerAnimated(true, completion: nil)
+ }
+}
+
+// Class extensions make it easy to group functionality, like protocol methods
+extension FilterViewController: UITableViewDelegate, UITableViewDataSource {
+ func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ return TMDB.MovieList.allLists.count
+ }
+
+ func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
+ let cell = tableView.dequeueReusableCellWithIdentifier("filterCell") as UITableViewCell
+ let movieList: TMDB.MovieList = TMDB.MovieList.allLists[indexPath.row]
+
+ cell.textLabel?.text = movieList.listName
+
+ if movieList == delegate?.activeList {
+ cell.accessoryType = UITableViewCellAccessoryType.Checkmark
+ } else {
+ cell.accessoryType = UITableViewCellAccessoryType.None
+ }
+
+ return cell
+ }
+
+ func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
+ tableView.deselectRowAtIndexPath(indexPath, animated: false) // Fix sticky cells
+ let movieList: TMDB.MovieList = TMDB.MovieList.allLists[indexPath.row]
+ self.delegate?.filterDidChange(movieList)
+ self.dismiss()
+ }
+}
+
+// Protocols allow us to force an object to adopt certain
+// properties and methods (by adopting the protocol)
+protocol FilterViewDelegate {
+ var activeList: TMDB.MovieList { get }
+ func filterDidChange(list: TMDB.MovieList)
+}
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store
new file mode 100644
index 0000000..c068369
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/.DS_Store differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..7997783
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,44 @@
+{
+ "images" : [
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-29@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "29x29",
+ "idiom" : "iphone",
+ "filename" : "Icon-29@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-40@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "40x40",
+ "idiom" : "iphone",
+ "filename" : "Icon-40@3x.png",
+ "scale" : "3x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-60@2x.png",
+ "scale" : "2x"
+ },
+ {
+ "size" : "60x60",
+ "idiom" : "iphone",
+ "filename" : "Icon-60@3x.png",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png
new file mode 100644
index 0000000..d463ba9
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png
new file mode 100644
index 0000000..e421cfa
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png
new file mode 100644
index 0000000..2be6555
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png
new file mode 100644
index 0000000..efa69d2
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png
new file mode 100644
index 0000000..efa69d2
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png
new file mode 100644
index 0000000..e405742
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..0f84226
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "bt6DhdALyhf90gReozoQ0y3R3vZ.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg
new file mode 100644
index 0000000..1e19bbb
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/goneBackdrop.imageset/bt6DhdALyhf90gReozoQ0y3R3vZ.jpg differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..5d9e965
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-1.jpg differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x-2.jpg differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg
new file mode 100644
index 0000000..73eaafc
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/guardiansBackdrop.imageset/bHarw8xrmQeqf3t8HpuMY7zoK4x.jpg differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..3124e77
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "umR9aXTxOxQUuDH2DamoJ5fIPB.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg
new file mode 100644
index 0000000..f4c469c
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/hobbitBackdrop.imageset/umR9aXTxOxQUuDH2DamoJ5fIPB.jpg differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..ed3e63e
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "eDildzNrm4XJABWkNKtqB29t6mv.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg
new file mode 100644
index 0000000..90ede16
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/interviewBackdrop.imageset/eDildzNrm4XJABWkNKtqB29t6mv.jpg differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json
new file mode 100644
index 0000000..8d49e39
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "Rectangle 1 + NO BACKDROP AVAILABL@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png
new file mode 100644
index 0000000..68aa392
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png
new file mode 100644
index 0000000..bb5d8b4
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@2x.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png
new file mode 100644
index 0000000..12923f2
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/BackdropPlaceholders/noBackdrop.imageset/Rectangle 1 + NO BACKDROP AVAILABL@3x.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json
new file mode 100644
index 0000000..4e659b8
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "settings.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "settings@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "settings@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png
new file mode 100644
index 0000000..e2d21f0
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png
new file mode 100644
index 0000000..6fd890d
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@2x.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png
new file mode 100644
index 0000000..d68af6b
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/settings.imageset/settings@3x.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json
new file mode 100644
index 0000000..50564ce
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "star.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "star@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "star@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png
new file mode 100644
index 0000000..2b2b41b
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png
new file mode 100644
index 0000000..f1367c8
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@2x.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png
new file mode 100644
index 0000000..390ad8e
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/star.imageset/star@3x.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json
new file mode 100644
index 0000000..04ea068
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "tag.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "tag@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "tag@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png
new file mode 100644
index 0000000..d46a1af
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png
new file mode 100644
index 0000000..5d176aa
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@2x.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png
new file mode 100644
index 0000000..bee24d8
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Icons/tag.imageset/tag@3x.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json
new file mode 100644
index 0000000..16f2d86
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-1.jpg differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj-2.jpg differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg
new file mode 100644
index 0000000..bbeeeef
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/gonePoster.imageset/gdiLTof3rbPDAmPaCf4g6op46bj.jpg differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg
new file mode 100644
index 0000000..700d056
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json
new file mode 100644
index 0000000..2febbf6
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/guardiansPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "9gm3lL8JMTTmc3W4BmNMCuRLdL8-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json
new file mode 100644
index 0000000..37c7f9d
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-1.jpg differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo-2.jpg differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg
new file mode 100644
index 0000000..ae13731
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/hobbitPoster.imageset/vgAHvS0bT3fpcpnJqT6uDTUsHTo.jpg differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json
new file mode 100644
index 0000000..8e8af21
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "interview.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "interview-1.jpg"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "interview-2.jpg"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-1.jpg differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview-2.jpg differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg
new file mode 100644
index 0000000..0dc79f2
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/interviewPoster.imageset/interview.jpg differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json
new file mode 100644
index 0000000..4b2222a
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Contents.json
@@ -0,0 +1,23 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "scale" : "1x",
+ "filename" : "Placeholder.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x",
+ "filename" : "Placeholder@2x.png"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x",
+ "filename" : "Placeholder@3x.png"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png
new file mode 100644
index 0000000..4f45f19
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png
new file mode 100644
index 0000000..e21d629
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@2x.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png
new file mode 100644
index 0000000..6d89554
Binary files /dev/null and b/5 - Completed Project/SwiftMovies/SwiftMovies/Images.xcassets/Poster Placeholders/noPoster.imageset/Placeholder@3x.png differ
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Info.plist b/5 - Completed Project/SwiftMovies/SwiftMovies/Info.plist
new file mode 100644
index 0000000..aab298d
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/Info.plist
@@ -0,0 +1,52 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleDisplayName
+ Swift Movies
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ phillycocoa.$(PRODUCT_NAME:rfc1034identifier)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UIStatusBarTintParameters
+
+ UINavigationBar
+
+ Style
+ UIBarStyleDefault
+ Translucent
+
+
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+
+
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/Movie.swift b/5 - Completed Project/SwiftMovies/SwiftMovies/Movie.swift
new file mode 100644
index 0000000..d5d55b6
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/Movie.swift
@@ -0,0 +1,110 @@
+//
+// Movie.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+final class Movie {
+ // The pattern we've adopted lets us use constants throughout
+ // and optionals only for properties that are truly optional
+ let tmdbId: Int
+ let title: String
+ let summary: String?
+ let rating: Rating?
+ let releaseDate: String?
+ let genres: [String]?
+ let runtime: Int?
+ let posterPath: String?
+ let backdropPath: String?
+
+ // We could use an init with JSON function or similar here
+ // but doing it this way insulates our Movie class from our API service
+ // We could now just as easily add a RottenTomatoes initializer for example
+ init(TMDBResponse: TMDB.MovieResponse) {
+ self.tmdbId = TMDBResponse.tmdbId
+ self.title = TMDBResponse.title
+ self.summary = TMDBResponse.overview
+
+ // We only consider a rating valid if we have both the average and the vote count
+ if let averageRating = TMDBResponse.averageRating {
+ if let voteCount = TMDBResponse.voteCount {
+ self.rating = Rating(averageRating: averageRating, voteCount: voteCount)
+ }
+ }
+
+ self.releaseDate = TMDBResponse.releaseDate
+ self.genres = TMDBResponse.genres
+ self.runtime = TMDBResponse.runtime
+ self.posterPath = TMDBResponse.posterPath
+ self.backdropPath = TMDBResponse.backdropPath
+ }
+
+ // A Type Alias is just like it sounds - its a shorthand name for a specific type
+ // It comes in handy for blocks where the syntax is a bit unruly, especially
+ // when the block is a function parameter
+ typealias ImageCompletion = (result: Result) -> Void
+
+ func loadPosterImage(completion: ImageCompletion) {
+ if let posterPath = self.posterPath {
+ // For the sake of this workshop we are passing a hardcoded image size parameter
+ // In reality we would want to query the TMDB config endpoint to fetch all of the sizes
+ // and have them in a strongly typed form - like an enum
+ self.loadImage("w500", path: posterPath, completion: completion)
+ // returns can be handy for avoiding a lot of nesting and if/else statements
+ return
+ }
+
+ completion(result: Result.Failure)
+ }
+
+ func loadBackdropImage(completion: ImageCompletion) {
+ if let backdropPath = self.backdropPath {
+ self.loadImage("w780", path: backdropPath, completion: completion)
+ return
+ }
+
+ completion(result: Result.Failure)
+ }
+
+ // Since we have two different images we have to fetch, it makes sense to keep some
+ // shared logic in a seperate function to keep things DRY
+ // Note that we make it a private function so there is no risk of it being called outside its own instance
+ private func loadImage(size: String, path: String, completion: ImageCompletion) {
+ let url = NSURL(string: "\(TMDB_IMAGE_BASE_URL)/\(size)/\(path)")
+ // Another option:
+ // let url = NSURL(string: TMDB_IMAGE_BASE_URL + "/" + size + "/" + path")
+ if url == nil {
+ completion(result: Result.Failure)
+ return
+ }
+
+ // This method when passed the Main Queue will execute the completion closure on the Main Thread
+ // Otherwise we would want to get the Main Thread before executing our completion closure
+ // As we are going to be doing our interfaced updates in the completion
+ NSURLConnection.sendAsynchronousRequest(NSURLRequest(URL: url!), queue: NSOperationQueue.mainQueue()) {
+ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
+
+ if data != nil {
+ if let image = UIImage(data: data) {
+ completion(result: Result.Success(image))
+ return
+ }
+ }
+
+ // If we make it here something went wrong
+ completion(result: Result.Failure)
+ }
+ }
+}
+
+// A struct is similar to a class except that it cannot inherit
+// and it is a value type (as opposed to a reference type)
+// They are often used for objects that just hold data
+struct Rating {
+ var averageRating: Double
+ var voteCount: Int
+}
\ No newline at end of file
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/SettingsViewController.swift b/5 - Completed Project/SwiftMovies/SwiftMovies/SettingsViewController.swift
new file mode 100644
index 0000000..5eb50ef
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/SettingsViewController.swift
@@ -0,0 +1,59 @@
+//
+// SettingsController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/7/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of SettingsViewController (optimization)
+final class SettingsViewController: UITableViewController {
+ // Private properties are only available to the instance of the object (can't be called from another object)
+ // Its good practice for things you know will only be used internally
+ private let webViewSegue = "showWebView"
+ private var webViewProperties: (title: String?, urlString: String?)
+
+ override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
+ let path = (indexPath.section, indexPath.row)
+
+ // We can use tuples and a switch to cover our row actions without a big if/else mess
+ // We are also using a tuple to capture the title and url in one variable
+ switch path {
+ case (0, 0):
+ self.webViewProperties = ("@themoviedb", "http://twitter.com/themoviedb")
+ case (0, 1):
+ self.webViewProperties = ("The Movie DB", "http://facebook.com/themoviedb")
+ case (1, 0):
+ self.webViewProperties = ("Terms of Service", "http://themoviedb.org/documentation/website/terms-of-use")
+ case (1, 1):
+ self.webViewProperties = ("Privacy Policy", "http://themoviedb.org/privacy-policy")
+ default:
+ // This should never happen, but lets get in the mindset of handling issues gracefully
+ // Swift will actually give an error if we don't have this default case (must be exhaustive)
+ // We can demonstrate this by commenting out one of our cell handlers then tapping that cell
+ let alertTitle = "Sorry!"
+ let alertMessage = "An unknown error occurred."
+ let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: UIAlertControllerStyle.Alert)
+ alert.addAction(UIAlertAction(title: "Okay", style: UIAlertActionStyle.Default, handler: nil))
+ self.presentViewController(alert, animated: true, completion: nil)
+ self.tableView.deselectRowAtIndexPath(indexPath, animated: false) // Deselect the cell so it does not "stick"
+
+ // Return so we don't perform the segue
+ return
+ }
+
+ // Since all the various rows are going to the same view controller, we can trigger the
+ // segue manually instead of having to create 4 segues pointing to the same controller
+ self.performSegueWithIdentifier(webViewSegue, sender: self)
+ }
+
+ override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
+ if segue.identifier == webViewSegue {
+ let webViewController = segue.destinationViewController as WebViewController
+ webViewController.titleString = self.webViewProperties.title
+ webViewController.urlString = self.webViewProperties.urlString
+ }
+ }
+}
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift b/5 - Completed Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift
new file mode 100644
index 0000000..f26c7e7
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/SwiftyJSON.swift
@@ -0,0 +1,1335 @@
+// SwiftyJSON.swift
+//
+// Copyright (c) 2014 Ruoyu Fu, Pinglin Tang
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+import Foundation
+
+// MARK: - Error
+
+///Error domain
+public let ErrorDomain: String! = "SwiftyJSONErrorDomain"
+
+///Error code
+public let ErrorUnsupportedType: Int! = 999
+public let ErrorIndexOutOfBounds: Int! = 900
+public let ErrorWrongType: Int! = 901
+public let ErrorNotExist: Int! = 500
+
+// MARK: - JSON Type
+
+/**
+JSON's type definitions.
+
+See http://tools.ietf.org/html/rfc7231#section-4.3
+*/
+public enum Type :Int{
+
+ case Number
+ case String
+ case Bool
+ case Array
+ case Dictionary
+ case Null
+ case Unknown
+}
+
+// MARK: - JSON Base
+
+public struct JSON {
+
+ /**
+ Creates a JSON using the data.
+
+ :param: data The NSData used to convert to json.Top level object in data is an NSArray or NSDictionary
+ :param: opt The JSON serialization reading options. `.AllowFragments` by default.
+ :param: error error The NSErrorPointer used to return the error. `nil` by default.
+
+ :returns: The created JSON
+ */
+ public init(data:NSData, options opt: NSJSONReadingOptions = .AllowFragments, error: NSErrorPointer = nil) {
+ if let object: AnyObject = NSJSONSerialization.JSONObjectWithData(data, options: opt, error: error) {
+ self.init(object)
+ } else {
+ self.init(NSNull())
+ }
+ }
+
+ /**
+ Creates a JSON using the object.
+
+ :param: object The object must have the following properties: All objects are NSString/String, NSNumber/Int/Float/Double/Bool, NSArray/Array, NSDictionary/Dictionary, or NSNull; All dictionary keys are NSStrings/String; NSNumbers are not NaN or infinity.
+
+ :returns: The created JSON
+ */
+ public init(_ object: AnyObject) {
+ self.object = object
+ }
+
+ /// Private object
+ private var _object: AnyObject = NSNull()
+ /// Private type
+ private var _type: Type = .Null
+ /// prviate error
+ private var _error: NSError?
+
+ /// Object in JSON
+ public var object: AnyObject {
+ get {
+ return _object
+ }
+ set {
+ _object = newValue
+ switch newValue {
+ case let number as NSNumber:
+ if number.isBool {
+ _type = .Bool
+ } else {
+ _type = .Number
+ }
+ case let string as NSString:
+ _type = .String
+ case let null as NSNull:
+ _type = .Null
+ case let array as [AnyObject]:
+ _type = .Array
+ case let dictionary as [String : AnyObject]:
+ _type = .Dictionary
+ default:
+ _type = .Unknown
+ _object = NSNull()
+ _error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"])
+ }
+ }
+ }
+
+ /// json type
+ public var type: Type { get { return _type } }
+
+ /// Error in JSON
+ public var error: NSError? { get { return self._error } }
+
+ /// The static null json
+ public static var nullJSON: JSON { get { return JSON(NSNull()) } }
+
+}
+
+// MARK: - SequenceType
+extension JSON: SequenceType{
+
+ /// If `type` is `.Array` or `.Dictionary`, return `array.empty` or `dictonary.empty` otherwise return `false`.
+ public var isEmpty: Bool {
+ get {
+ switch self.type {
+ case .Array:
+ return (self.object as [AnyObject]).isEmpty
+ case .Dictionary:
+ return (self.object as [String : AnyObject]).isEmpty
+ default:
+ return false
+ }
+ }
+ }
+
+ /// If `type` is `.Array` or `.Dictionary`, return `array.count` or `dictonary.count` otherwise return `0`.
+ public var count: Int {
+ get {
+ switch self.type {
+ case .Array:
+ return self.arrayValue.count
+ case .Dictionary:
+ return self.dictionaryValue.count
+ default:
+ return 0
+ }
+ }
+ }
+
+ /**
+ If `type` is `.Array` or `.Dictionary`, return a generator over the elements like `Array` or `Dictionary, otherwise return a generator over empty.
+
+ :returns: Return a *generator* over the elements of this *sequence*.
+ */
+ public func generate() -> GeneratorOf <(String, JSON)> {
+ switch self.type {
+ case .Array:
+ let array_ = object as [AnyObject]
+ var generate_ = array_.generate()
+ var index_: Int = 0
+ return GeneratorOf<(String, JSON)> {
+ if let element_: AnyObject = generate_.next() {
+ return ("\(index_++)", JSON(element_))
+ } else {
+ return nil
+ }
+ }
+ case .Dictionary:
+ let dictionary_ = object as [String : AnyObject]
+ var generate_ = dictionary_.generate()
+ return GeneratorOf<(String, JSON)> {
+ if let (key_: String, value_: AnyObject) = generate_.next() {
+ return (key_, JSON(value_))
+ } else {
+ return nil
+ }
+ }
+ default:
+ return GeneratorOf<(String, JSON)> {
+ return nil
+ }
+ }
+ }
+}
+
+// MARK: - Subscript
+
+/**
+* To mark both String and Int can be used in subscript.
+*/
+public protocol SubscriptType {}
+
+extension Int: SubscriptType {}
+
+extension String: SubscriptType {}
+
+extension JSON {
+
+ /// If `type` is `.Array`, return json which's object is `array[index]`, otherwise return null json with error.
+ private subscript(#index: Int) -> JSON {
+ get {
+
+ if self.type != .Array {
+ var errorResult_ = JSON.nullJSON
+ errorResult_._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] failure, It is not an array"])
+ return errorResult_
+ }
+
+ let array_ = self.object as [AnyObject]
+
+ if index >= 0 && index < array_.count {
+ return JSON(array_[index])
+ }
+
+ var errorResult_ = JSON.nullJSON
+ errorResult_._error = NSError(domain: ErrorDomain, code:ErrorIndexOutOfBounds , userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] is out of bounds"])
+ return errorResult_
+ }
+ set {
+ if self.type == .Array {
+ var array_ = self.object as [AnyObject]
+ if array_.count > index {
+ array_[index] = newValue.object
+ self.object = array_
+ }
+ }
+ }
+ }
+
+ /// If `type` is `.Dictionary`, return json which's object is `dictionary[key]` , otherwise return null json with error.
+ private subscript(#key: String) -> JSON {
+ get {
+ var returnJSON = JSON.nullJSON
+ if self.type == .Dictionary {
+ if let object_: AnyObject = self.object[key] {
+ returnJSON = JSON(object_)
+ } else {
+ returnJSON._error = NSError(domain: ErrorDomain, code: ErrorNotExist, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] does not exist"])
+ }
+ } else {
+ returnJSON._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Dictionary[\"\(key)\"] failure, It is not an dictionary"])
+ }
+ return returnJSON
+ }
+ set {
+ if self.type == .Dictionary {
+ var dictionary_ = self.object as [String : AnyObject]
+ dictionary_[key] = newValue.object
+ self.object = dictionary_
+ }
+ }
+ }
+
+ /// If `sub` is `Int`, return `subscript(index:)`; If `sub` is `String`, return `subscript(key:)`.
+ private subscript(#sub: SubscriptType) -> JSON {
+ get {
+ if sub is String {
+ return self[key:sub as String]
+ } else {
+ return self[index:sub as Int]
+ }
+ }
+ set {
+ if sub is String {
+ self[key:sub as String] = newValue
+ } else {
+ self[index:sub as Int] = newValue
+ }
+ }
+ }
+
+ /**
+ Find a json in the complex data structuresby using the Int/String's array.
+
+ :param: path The target json's path. Example:
+
+ let json = JSON[data]
+ let path = [9,"list","person","name"]
+ let name = json[path]
+
+ The same as: let name = json[9]["list"]["person"]["name"]
+
+ :returns: Return a json found by the path or a null json with error
+ */
+ public subscript(path: [SubscriptType]) -> JSON {
+ get {
+ if path.count == 0 {
+ return JSON.nullJSON
+ }
+
+ var next = self
+ for sub in path {
+ next = next[sub:sub]
+ }
+ return next
+ }
+ set {
+
+ switch path.count {
+ case 0: return
+ case 1: self[sub:path[0]] = newValue
+ default:
+ var last = newValue
+ var newPath = path
+ newPath.removeLast()
+ for sub in path.reverse() {
+ var previousLast = self[newPath]
+ previousLast[sub:sub] = last
+ last = previousLast
+ if newPath.count <= 1 {
+ break
+ }
+ newPath.removeLast()
+ }
+ self[sub:newPath[0]] = last
+ }
+ }
+ }
+
+ /**
+ Find a json in the complex data structuresby using the Int/String's array.
+
+ :param: path The target json's path. Example:
+
+ let name = json[9,"list","person","name"]
+
+ The same as: let name = json[9]["list"]["person"]["name"]
+
+ :returns: Return a json found by the path or a null json with error
+ */
+ public subscript(path: SubscriptType...) -> JSON {
+ get {
+ return self[path]
+ }
+ set {
+ self[path] = newValue
+ }
+ }
+}
+
+// MARK: - LiteralConvertible
+
+extension JSON: StringLiteralConvertible {
+
+ public init(stringLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+
+ public init(extendedGraphemeClusterLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+
+ public init(unicodeScalarLiteral value: StringLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: IntegerLiteralConvertible {
+
+ public init(integerLiteral value: IntegerLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: BooleanLiteralConvertible {
+
+ public init(booleanLiteral value: BooleanLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: FloatLiteralConvertible {
+
+ public init(floatLiteral value: FloatLiteralType) {
+ self.init(value)
+ }
+}
+
+extension JSON: DictionaryLiteralConvertible {
+
+ public init(dictionaryLiteral elements: (String, AnyObject)...) {
+ var dictionary_ = [String : AnyObject]()
+ for (key_, value) in elements {
+ dictionary_[key_] = value
+ }
+ self.init(dictionary_)
+ }
+}
+
+extension JSON: ArrayLiteralConvertible {
+
+ public init(arrayLiteral elements: AnyObject...) {
+ self.init(elements)
+ }
+}
+
+extension JSON: NilLiteralConvertible {
+
+ public init(nilLiteral: ()) {
+ self.init(NSNull())
+ }
+}
+
+// MARK: - Raw
+
+extension JSON: RawRepresentable {
+
+ public init?(rawValue: AnyObject) {
+ if JSON(rawValue).type == .Unknown {
+ return nil
+ } else {
+ self.init(rawValue)
+ }
+ }
+
+ public var rawValue: AnyObject {
+ return self.object
+ }
+
+ public func rawData(options opt: NSJSONWritingOptions = NSJSONWritingOptions(0), error: NSErrorPointer = nil) -> NSData? {
+ return NSJSONSerialization.dataWithJSONObject(self.object, options: opt, error:error)
+ }
+
+ public func rawString(encoding: UInt = NSUTF8StringEncoding, options opt: NSJSONWritingOptions = .PrettyPrinted) -> String? {
+ switch self.type {
+ case .Array, .Dictionary:
+ if let data = self.rawData(options: opt) {
+ return NSString(data: data, encoding: encoding)
+ } else {
+ return nil
+ }
+ case .String:
+ return (self.object as String)
+ case .Number:
+ return (self.object as NSNumber).stringValue
+ case .Bool:
+ return (self.object as Bool).description
+ case .Null:
+ return "null"
+ default:
+ return nil
+ }
+ }
+}
+
+// MARK: - Printable, DebugPrintable
+
+extension JSON: Printable, DebugPrintable {
+
+ public var description: String {
+ if let string = self.rawString(options:.PrettyPrinted) {
+ return string
+ } else {
+ return "unknown"
+ }
+ }
+
+ public var debugDescription: String {
+ return description
+ }
+}
+
+// MARK: - Array
+
+extension JSON {
+
+ //Optional [JSON]
+ public var array: [JSON]? {
+ get {
+ if self.type == .Array {
+ return map(self.object as [AnyObject]){ JSON($0) }
+ } else {
+ return nil
+ }
+ }
+ }
+
+ //Non-optional [JSON]
+ public var arrayValue: [JSON] {
+ get {
+ return self.array ?? []
+ }
+ }
+
+ //Optional [AnyObject]
+ public var arrayObject: [AnyObject]? {
+ get {
+ switch self.type {
+ case .Array:
+ return self.object as? [AnyObject]
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSMutableArray(array: newValue!, copyItems: true)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+}
+
+// MARK: - Dictionary
+
+extension JSON {
+
+ private func _map(source: [Key: Value], transform: Value -> NewValue) -> [Key: NewValue] {
+ var result = [Key: NewValue](minimumCapacity:source.count)
+ for (key,value) in source {
+ result[key] = transform(value)
+ }
+ return result
+ }
+
+ //Optional [String : JSON]
+ public var dictionary: [String : JSON]? {
+ get {
+ if self.type == .Dictionary {
+ return _map(self.object as [String : AnyObject]){ JSON($0) }
+ } else {
+ return nil
+ }
+ }
+ }
+
+ //Non-optional [String : JSON]
+ public var dictionaryValue: [String : JSON] {
+ get {
+ return self.dictionary ?? [:]
+ }
+ }
+
+ //Optional [String : AnyObject]
+ public var dictionaryObject: [String : AnyObject]? {
+ get {
+ switch self.type {
+ case .Dictionary:
+ return self.object as? [String : AnyObject]
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSMutableDictionary(dictionary: newValue!, copyItems: true)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+}
+
+// MARK: - Bool
+
+extension JSON: BooleanType {
+
+ //Optional bool
+ public var bool: Bool? {
+ get {
+ switch self.type {
+ case .Bool:
+ return self.object.boolValue
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(bool: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ //Non-optional bool
+ public var boolValue: Bool {
+ get {
+ switch self.type {
+ case .Bool, .Number, .String:
+ return self.object.boolValue
+ default:
+ return false
+ }
+ }
+ set {
+ self.object = NSNumber(bool: newValue)
+ }
+ }
+}
+
+// MARK: - String
+
+extension JSON {
+
+ //Optional string
+ public var string: String? {
+ get {
+ switch self.type {
+ case .String:
+ return self.object as? String
+ default:
+ return nil
+ }
+ }
+ set {
+ if newValue != nil {
+ self.object = NSString(string:newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ //Non-optional string
+ public var stringValue: String {
+ get {
+ switch self.type {
+ case .String:
+ return self.object as String
+ case .Number:
+ return self.object.stringValue
+ case .Bool:
+ return (self.object as Bool).description
+ default:
+ return ""
+ }
+ }
+ set {
+ self.object = NSString(string:newValue)
+ }
+ }
+}
+
+// MARK: - Number
+extension JSON {
+
+ //Optional number
+ public var number: NSNumber? {
+ get {
+ switch self.type {
+ case .Number, .Bool:
+ return self.object as? NSNumber
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = newValue?.copy() ?? NSNull()
+ }
+ }
+
+ //Non-optional number
+ public var numberValue: NSNumber {
+ get {
+ switch self.type {
+ case .String:
+ let scanner = NSScanner(string: self.object as String)
+ if scanner.scanDouble(nil){
+ if (scanner.atEnd) {
+ return NSNumber(double:(self.object as NSString).doubleValue)
+ }
+ }
+ return NSNumber(double: 0.0)
+ case .Number, .Bool:
+ return self.object as NSNumber
+ default:
+ return NSNumber(double: 0.0)
+ }
+ }
+ set {
+ self.object = newValue.copy()
+ }
+ }
+}
+
+//MARK: - Null
+extension JSON {
+
+ public var null: NSNull? {
+ get {
+ switch self.type {
+ case .Null:
+ return NSNull()
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = NSNull()
+ }
+ }
+}
+
+//MARK: - URL
+extension JSON {
+
+ //Optional URL
+ public var URL: NSURL? {
+ get {
+ switch self.type {
+ case .String:
+ if let encodedString_ = self.object.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
+ return NSURL(string: encodedString_)
+ } else {
+ return nil
+ }
+ default:
+ return nil
+ }
+ }
+ set {
+ self.object = newValue?.absoluteString ?? NSNull()
+ }
+ }
+}
+
+// MARK: - Int, Double, Float, Int8, Int16, Int32, Int64
+
+extension JSON {
+
+ public var double: Double? {
+ get {
+ return self.number?.doubleValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(double: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var doubleValue: Double {
+ get {
+ return self.numberValue.doubleValue
+ }
+ set {
+ self.object = NSNumber(double: newValue)
+ }
+ }
+
+ public var float: Float? {
+ get {
+ return self.number?.floatValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(float: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var floatValue: Float {
+ get {
+ return self.numberValue.floatValue
+ }
+ set {
+ self.object = NSNumber(float: newValue)
+ }
+ }
+
+ public var int: Int? {
+ get {
+ return self.number?.longValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(integer: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var intValue: Int {
+ get {
+ return self.numberValue.integerValue
+ }
+ set {
+ self.object = NSNumber(integer: newValue)
+ }
+ }
+
+ public var uInt: UInt? {
+ get {
+ return self.number?.unsignedLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uIntValue: UInt {
+ get {
+ return self.numberValue.unsignedLongValue
+ }
+ set {
+ self.object = NSNumber(unsignedLong: newValue)
+ }
+ }
+
+ public var int8: Int8? {
+ get {
+ return self.number?.charValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(char: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int8Value: Int8 {
+ get {
+ return self.numberValue.charValue
+ }
+ set {
+ self.object = NSNumber(char: newValue)
+ }
+ }
+
+ public var uInt8: UInt8? {
+ get {
+ return self.number?.unsignedCharValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedChar: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt8Value: UInt8 {
+ get {
+ return self.numberValue.unsignedCharValue
+ }
+ set {
+ self.object = NSNumber(unsignedChar: newValue)
+ }
+ }
+
+ public var int16: Int16? {
+ get {
+ return self.number?.shortValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(short: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int16Value: Int16 {
+ get {
+ return self.numberValue.shortValue
+ }
+ set {
+ self.object = NSNumber(short: newValue)
+ }
+ }
+
+ public var uInt16: UInt16? {
+ get {
+ return self.number?.unsignedShortValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedShort: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt16Value: UInt16 {
+ get {
+ return self.numberValue.unsignedShortValue
+ }
+ set {
+ self.object = NSNumber(unsignedShort: newValue)
+ }
+ }
+
+ public var int32: Int32? {
+ get {
+ return self.number?.intValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(int: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int32Value: Int32 {
+ get {
+ return self.numberValue.intValue
+ }
+ set {
+ self.object = NSNumber(int: newValue)
+ }
+ }
+
+ public var uInt32: UInt32? {
+ get {
+ return self.number?.unsignedIntValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedInt: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt32Value: UInt32 {
+ get {
+ return self.numberValue.unsignedIntValue
+ }
+ set {
+ self.object = NSNumber(unsignedInt: newValue)
+ }
+ }
+
+ public var int64: Int64? {
+ get {
+ return self.number?.longLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(longLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var int64Value: Int64 {
+ get {
+ return self.numberValue.longLongValue
+ }
+ set {
+ self.object = NSNumber(longLong: newValue)
+ }
+ }
+
+ public var uInt64: UInt64? {
+ get {
+ return self.number?.unsignedLongLongValue
+ }
+ set {
+ if newValue != nil {
+ self.object = NSNumber(unsignedLongLong: newValue!)
+ } else {
+ self.object = NSNull()
+ }
+ }
+ }
+
+ public var uInt64Value: UInt64 {
+ get {
+ return self.numberValue.unsignedLongLongValue
+ }
+ set {
+ self.object = NSNumber(unsignedLongLong: newValue)
+ }
+ }
+}
+
+//MARK: - Comparable
+extension JSON: Comparable {}
+
+public func ==(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) == (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) == (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func <=(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) <= (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) <= (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func >=(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) >= (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) >= (rhs.object as String)
+ case (.Bool, .Bool):
+ return (lhs.object as Bool) == (rhs.object as Bool)
+ case (.Array, .Array):
+ return (lhs.object as NSArray) == (rhs.object as NSArray)
+ case (.Dictionary, .Dictionary):
+ return (lhs.object as NSDictionary) == (rhs.object as NSDictionary)
+ case (.Null, .Null):
+ return true
+ default:
+ return false
+ }
+}
+
+public func >(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) > (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) > (rhs.object as String)
+ default:
+ return false
+ }
+}
+
+public func <(lhs: JSON, rhs: JSON) -> Bool {
+
+ switch (lhs.type, rhs.type) {
+ case (.Number, .Number):
+ return (lhs.object as NSNumber) < (rhs.object as NSNumber)
+ case (.String, .String):
+ return (lhs.object as String) < (rhs.object as String)
+ default:
+ return false
+ }
+}
+
+private let trueNumber = NSNumber(bool: true)
+private let falseNumber = NSNumber(bool: false)
+private let trueObjCType = String.fromCString(trueNumber.objCType)
+private let falseObjCType = String.fromCString(falseNumber.objCType)
+
+// MARK: - NSNumber: Comparable
+
+extension NSNumber: Comparable {
+ var isBool:Bool {
+ get {
+ let objCType = String.fromCString(self.objCType)
+ if (self.compare(trueNumber) == NSComparisonResult.OrderedSame && objCType == trueObjCType) || (self.compare(falseNumber) == NSComparisonResult.OrderedSame && objCType == falseObjCType){
+ return true
+ } else {
+ return false
+ }
+ }
+ }
+}
+
+public func ==(lhs: NSNumber, rhs: NSNumber) -> Bool {
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedSame
+ }
+}
+
+public func !=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+ return !(lhs == rhs)
+}
+
+public func <(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedAscending
+ }
+}
+
+public func >(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) == NSComparisonResult.OrderedDescending
+ }
+}
+
+public func <=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) != NSComparisonResult.OrderedDescending
+ }
+}
+
+public func >=(lhs: NSNumber, rhs: NSNumber) -> Bool {
+
+ switch (lhs.isBool, rhs.isBool) {
+ case (false, true):
+ return false
+ case (true, false):
+ return false
+ default:
+ return lhs.compare(rhs) != NSComparisonResult.OrderedAscending
+ }
+}
+
+//MARK:- Unavailable
+
+@availability(*, unavailable, renamed="JSON")
+public typealias JSONValue = JSON
+
+extension JSON {
+
+ @availability(*, unavailable, message="use 'init(_ object:AnyObject)' instead")
+ public init(object: AnyObject) {
+ self = JSON(object)
+ }
+
+ @availability(*, unavailable, renamed="dictionaryObject")
+ public var dictionaryObjects: [String : AnyObject]? {
+ get { return self.dictionaryObject }
+ }
+
+ @availability(*, unavailable, renamed="arrayObject")
+ public var arrayObjects: [AnyObject]? {
+ get { return self.arrayObject }
+ }
+
+ @availability(*, unavailable, renamed="int8")
+ public var char: Int8? {
+ get {
+ return self.number?.charValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int8Value")
+ public var charValue: Int8 {
+ get {
+ return self.numberValue.charValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt8")
+ public var unsignedChar: UInt8? {
+ get{
+ return self.number?.unsignedCharValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt8Value")
+ public var unsignedCharValue: UInt8 {
+ get{
+ return self.numberValue.unsignedCharValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int16")
+ public var short: Int16? {
+ get{
+ return self.number?.shortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int16Value")
+ public var shortValue: Int16 {
+ get{
+ return self.numberValue.shortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt16")
+ public var unsignedShort: UInt16? {
+ get{
+ return self.number?.unsignedShortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt16Value")
+ public var unsignedShortValue: UInt16 {
+ get{
+ return self.numberValue.unsignedShortValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int")
+ public var long: Int? {
+ get{
+ return self.number?.longValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="intValue")
+ public var longValue: Int {
+ get{
+ return self.numberValue.longValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt")
+ public var unsignedLong: UInt? {
+ get{
+ return self.number?.unsignedLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uIntValue")
+ public var unsignedLongValue: UInt {
+ get{
+ return self.numberValue.unsignedLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int64")
+ public var longLong: Int64? {
+ get{
+ return self.number?.longLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int64Value")
+ public var longLongValue: Int64 {
+ get{
+ return self.numberValue.longLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt64")
+ public var unsignedLongLong: UInt64? {
+ get{
+ return self.number?.unsignedLongLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt64Value")
+ public var unsignedLongLongValue: UInt64 {
+ get{
+ return self.numberValue.unsignedLongLongValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="int")
+ public var integer: Int? {
+ get {
+ return self.number?.integerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="intValue")
+ public var integerValue: Int {
+ get {
+ return self.numberValue.integerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uInt")
+ public var unsignedInteger: Int? {
+ get {
+ return self.number?.unsignedIntegerValue
+ }
+ }
+
+ @availability(*, unavailable, renamed="uIntValue")
+ public var unsignedIntegerValue: Int {
+ get {
+ return self.numberValue.unsignedIntegerValue
+ }
+ }
+}
\ No newline at end of file
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/TMDB.swift b/5 - Completed Project/SwiftMovies/SwiftMovies/TMDB.swift
new file mode 100644
index 0000000..8cc05c7
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/TMDB.swift
@@ -0,0 +1,218 @@
+//
+// TMDB.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import Foundation
+
+let TMDB_API_KEY = "8a4a247d072d9ca4a0072893ab60e277"
+let TMDB_API_BASE_URL = "http://api.themoviedb.org/3"
+let TMDB_IMAGE_BASE_URL = "http://image.tmdb.org/t/p"
+
+// A generic is like a placeholder for type
+// Here we are saying that Result will have an object
+// of some type associated with the Success case
+// but we don't need to specify what type until we use it
+// This lets us reuse the result enum for any object type!
+enum Result {
+ case Success(T)
+ case Failure
+}
+
+// Here we are using a protocol to say that
+// an APIResponse should have a failable initializer
+// that takes in a JSON object (provided by SwiftyJSON)
+protocol APIResponse {
+ init?(json:JSON)
+}
+
+final class TMDB {
+ // The new syntax for #pragma mark gives us a bookmark in the path bar
+ // MARK: MovieResponse
+
+ // We can nest the struct inside the class and access it like TMDB.MovieResponse
+ struct MovieResponse: APIResponse {
+ // We specify the properties we want to be required as constants
+ // And properties we consider optional as optionals
+ let tmdbId: Int
+ let title: String
+ let overview: String?
+ let averageRating: Double?
+ let voteCount: Int?
+ let releaseDate: String?
+ let genres: [String]?
+ let runtime: Int?
+ let posterPath: String?
+ let backdropPath: String?
+
+ // Adding ? to an initializer makes it failable
+ // This means that just like an optional the init
+ // function can return nil
+ // We are doing this here because we don't want it to
+ // be possible to have a Movie without an id and title
+ // this way we never return invalid results
+ init?(json: JSON) {
+ let jsonId = json["id"]
+ let jsonTitle = json["title"]
+ let jsonOverview = json["overview"]
+ let jsonVoteAverage = json["vote_average"]
+ let jsonVoteCount = json["vote_count"]
+ let jsonReleaseDate = json["release_date"]
+ let jsonRuntime = json["runtime"]
+ let jsonPosterPath = json["poster_path"]
+ let jsonBackdropPath = json["backdrop_path"]
+ let jsonGenres = json["genres"]
+
+ // Required fields
+ // If any require fields are missing we want to fail
+ if let id = jsonId.int {
+ self.tmdbId = id
+ } else {
+ return nil
+ }
+
+ if let title = jsonTitle.string {
+ self.title = title
+ } else {
+ return nil
+ }
+
+ // Optional fields
+ // The TMDB api returns "" for a missing string, 0 for a missing int, 0.0 for missing double
+ // As a result we need to process these as we want to be able to set our interface
+ // based on whether these values are really present (and we want those to be invalid)
+ // This could be a bunch of if statements but the ternary operator condenses it
+ // However this is not very readable - this should be replaced with a function that processes the results
+ self.overview = (jsonOverview.stringValue.isEmpty ? nil: jsonOverview.string)
+ self.averageRating = (jsonVoteAverage.doubleValue.isZero ? nil: jsonVoteAverage.double)
+ self.voteCount = (jsonVoteCount.intValue == 0 ? nil: jsonVoteCount.int)
+ self.releaseDate = (jsonReleaseDate.stringValue.isEmpty ? nil: jsonReleaseDate.string)
+ self.runtime = (jsonRuntime.intValue == 0 ? nil: jsonRuntime.int)
+ self.posterPath = (jsonPosterPath.stringValue.isEmpty ? nil: jsonPosterPath.string)
+ self.backdropPath = (jsonBackdropPath.stringValue.isEmpty ? nil: jsonBackdropPath.string)
+
+ if let jsonArray = jsonGenres.array {
+ var genreArray: [String] = []
+
+ for jsonGenre in jsonArray {
+ if let genreString = jsonGenre["name"].string {
+ genreArray.append(genreString)
+ }
+ }
+
+ if !genreArray.isEmpty {
+ self.genres = genreArray
+ }
+ }
+
+ }
+ }
+
+ // MARK: MovieList
+
+ // Enums are very powerful in swift
+ // They can have (non-stored) properties and methods
+ // Enum types can also have non-integer values
+ enum MovieList {
+ case Popular
+ case Upcoming
+ case NowPlaying
+ case TopRated
+
+ static let allLists = [Popular, Upcoming, NowPlaying, TopRated]
+
+ var queryPath: String {
+ switch self {
+ case .Popular:
+ return "popular"
+ case .Upcoming:
+ return "upcoming"
+ case .NowPlaying:
+ return "now_playing"
+ case .TopRated:
+ return "top_rated"
+ }
+ }
+
+ var listName: String {
+ switch self {
+ case .Popular:
+ return "Popular"
+ case .Upcoming:
+ return "Upcoming"
+ case .NowPlaying:
+ return "Now Playing"
+ case .TopRated:
+ return "Top Rated"
+ }
+ }
+ }
+
+ // We use typealiases to avoid typing out long code blocks and to make our parameters more readable
+ typealias MoviesCompletion = (result: Result<[Movie]>) -> Void
+ typealias MovieCompletion = (result: Result) -> Void
+
+ // MARK: Query Methods
+
+ class func fetchMovieList(list: MovieList, completion: MoviesCompletion) {
+ let urlString = "\(TMDB_API_BASE_URL)/movie/\(list.queryPath)?api_key=\(TMDB_API_KEY)"
+
+ let request = NSURLRequest(URL: NSURL(string: urlString)!)
+
+ // This method when passed the Main Queue will execute the completion closure on the Main Thread
+ // Otherwise we would want to get the Main Thread before executing our completion closure
+ // As we are going to be doing our interfaced updates in the completion
+ NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
+ (response:NSURLResponse!, data:NSData!, error:NSError!) -> Void in
+ // SwiftyJSON makes JSON parsing much easier
+ // Otherwise we would need a huge nest of if/let statements
+ // Or we would need to use a more advanced approach (creating our own JSON parser)
+ if data == nil {
+ completion(result: Result.Failure)
+ return
+ }
+
+ let json = JSON(data: data)
+
+ if let results = json["results"].array {
+ var moviesArray: [Movie] = []
+
+ for jsonMovie in results {
+ if let movieResponse = MovieResponse(json: jsonMovie) {
+ let movie = Movie(TMDBResponse: movieResponse)
+ moviesArray.append(movie)
+ }
+ }
+
+ // Our result enum makes error handling a breeze
+ completion(result: Result.Success(moviesArray))
+ return
+ }
+
+ // If we make it here something went wrong
+ completion(result: Result.Failure)
+ }
+ }
+
+ class func fetchMovie(id: Int, completion: MovieCompletion) {
+ let urlString = "\(TMDB_API_BASE_URL)/movie/\(id)?api_key=\(TMDB_API_KEY)"
+ let request = NSURLRequest(URL: NSURL(string: urlString)!)
+
+ NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {
+ (response:NSURLResponse!, data:NSData!, error:NSError!) -> Void in
+ let jsonMovie = JSON(data: data)
+
+ if let movieResponse = MovieResponse(json: jsonMovie) {
+ let movie = Movie(TMDBResponse: movieResponse)
+ completion(result: Result.Success(movie))
+ return
+ }
+
+ // If we make it here something went wrong
+ completion(result: Result.Failure)
+ }
+ }
+}
\ No newline at end of file
diff --git a/5 - Completed Project/SwiftMovies/SwiftMovies/WebViewController.swift b/5 - Completed Project/SwiftMovies/SwiftMovies/WebViewController.swift
new file mode 100644
index 0000000..d4d8d93
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMovies/WebViewController.swift
@@ -0,0 +1,49 @@
+//
+// WebViewController.swift
+// SwiftMovies
+//
+// Created by Tom Piarulli on 1/8/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+
+// Final signifies there will be no subclasses of WebViewController (optimization)
+final class WebViewController: UIViewController {
+ @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
+ @IBOutlet weak var webView: UIWebView!
+
+ var urlString: String?
+ var titleString: String?
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ // Since our titleString and urlString are optionals we have to unwrap them
+ if let title = titleString {
+ self.navigationItem.title = titleString
+ }
+
+ if let urlString = self.urlString {
+ // The NSURL init method returns an optional as well
+ // Its common for Cocoa methods to return optionals (because of Obj-C)
+ if let url = NSURL(string: urlString) {
+ let request = NSURLRequest(URL: url)
+ webView.loadRequest(request)
+ }
+ }
+ }
+}
+
+// Class extensions make it easy to group functionality, like protocol methods
+extension WebViewController: UIWebViewDelegate {
+ // These methods are called automatically when we set the delegate
+ // and adopt the protocol (delegate here is set in storyboard)
+ func webViewDidStartLoad(webView: UIWebView) {
+ self.activityIndicator.startAnimating()
+ }
+
+ func webViewDidFinishLoad(webView: UIWebView) {
+ self.activityIndicator.stopAnimating()
+ }
+}
diff --git a/5 - Completed Project/SwiftMovies/SwiftMoviesTests/Info.plist b/5 - Completed Project/SwiftMovies/SwiftMoviesTests/Info.plist
new file mode 100644
index 0000000..2afc012
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMoviesTests/Info.plist
@@ -0,0 +1,24 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ phillycocoa.$(PRODUCT_NAME:rfc1034identifier)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ BNDL
+ CFBundleShortVersionString
+ 1.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+
+
diff --git a/5 - Completed Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift b/5 - Completed Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift
new file mode 100644
index 0000000..3cb0bdc
--- /dev/null
+++ b/5 - Completed Project/SwiftMovies/SwiftMoviesTests/SwiftMoviesTests.swift
@@ -0,0 +1,36 @@
+//
+// SwiftMoviesTests.swift
+// SwiftMoviesTests
+//
+// Created by Tom Piarulli on 1/5/15.
+// Copyright (c) 2015 Philly Cocoaheads. All rights reserved.
+//
+
+import UIKit
+import XCTest
+
+class SwiftMoviesTests: 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/Slides.pdf b/Slides.pdf
new file mode 100644
index 0000000..eff79ec
Binary files /dev/null and b/Slides.pdf differ