Skip to content

Commit 11d589f

Browse files
committed
Part6
1 parent 70ed338 commit 11d589f

File tree

6 files changed

+200
-32
lines changed

6 files changed

+200
-32
lines changed

SwiftTutorial.xcodeproj/project.pbxproj

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
020BE46319A71EB3006C3E0B /* SwiftTutorialTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 020BE46219A71EB3006C3E0B /* SwiftTutorialTests.swift */; };
1515
020BE46D19A721FF006C3E0B /* APIController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 020BE46C19A721FF006C3E0B /* APIController.swift */; };
1616
020BE46F19A7265F006C3E0B /* Blank52.png in Resources */ = {isa = PBXBuildFile; fileRef = 020BE46E19A7265F006C3E0B /* Blank52.png */; };
17+
0262C60619A729E6003CF464 /* Album.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0262C60519A729E6003CF464 /* Album.swift */; };
18+
0262C60819A72A94003CF464 /* DetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0262C60719A72A94003CF464 /* DetailsViewController.swift */; };
1719
/* End PBXBuildFile section */
1820

1921
/* Begin PBXContainerItemProxy section */
@@ -38,6 +40,8 @@
3840
020BE46219A71EB3006C3E0B /* SwiftTutorialTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftTutorialTests.swift; sourceTree = "<group>"; };
3941
020BE46C19A721FF006C3E0B /* APIController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIController.swift; sourceTree = "<group>"; };
4042
020BE46E19A7265F006C3E0B /* Blank52.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Blank52.png; sourceTree = "<group>"; };
43+
0262C60519A729E6003CF464 /* Album.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = "<group>"; };
44+
0262C60719A72A94003CF464 /* DetailsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailsViewController.swift; sourceTree = "<group>"; };
4145
/* End PBXFileReference section */
4246

4347
/* Begin PBXFrameworksBuildPhase section */
@@ -86,6 +90,8 @@
8690
020BE45319A71EB3006C3E0B /* Main.storyboard */,
8791
020BE45619A71EB3006C3E0B /* Images.xcassets */,
8892
020BE44D19A71EB3006C3E0B /* Supporting Files */,
93+
0262C60519A729E6003CF464 /* Album.swift */,
94+
0262C60719A72A94003CF464 /* DetailsViewController.swift */,
8995
);
9096
path = SwiftTutorial;
9197
sourceTree = "<group>";
@@ -218,6 +224,8 @@
218224
020BE45219A71EB3006C3E0B /* SearchResultsViewController.swift in Sources */,
219225
020BE45019A71EB3006C3E0B /* AppDelegate.swift in Sources */,
220226
020BE46D19A721FF006C3E0B /* APIController.swift in Sources */,
227+
0262C60619A729E6003CF464 /* Album.swift in Sources */,
228+
0262C60819A72A94003CF464 /* DetailsViewController.swift in Sources */,
221229
);
222230
runOnlyForDeploymentPostprocessing = 0;
223231
};
@@ -403,6 +411,7 @@
403411
020BE46819A71EB3006C3E0B /* Release */,
404412
);
405413
defaultConfigurationIsVisible = 0;
414+
defaultConfigurationName = Release;
406415
};
407416
020BE46919A71EB3006C3E0B /* Build configuration list for PBXNativeTarget "SwiftTutorialTests" */ = {
408417
isa = XCConfigurationList;
@@ -411,6 +420,7 @@
411420
020BE46B19A71EB3006C3E0B /* Release */,
412421
);
413422
defaultConfigurationIsVisible = 0;
423+
defaultConfigurationName = Release;
414424
};
415425
/* End XCConfigurationList section */
416426
};

SwiftTutorial/APIController.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ protocol APIControllerProtocol {
1414

1515
class APIController {
1616

17-
var delegate: APIControllerProtocol?
17+
var delegate: APIControllerProtocol
1818

19-
init() {
19+
init(delegate: APIControllerProtocol) {
20+
self.delegate = delegate
2021
}
2122

2223
func searchItunesFor(searchTerm: String) {
@@ -26,7 +27,7 @@ class APIController {
2627

2728
// Now escape anything else that isn't URL-friendly
2829
if let escapedSearchTerm = itunesSearchTerm.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding) {
29-
let urlPath = "http://itunes.apple.com/search?term=\(escapedSearchTerm)&media=software"
30+
let urlPath = "https://itunes.apple.com/search?term=\(escapedSearchTerm)&media=music&entity=album"
3031
let url: NSURL = NSURL(string: urlPath)
3132
let session = NSURLSession.sharedSession()
3233
let task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in
@@ -43,7 +44,7 @@ class APIController {
4344
println("JSON Error \(err!.localizedDescription)")
4445
}
4546
let results: NSArray = jsonResult["results"] as NSArray
46-
self.delegate?.didReceiveAPIResults(jsonResult)
47+
self.delegate.didReceiveAPIResults(jsonResult)
4748

4849
})
4950

SwiftTutorial/Album.swift

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
//
2+
// Album.swift
3+
// SwiftTutorial
4+
//
5+
// Created by Jameson Quave on 8/22/14.
6+
// Copyright (c) 2014 JQ Software LLC. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
class Album {
12+
var title: String
13+
var price: String
14+
var thumbnailImageURL: String
15+
var largeImageURL: String
16+
var itemURL: String
17+
var artistURL: String
18+
19+
init(name: String, price: String, thumbnailImageURL: String, largeImageURL: String, itemURL: String, artistURL: String) {
20+
self.title = name
21+
self.price = price
22+
self.thumbnailImageURL = thumbnailImageURL
23+
self.largeImageURL = largeImageURL
24+
self.itemURL = itemURL
25+
self.artistURL = artistURL
26+
}
27+
28+
class func albumsWithJSON(allResults: NSArray) -> [Album] {
29+
30+
// Create an empty array of Albums to append to from this list
31+
var albums = [Album]()
32+
33+
// Store the results in our table data array
34+
if allResults.count>0 {
35+
36+
// Sometimes iTunes returns a collection, not a track, so we check both for the 'name'
37+
for result in allResults {
38+
39+
var name = result["trackName"] as? String
40+
if name == nil {
41+
name = result["collectionName"] as? String
42+
}
43+
44+
// Sometimes price comes in as formattedPrice, sometimes as collectionPrice.. and sometimes it's a float instead of a string. Hooray!
45+
var price = result["formattedPrice"] as? String
46+
if price == nil {
47+
price = result["collectionPrice"] as? String
48+
if price == nil {
49+
var priceFloat: Float? = result["collectionPrice"] as? Float
50+
var nf: NSNumberFormatter = NSNumberFormatter()
51+
nf.maximumFractionDigits = 2;
52+
if priceFloat != nil {
53+
price = "$"+nf.stringFromNumber(priceFloat)
54+
}
55+
}
56+
}
57+
58+
let thumbnailURL = result["artworkUrl60"] as? String ?? ""
59+
let imageURL = result["artworkUrl100"] as? String ?? ""
60+
let artistURL = result["artistViewUrl"] as? String ?? ""
61+
62+
var itemURL = result["collectionViewUrl"] as? String
63+
if itemURL == nil {
64+
itemURL = result["trackViewUrl"] as? String
65+
}
66+
67+
var newAlbum = Album(name: name!, price: price!, thumbnailImageURL: thumbnailURL, largeImageURL: imageURL, itemURL: itemURL!, artistURL: artistURL)
68+
albums.append(newAlbum)
69+
}
70+
}
71+
return albums
72+
}
73+
74+
}

SwiftTutorial/Base.lproj/Main.storyboard

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2-
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6206.8" systemVersion="13E28" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="vXZ-lx-hvc">
2+
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6206.8" systemVersion="13E28" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="5ke-Z4-Imp">
33
<dependencies>
44
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7026.1"/>
55
</dependencies>
@@ -39,8 +39,14 @@
3939
</label>
4040
</subviews>
4141
</tableViewCellContentView>
42+
<connections>
43+
<segue destination="Nwf-37-TC2" kind="show" id="8Ed-3c-FJj"/>
44+
</connections>
4245
</tableViewCell>
4346
</prototypes>
47+
<variation key="widthClass=compact" fixedFrame="YES">
48+
<rect key="frame" x="0.0" y="0.0" width="400" height="600"/>
49+
</variation>
4450
<connections>
4551
<outlet property="dataSource" destination="vXZ-lx-hvc" id="kG3-L6-sl2"/>
4652
<outlet property="delegate" destination="vXZ-lx-hvc" id="yvw-kU-NYD"/>
@@ -49,12 +55,68 @@
4955
</subviews>
5056
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
5157
</view>
58+
<navigationItem key="navigationItem" id="v1W-Pi-vnb"/>
5259
<connections>
5360
<outlet property="appsTableView" destination="uSB-Wx-Ygo" id="K0F-VR-2Uq"/>
5461
</connections>
5562
</viewController>
5663
<placeholder placeholderIdentifier="IBFirstResponder" id="x5A-6p-PRh" sceneMemberID="firstResponder"/>
5764
</objects>
65+
<point key="canvasLocation" x="768" y="798"/>
66+
</scene>
67+
<!--Details View Controller-->
68+
<scene sceneID="UHq-xC-SWi">
69+
<objects>
70+
<viewController id="Nwf-37-TC2" customClass="DetailsViewController" customModule="SwiftTutorial" customModuleProvider="target" sceneMemberID="viewController">
71+
<layoutGuides>
72+
<viewControllerLayoutGuide type="top" id="Jax-o9-v1A"/>
73+
<viewControllerLayoutGuide type="bottom" id="gK4-fb-m9P"/>
74+
</layoutGuides>
75+
<view key="view" contentMode="scaleToFill" id="gW6-m7-mzX">
76+
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
77+
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
78+
<subviews>
79+
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="hel-WJ-0Op">
80+
<rect key="frame" x="16" y="89" width="100" height="100"/>
81+
</imageView>
82+
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Title Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="7SW-it-u9F">
83+
<rect key="frame" x="149" y="118" width="435" height="42"/>
84+
<fontDescription key="fontDescription" type="system" pointSize="17"/>
85+
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
86+
<nil key="highlightedColor"/>
87+
<variation key="widthClass=compact" fixedFrame="YES">
88+
<rect key="frame" x="133" y="118" width="251" height="42"/>
89+
</variation>
90+
</label>
91+
</subviews>
92+
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
93+
</view>
94+
<connections>
95+
<outlet property="albumCover" destination="hel-WJ-0Op" id="Ans-OY-3NK"/>
96+
<outlet property="titleLabel" destination="7SW-it-u9F" id="rHz-V7-TMF"/>
97+
</connections>
98+
</viewController>
99+
<placeholder placeholderIdentifier="IBFirstResponder" id="Jyv-3h-51E" userLabel="First Responder" sceneMemberID="firstResponder"/>
100+
</objects>
101+
<point key="canvasLocation" x="1417.5" y="798"/>
102+
</scene>
103+
<!--Navigation Controller-->
104+
<scene sceneID="3tg-ke-aa0">
105+
<objects>
106+
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="5ke-Z4-Imp" sceneMemberID="viewController">
107+
<toolbarItems/>
108+
<navigationBar key="navigationBar" contentMode="scaleToFill" id="Oku-16-uyZ">
109+
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
110+
<autoresizingMask key="autoresizingMask"/>
111+
</navigationBar>
112+
<nil name="viewControllers"/>
113+
<connections>
114+
<segue destination="vXZ-lx-hvc" kind="relationship" relationship="rootViewController" id="hMI-GV-FKh"/>
115+
</connections>
116+
</navigationController>
117+
<placeholder placeholderIdentifier="IBFirstResponder" id="gZA-2A-wIT" userLabel="First Responder" sceneMemberID="firstResponder"/>
118+
</objects>
119+
<point key="canvasLocation" x="116" y="798"/>
58120
</scene>
59121
</scenes>
60122
</document>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//
2+
// DetailsViewController.swift
3+
// SwiftTutorial
4+
//
5+
// Created by Jameson Quave on 8/22/14.
6+
// Copyright (c) 2014 JQ Software LLC. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
class DetailsViewController: UIViewController {
12+
13+
var album: Album?
14+
15+
@IBOutlet weak var albumCover: UIImageView!
16+
@IBOutlet weak var titleLabel: UILabel!
17+
18+
required init(coder aDecoder: NSCoder) {
19+
super.init(coder: aDecoder)
20+
}
21+
22+
override func viewDidLoad() {
23+
super.viewDidLoad()
24+
titleLabel.text = self.album?.title
25+
albumCover.image = UIImage(data: NSData(contentsOfURL: NSURL(string: self.album!.largeImageURL)))
26+
}
27+
28+
}

SwiftTutorial/SearchResultsViewController.swift

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,39 +14,37 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa
1414

1515
@IBOutlet var appsTableView : UITableView?
1616
var tableData = []
17-
var api = APIController()
17+
//var api = APIController(delegate: self)
18+
var api : APIController?
1819
var imageCache = [String : UIImage]()
20+
var albums = [Album]()
1921

2022
override func viewDidLoad() {
2123
super.viewDidLoad()
22-
api.searchItunesFor("JQ Software")
23-
api.delegate = self
24+
UIApplication.sharedApplication().networkActivityIndicatorVisible = true
25+
api = APIController(delegate: self)
26+
api!.searchItunesFor("Beatles")
2427
}
2528

2629
/// MARK: UITableViewDataSource, UITableViewDelegate methods
2730
func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
28-
return tableData.count
31+
32+
return albums.count
2933
}
3034

3135
func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
3236

3337
let cell: UITableViewCell = tableView.dequeueReusableCellWithIdentifier(kCellIdentifier) as UITableViewCell
3438

35-
var rowData: NSDictionary = self.tableData[indexPath.row] as NSDictionary
36-
37-
// Add a check to make sure this exists
38-
let cellText: String? = rowData["trackName"] as? String
39-
cell.textLabel.text = cellText
39+
let album = self.albums[indexPath.row]
40+
cell.textLabel.text = album.title
4041
cell.imageView.image = UIImage(named: "Blank52")
4142

42-
4343
// Get the formatted price string for display in the subtitle
44-
let formattedPrice: NSString = rowData["formattedPrice"] as NSString
45-
46-
// Jump in to a background thread to get the image for this item
44+
let formattedPrice = album.price
4745

4846
// Grab the artworkUrl60 key to get an image URL for the app's thumbnail
49-
let urlString = rowData["artworkUrl60"] as String
47+
let urlString = album.thumbnailImageURL
5048

5149
// Check our image cache for the existing key. This is just a dictionary of UIImages
5250
var image = self.imageCache[urlString]
@@ -87,26 +85,21 @@ class SearchResultsViewController: UIViewController, UITableViewDataSource, UITa
8785
return cell
8886
}
8987

88+
// The APIControllerProtocol method
9089
func didReceiveAPIResults(results: NSDictionary) {
9190
var resultsArr: NSArray = results["results"] as NSArray
9291
dispatch_async(dispatch_get_main_queue(), {
93-
self.tableData = resultsArr
92+
self.albums = Album.albumsWithJSON(resultsArr)
9493
self.appsTableView!.reloadData()
94+
UIApplication.sharedApplication().networkActivityIndicatorVisible = false
9595
})
9696
}
9797

98-
func tableView(tableView: UITableView!, didSelectRowAtIndexPath indexPath: NSIndexPath!) {
99-
// Get the row data for the selected row
100-
var rowData: NSDictionary = self.tableData[indexPath.row] as NSDictionary
101-
102-
var name: String = rowData["trackName"] as String
103-
var formattedPrice: String = rowData["formattedPrice"] as String
104-
105-
var alert: UIAlertView = UIAlertView()
106-
alert.title = name
107-
alert.message = formattedPrice
108-
alert.addButtonWithTitle("Ok")
109-
alert.show()
98+
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject) {
99+
var detailsViewController: DetailsViewController = segue.destinationViewController as DetailsViewController
100+
var albumIndex = appsTableView!.indexPathForSelectedRow().row
101+
var selectedAlbum = self.albums[albumIndex]
102+
detailsViewController.album = selectedAlbum
110103
}
111104

112105

0 commit comments

Comments
 (0)