Skip to content

Commit 0741208

Browse files
committed
Added multithreading for network requests. Pull-down to refresh on the main table view.
1 parent d6db92a commit 0741208

File tree

8 files changed

+141
-13
lines changed

8 files changed

+141
-13
lines changed

Diff for: Checklists/.DS_Store

-6 KB
Binary file not shown.

Diff for: SPoT/SPoT.xcodeproj/project.pbxproj

+6
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
BC6F92F616DB8F9600DBEBCA /* RecentPhotosTVC.m in Sources */ = {isa = PBXBuildFile; fileRef = BC6F92F516DB8F9600DBEBCA /* RecentPhotosTVC.m */; };
2525
BC6F92FA16DB939500DBEBCA /* StanfordPhotosTVC.m in Sources */ = {isa = PBXBuildFile; fileRef = BC6F92F916DB939500DBEBCA /* StanfordPhotosTVC.m */; };
2626
BC8B459716DD2173008BE654 /* iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BC8B459616DD2173008BE654 /* iPad.storyboard */; };
27+
BCC2864716DE17CD00D50228 /* NetworkActivity.m in Sources */ = {isa = PBXBuildFile; fileRef = BCC2864616DE17CD00D50228 /* NetworkActivity.m */; };
2728
/* End PBXBuildFile section */
2829

2930
/* Begin PBXFileReference section */
@@ -56,6 +57,8 @@
5657
BC6F92F816DB939500DBEBCA /* StanfordPhotosTVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StanfordPhotosTVC.h; sourceTree = "<group>"; };
5758
BC6F92F916DB939500DBEBCA /* StanfordPhotosTVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StanfordPhotosTVC.m; sourceTree = "<group>"; };
5859
BC8B459616DD2173008BE654 /* iPad.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = iPad.storyboard; sourceTree = "<group>"; };
60+
BCC2864516DE17CD00D50228 /* NetworkActivity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NetworkActivity.h; sourceTree = "<group>"; };
61+
BCC2864616DE17CD00D50228 /* NetworkActivity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NetworkActivity.m; sourceTree = "<group>"; };
5962
/* End PBXFileReference section */
6063

6164
/* Begin PBXFrameworksBuildPhase section */
@@ -113,6 +116,8 @@
113116
BC6F92F516DB8F9600DBEBCA /* RecentPhotosTVC.m */,
114117
BC6F92EF16DB8EEA00DBEBCA /* ImageViewController.h */,
115118
BC6F92F016DB8EEA00DBEBCA /* ImageViewController.m */,
119+
BCC2864516DE17CD00D50228 /* NetworkActivity.h */,
120+
BCC2864616DE17CD00D50228 /* NetworkActivity.m */,
116121
BC6F92DB16DB8D5E00DBEBCA /* iPhone.storyboard */,
117122
BC8B459616DD2173008BE654 /* iPad.storyboard */,
118123
BC6F92E916DB8EEA00DBEBCA /* FlickrFetcher */,
@@ -222,6 +227,7 @@
222227
BC6F92F316DB8EEA00DBEBCA /* ImageViewController.m in Sources */,
223228
BC6F92F616DB8F9600DBEBCA /* RecentPhotosTVC.m in Sources */,
224229
BC6F92FA16DB939500DBEBCA /* StanfordPhotosTVC.m in Sources */,
230+
BCC2864716DE17CD00D50228 /* NetworkActivity.m in Sources */,
225231
);
226232
runOnlyForDeploymentPostprocessing = 0;
227233
};

Diff for: SPoT/SPoT/FlickrFetcher/FlickrFetcher.m

+3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#import "FlickrFetcher.h"
1010
#import "FlickrAPIKey.h"
11+
#import "NetworkActivity.h"
1112

1213
#define FLICKR_PLACE_ID @"place_id"
1314

@@ -18,7 +19,9 @@ + (NSDictionary *)executeFlickrFetch:(NSString *)query
1819
query = [NSString stringWithFormat:@"%@&format=json&nojsoncallback=1&api_key=%@", query, FlickrAPIKey];
1920
query = [query stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
2021
if (NSLOG_FLICKR) NSLog(@"[%@ %@] sent %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), query);
22+
[NetworkActivity addRequest];
2123
NSData *jsonData = [[NSString stringWithContentsOfURL:[NSURL URLWithString:query] encoding:NSUTF8StringEncoding error:nil] dataUsingEncoding:NSUTF8StringEncoding];
24+
[NetworkActivity removeRequest];
2225
NSError *error = nil;
2326
NSDictionary *results = jsonData ? [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves error:&error] : nil;
2427
if (error) NSLog(@"[%@ %@] JSON error: %@", NSStringFromClass([self class]), NSStringFromSelector(_cmd), error.localizedDescription);

Diff for: SPoT/SPoT/ImageViewController.m

+26-8
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88

99
#import "ImageViewController.h"
1010
#import "Utils.h"
11+
#import "NetworkActivity.h"
1112

1213
@interface ImageViewController () <UIScrollViewDelegate>
1314
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
15+
@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *spinner;
1416
@property (strong, nonatomic) UIImageView *imageView;
1517
@end
1618

@@ -35,14 +37,30 @@ - (void)resetImage
3537
self.scrollView.contentSize = CGSizeZero;
3638
self.imageView.image = nil;
3739

38-
NSData *imageData = [[NSData alloc] initWithContentsOfURL:self.imageURL];
39-
UIImage *image = [[UIImage alloc] initWithData:imageData];
40-
if (image) {
41-
self.scrollView.zoomScale = 1.0;
42-
self.scrollView.contentSize = image.size;
43-
self.imageView.image = image;
44-
self.imageView.frame = CGRectMake(0, 0, image.size.width, image.size.height);
45-
}
40+
[self.spinner startAnimating];
41+
NSLog(@"%d", self.spinner.isAnimating);
42+
NSURL *imageURL = self.imageURL;
43+
dispatch_queue_t imageFetchQ = dispatch_queue_create("Image Fetcher", NULL);
44+
dispatch_async(imageFetchQ, ^{
45+
[NetworkActivity addRequest];
46+
NSData *imageData = [[NSData alloc] initWithContentsOfURL:self.imageURL];
47+
[NetworkActivity removeRequest];
48+
UIImage *image = [[UIImage alloc] initWithData:imageData];
49+
if(imageURL == self.imageURL)
50+
{
51+
dispatch_async(dispatch_get_main_queue(), ^{
52+
// Can only do UIKit calls in the main thread.
53+
if (image) {
54+
self.scrollView.zoomScale = 1.0;
55+
self.scrollView.contentSize = image.size;
56+
self.imageView.image = image;
57+
self.imageView.frame = CGRectMake(0, 0, image.size.width, image.size.height);
58+
}
59+
[self.spinner stopAnimating];
60+
NSLog(@"%d", self.spinner.isAnimating);
61+
});
62+
}
63+
});
4664
}
4765
}
4866

Diff for: SPoT/SPoT/NetworkActivity.h

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//
2+
// NetworkActivity.h
3+
// SPoT
4+
//
5+
// Created by Vasco Orey on 2/27/13.
6+
// Copyright (c) 2013 Delta Dog Studios. All rights reserved.
7+
//
8+
9+
#import <Foundation/Foundation.h>
10+
11+
@interface NetworkActivity : NSObject
12+
13+
+(void)addRequest;
14+
+(void)removeRequest;
15+
16+
@end

Diff for: SPoT/SPoT/NetworkActivity.m

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//
2+
// NetworkActivity.m
3+
// SPoT
4+
//
5+
// Created by Vasco Orey on 2/27/13.
6+
// Copyright (c) 2013 Delta Dog Studios. All rights reserved.
7+
//
8+
9+
#import "NetworkActivity.h"
10+
11+
static NetworkActivity *sharedActivity;
12+
13+
@interface NetworkActivity ()
14+
@property (atomic) NSUInteger count;
15+
@end
16+
17+
@implementation NetworkActivity
18+
19+
-(void)setCount:(NSUInteger)count
20+
{
21+
_count = count;
22+
[UIApplication sharedApplication].networkActivityIndicatorVisible = count > 0;
23+
}
24+
25+
-(void)addRequest
26+
{
27+
self.count ++;
28+
}
29+
30+
-(void)removeRequest
31+
{
32+
NSAssert(self.count > 0, @"Seems like you called removeRequest one too many times!");
33+
self.count --;
34+
}
35+
36+
+(NetworkActivity *)sharedActivity
37+
{
38+
if(!sharedActivity)
39+
{
40+
sharedActivity = [[NetworkActivity alloc] init];
41+
}
42+
return sharedActivity;
43+
}
44+
45+
+(void)addRequest
46+
{
47+
[[self sharedActivity] addRequest];
48+
}
49+
50+
+(void)removeRequest
51+
{
52+
[[self sharedActivity] removeRequest];
53+
}
54+
55+
@end

Diff for: SPoT/SPoT/StanfordTagsTVC.m

+17-1
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ -(void)setPhotos:(NSArray *)photos
6464

6565
-(void)getTagInfo
6666
{
67+
self.tagOcurrences = nil;
68+
self.tags = nil;
6769
for(NSDictionary *photo in self.photos)
6870
{
6971
NSArray *separatedTags = [photo[FLICKR_TAGS] componentsSeparatedByString:@" "];
@@ -91,7 +93,21 @@ -(void)getTagInfo
9193
-(void)viewDidLoad
9294
{
9395
[super viewDidLoad];
94-
self.photos = [FlickrFetcher stanfordPhotos];
96+
[self loadLatestPhotosFromFlickr];
97+
[self.refreshControl addTarget:self action:@selector(loadLatestPhotosFromFlickr) forControlEvents:UIControlEventValueChanged];
98+
}
99+
100+
-(void)loadLatestPhotosFromFlickr
101+
{
102+
[self.refreshControl beginRefreshing];
103+
dispatch_queue_t loadingQ = dispatch_queue_create("Loading Queue", NULL);
104+
dispatch_async(loadingQ, ^{
105+
NSArray *latestPhotos = [FlickrFetcher stanfordPhotos];
106+
dispatch_async(dispatch_get_main_queue(), ^{
107+
self.photos = latestPhotos;
108+
[self.refreshControl endRefreshing];
109+
});
110+
});
95111
}
96112

97113
-(NSArray *)photosForTag:(NSString *)tag

Diff for: SPoT/SPoT/en.lproj/iPhone.storyboard

+18-4
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@
6363
</connections>
6464
</tableView>
6565
<navigationItem key="navigationItem" title="SPoT" id="6ou-xq-r9q"/>
66+
<refreshControl key="refreshControl" opaque="NO" multipleTouchEnabled="YES" contentMode="center" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" id="Kcm-NS-TZK">
67+
<autoresizingMask key="autoresizingMask"/>
68+
</refreshControl>
6669
</tableViewController>
6770
<placeholder placeholderIdentifier="IBFirstResponder" id="sz1-x5-15H" userLabel="First Responder" sceneMemberID="firstResponder"/>
6871
</objects>
@@ -108,10 +111,13 @@
108111
</connections>
109112
</tableView>
110113
<navigationItem key="navigationItem" id="YMV-f1-sCA"/>
114+
<refreshControl key="refreshControl" opaque="NO" multipleTouchEnabled="YES" contentMode="center" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" id="Sik-Kf-MeV">
115+
<autoresizingMask key="autoresizingMask"/>
116+
</refreshControl>
111117
</tableViewController>
112118
<placeholder placeholderIdentifier="IBFirstResponder" id="TjZ-nB-Kwn" userLabel="First Responder" sceneMemberID="firstResponder"/>
113119
</objects>
114-
<point key="canvasLocation" x="1077" y="-355"/>
120+
<point key="canvasLocation" x="1078" y="-355"/>
115121
</scene>
116122
<!--Navigation Controller - Highlights-->
117123
<scene sceneID="zQu-mw-OQV">
@@ -186,18 +192,22 @@
186192
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
187193
<subviews>
188194
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="fQs-14-B4v"/>
195+
<activityIndicatorView hidden="YES" opaque="NO" contentMode="scaleToFill" hidesWhenStopped="YES" style="gray" translatesAutoresizingMaskIntoConstraints="NO" id="0H5-NO-MpK"/>
189196
</subviews>
190197
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
191198
<constraints>
192-
<constraint firstItem="fQs-14-B4v" firstAttribute="trailing" secondItem="dsi-cj-yAV" secondAttribute="trailing" type="default" id="6MS-gL-I4C"/>
199+
<constraint firstItem="fQs-14-B4v" firstAttribute="leading" secondItem="dsi-cj-yAV" secondAttribute="leading" type="default" id="1G4-Fz-PaW"/>
200+
<constraint firstItem="0H5-NO-MpK" firstAttribute="centerX" secondItem="fQs-14-B4v" secondAttribute="centerX" type="default" id="FlZ-jh-U1p"/>
193201
<constraint firstItem="fQs-14-B4v" firstAttribute="bottom" secondItem="dsi-cj-yAV" secondAttribute="bottom" type="default" id="Gsv-KR-hWa"/>
194-
<constraint firstItem="fQs-14-B4v" firstAttribute="leading" secondItem="dsi-cj-yAV" secondAttribute="leading" type="default" id="RMb-vw-w5f"/>
202+
<constraint firstItem="fQs-14-B4v" firstAttribute="trailing" secondItem="dsi-cj-yAV" secondAttribute="trailing" type="default" id="YiM-BS-zk4"/>
203+
<constraint firstItem="0H5-NO-MpK" firstAttribute="centerY" secondItem="fQs-14-B4v" secondAttribute="centerY" type="default" id="acI-If-MPU"/>
195204
<constraint firstItem="fQs-14-B4v" firstAttribute="top" secondItem="dsi-cj-yAV" secondAttribute="top" type="default" id="lFj-uN-tRI"/>
196205
</constraints>
197206
</view>
198207
<navigationItem key="navigationItem" id="tX1-4e-ird"/>
199208
<connections>
200209
<outlet property="scrollView" destination="fQs-14-B4v" id="RaS-VI-xjp"/>
210+
<outlet property="spinner" destination="0H5-NO-MpK" id="gWv-Co-FiZ"/>
201211
</connections>
202212
</viewController>
203213
<placeholder placeholderIdentifier="IBFirstResponder" id="oAb-Qd-Smr" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -232,6 +242,7 @@
232242
<source key="sourceIdentifier" type="project" relativePath="./Classes/ImageViewController.h"/>
233243
<relationships>
234244
<relationship kind="outlet" name="scrollView" candidateClass="UIScrollView"/>
245+
<relationship kind="outlet" name="spinner" candidateClass="UIActivityIndicatorView"/>
235246
</relationships>
236247
</class>
237248
<class className="NSLayoutConstraint" superclassName="NSObject">
@@ -246,13 +257,16 @@
246257
<class className="StanfordTagsTVC" superclassName="UITableViewController">
247258
<source key="sourceIdentifier" type="project" relativePath="./Classes/StanfordTagsTVC.h"/>
248259
</class>
260+
<class className="UIRefreshControl" superclassName="UIControl">
261+
<source key="sourceIdentifier" type="project" relativePath="./Classes/UIRefreshControl.h"/>
262+
</class>
249263
</classes>
250264
<simulatedMetricsContainer key="defaultSimulatedMetrics">
251265
<simulatedStatusBarMetrics key="statusBar"/>
252266
<simulatedOrientationMetrics key="orientation"/>
253267
<simulatedScreenMetrics key="destination"/>
254268
</simulatedMetricsContainer>
255269
<inferredMetricsTieBreakers>
256-
<segue reference="FGq-o6-8V5"/>
270+
<segue reference="xiH-IF-OHl"/>
257271
</inferredMetricsTieBreakers>
258272
</document>

0 commit comments

Comments
 (0)