Statistics
| Branch: | Revision:

root / asi-http-request-with-pithos / iPhone Sample / WebPageViewController.m @ be116d22

History | View | Annotate | Download (12.1 kB)

1
//
2
//  WebPageViewController.m
3
//  iPhone
4
//
5
//  Created by Ben Copsey on 03/10/2010.
6
//  Copyright 2010 All-Seeing Interactive. All rights reserved.
7
//
8

    
9
#import "WebPageViewController.h"
10
#import "InfoCell.h"
11
#import "ASIWebPageRequest.h"
12
#import "ASIDownloadCache.h"
13
#import "ToggleCell.h"
14
#import "RequestProgressCell.h"
15

    
16
// Private stuff
17
@interface WebPageViewController ()
18
- (void)webPageFetchFailed:(ASIHTTPRequest *)theRequest;
19
- (void)webPageFetchSucceeded:(ASIHTTPRequest *)theRequest;
20
@end
21

    
22
@implementation WebPageViewController
23

    
24
- (void)fetchWebPage:(id)sender
25
{
26
	[self fetchURL:[NSURL URLWithString:[urlField text]]];
27
}
28

    
29
- (void)clearCache:(id)sender
30
{
31
	[[ASIDownloadCache sharedCache] clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];
32
	[[ASIDownloadCache sharedCache] clearCachedResponsesForStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
33
}
34

    
35
- (void)fetchURL:(NSURL *)url
36
{
37
	[urlField resignFirstResponder];
38

    
39
	[self setRequestsInProgress:[NSMutableArray array]];
40
	[[self tableView] reloadData];
41

    
42
	[request setDelegate:nil];
43
	[request cancel];
44
	[self setRequest:[ASIWebPageRequest requestWithURL:url]];
45

    
46
	[request setDidFailSelector:@selector(webPageFetchFailed:)];
47
	[request setDidFinishSelector:@selector(webPageFetchSucceeded:)];
48
	[request setDelegate:self];
49
	[request setDownloadProgressDelegate:self];
50
	[request setUrlReplacementMode:([replaceURLsSwitch isOn] ? ASIReplaceExternalResourcesWithData : ASIReplaceExternalResourcesWithLocalURLs)];
51
	
52
	// It is strongly recommended that you set both a downloadCache and a downloadDestinationPath for all ASIWebPageRequests
53
	[request setDownloadCache:[ASIDownloadCache sharedCache]];
54
	[request setCachePolicy:ASIOnlyLoadIfNotCachedCachePolicy];
55

    
56
	// This is actually the most efficient way to set a download path for ASIWebPageRequest, as it writes to the cache directly
57
	[request setDownloadDestinationPath:[[ASIDownloadCache sharedCache] pathToStoreCachedResponseDataForRequest:request]];
58
	
59
	[[ASIDownloadCache sharedCache] setShouldRespectCacheControlHeaders:NO];
60
	[request startAsynchronous];
61
}
62

    
63
- (void)webPageFetchFailed:(ASIHTTPRequest *)theRequest
64
{
65
	[responseField setText:[NSString stringWithFormat:@"Something went wrong: %@",[theRequest error]]];
66
}
67

    
68
- (void)webPageFetchSucceeded:(ASIHTTPRequest *)theRequest
69
{
70
	NSURL *baseURL;
71
	if ([replaceURLsSwitch isOn]) {
72
		baseURL = [theRequest url];
73

    
74
	// If we're using ASIReplaceExternalResourcesWithLocalURLs, we must set the baseURL to point to our locally cached file
75
	} else {
76
		baseURL = [NSURL fileURLWithPath:[request downloadDestinationPath]];
77
	}
78

    
79
	if ([theRequest downloadDestinationPath]) {
80
		NSString *response = [NSString stringWithContentsOfFile:[theRequest downloadDestinationPath] encoding:[theRequest responseEncoding] error:nil];
81
		[responseField setText:response];
82
		[webView loadHTMLString:response baseURL:baseURL];
83
	} else {
84
		[responseField setText:[theRequest responseString]];
85
		[webView loadHTMLString:[theRequest responseString] baseURL:baseURL];
86
	}
87
	
88
	[urlField setText:[[theRequest url] absoluteString]];
89
}
90

    
91
// We'll take over the page load when the user clicks on a link
92
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)theRequest navigationType:(UIWebViewNavigationType)navigationType
93
{
94
	if (navigationType == UIWebViewNavigationTypeLinkClicked) {
95
		[self fetchURL:[theRequest URL]];
96
		return NO;
97
	}
98
	return YES;
99
}
100

    
101

    
102
// At time of writing ASIWebPageRequests do not support automatic progress tracking across all requests needed for a page
103
// The code below shows one approach you could use for tracking progress - it creates a new row with a progress indicator for each resource request
104
// However, you could use the same approach and keep track of an overal total to show progress
105
- (void)requestStarted:(ASIWebPageRequest *)theRequest
106
{
107
	[[self requestsInProgress] addObject:theRequest];
108
	[[self tableView] reloadData];
109
}
110

    
111
- (void)requestFinished:(ASIWebPageRequest *)theRequest
112
{
113
	if (![[self requestsInProgress] containsObject:theRequest]) {
114
		[[self requestsInProgress] addObject:theRequest];
115
		[[self tableView] reloadData];	
116
	}
117
}
118

    
119
- (void)request:(ASIHTTPRequest *)theRequest didReceiveBytes:(long long)newLength
120
{
121
	NSInteger requestNumber = [[self requestsInProgress] indexOfObject:theRequest];
122
	if (requestNumber != NSNotFound) {
123
		RequestProgressCell *cell = (RequestProgressCell *)[[self tableView] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:requestNumber inSection:2]];
124
		if ([theRequest contentLength]+[theRequest partialDownloadSize] > 0) {
125
			float progressAmount = (float)(([theRequest totalBytesRead]*1.0)/(([theRequest contentLength]+[theRequest partialDownloadSize])*1.0));
126
			[[cell progressView] setProgress:progressAmount];
127
		}
128
	}
129
}
130

    
131
- (void)request:(ASIHTTPRequest *)theRequest incrementDownloadSizeBy:(long long)newLength
132
{
133
	[self request:theRequest didReceiveBytes:0];
134
}
135

    
136
/*
137
 Most of the code below here relates to the table view, and isn't that interesting
138
 */
139

    
140
- (void)dealloc
141
{
142
	[request setDelegate:nil];
143
	[request setDownloadProgressDelegate:nil];
144
	[request cancel];
145
	[request release];
146
	[webView setDelegate:nil];
147
	[webView release];
148
	[responseField release];
149
	[urlField release];
150
	[requestsInProgress release];
151
	[super dealloc];
152
}
153

    
154
- (void)viewDidLoad
155
{
156
	[super viewDidLoad];
157
	[[[self navigationBar] topItem] setTitle:@"Downloading a Web Page"];
158
	webView = [[UIWebView alloc] initWithFrame:CGRectZero];
159
	[webView setDelegate:self];
160
	responseField = [[UITextView alloc] initWithFrame:CGRectZero];
161
	[responseField setBackgroundColor:[UIColor clearColor]];
162
	[responseField setEditable:NO];
163
	[responseField setText:@"HTML source will appear here"];
164
	urlField = [[UITextField alloc] initWithFrame:CGRectZero];
165
	[urlField setBorderStyle:UITextBorderStyleRoundedRect];
166
	[urlField setText:@"http://allseeing-i.com"];
167
}
168

    
169
static NSString *intro = @"ASIWebPageRequest lets you download complete webpages, including most of their external resources. ASIWebPageRequest can download stylesheets, javascript files, images (including those referenced in CSS), frames, iframes, and HTML 5 audio and video.\r\n\r\nYou can set ASIWebPageRequest to modify HTML and CSS content to point at locally cached external resources, or you can have it replace the urls of external files with their actual data. This lets you save a complete web page as a single file.\r\n\r\nASIWebPageRequest is NOT intended to be a drop-in replacement for UIWebView's regular loading mechanism. It is best used for getting more control over caching web pages you control, or for displaying web page content that requires more complex authentication (eg NTLM).\r\n\r\nIt is strongly recommended that you use ASIWebPageRequest in conjunction with a downloadCache, and you should always set a downloadDestinationPath for all ASIWebPageRequests. ASIWebPageRequests cannot be used with startSynchronous.\r\n\r\nTo use ASIWebPage request, you must link with libxml, and add '${SDK_DIR}/usr/include/libxml2' to your Header Search Paths.";
170

    
171
- (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
172
{
173
	int tablePadding = 40;
174
	int tableWidth = [tableView frame].size.width;
175
	if (tableWidth > 480) { // iPad
176
		tablePadding = 110;
177
	}
178
	
179
	
180
	UITableViewCell *cell;
181
	if ([indexPath section] == 0) {
182
		
183
		cell = [tableView dequeueReusableCellWithIdentifier:@"InfoCell"];
184
		if (!cell) {
185
			cell = [InfoCell cell];	
186
		}
187
		[[cell textLabel] setText:intro];
188
		[cell layoutSubviews];
189
		
190
	} else if ([indexPath section] == 1) {
191
		if ([indexPath row] == 0) {
192
			cell = [tableView dequeueReusableCellWithIdentifier:@"WebPageCell"];
193
			if (!cell) {
194
				cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"WebPageCell"] autorelease];
195
				[[cell contentView] addSubview:webView];
196
			}
197
			[webView setFrame:CGRectMake(10,10,tableWidth-tablePadding,280)];
198
		} else {
199
			cell = [tableView dequeueReusableCellWithIdentifier:@"ToggleCell"];
200
			if (!cell) {
201
				cell = [ToggleCell cell];
202
			}
203
			[[cell textLabel] setText:@"Replace URLs with Data"];
204
			replaceURLsSwitch = [(ToggleCell *)cell toggle];
205

    
206
			// We set our switch to clear the cache when the value is changed
207
			// This is because data cached with ASIReplaceExternalResourcesWithLocalURLs is not suitable for use by other urlReplacementModes
208
			// In your own app, you should basically choose one of these modes, and always use that
209
			[replaceURLsSwitch addTarget:self action:@selector(clearCache:) forControlEvents:UIControlEventValueChanged];
210
		}
211
	} else if ([indexPath section] == 2) {
212

    
213
		cell = [tableView dequeueReusableCellWithIdentifier:@"RequestProgressCell"];
214
		if (!cell) {
215
			cell = [RequestProgressCell cell];
216
		}
217
		ASIHTTPRequest *theRequest = [[self requestsInProgress] objectAtIndex:[indexPath row]];
218
		if ([theRequest didUseCachedResponse]) {
219
			[[cell textLabel] setText:[NSString stringWithFormat:@"Cached: %@",[[theRequest url] absoluteString]]];
220
			[[cell accessoryView] setHidden:YES];
221
			
222
		} else {
223
			[[cell textLabel] setText:[[theRequest url] absoluteString]];
224
			if ([theRequest contentLength] > 0) {
225
				[[(RequestProgressCell *)cell progressView] setProgress:(float)(([theRequest totalBytesRead]*1.0)/(([theRequest contentLength]+[theRequest partialDownloadSize])*1.0))];
226
			}
227
			[[cell accessoryView] setHidden:NO];
228
		}
229

    
230
	} else {
231
		
232
		cell = [tableView dequeueReusableCellWithIdentifier:@"Response"];
233
		if (!cell) {
234
			cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Response"] autorelease];
235
			[[cell contentView] addSubview:responseField];
236
			
237
		}	
238
		[responseField setFrame:CGRectMake(5,5,tableWidth-tablePadding,180)];
239
		
240
	}
241
	[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
242
	return cell;
243
}
244

    
245

    
246
- (UIView *)tableView:(UITableView *)theTableView viewForHeaderInSection:(NSInteger)section
247
{
248
	if (section == 1) {
249
		int tablePadding = 40;
250
		int tableWidth = [tableView frame].size.width;
251
		if (tableWidth > 480) { // iPad
252
			tablePadding = 110;
253
		}
254
		
255
		UIView *view = [[[UIView alloc] initWithFrame:CGRectMake(0,0,tableWidth-(tablePadding/2),30)] autorelease];
256

    
257
		UIButton *clearCacheButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
258
		[clearCacheButton setTitle:@"Clear Cache" forState:UIControlStateNormal];
259
		[clearCacheButton sizeToFit];
260
		[clearCacheButton setFrame:CGRectMake([view frame].size.width-[clearCacheButton frame].size.width+10,7,[clearCacheButton frame].size.width,[clearCacheButton frame].size.height)];
261
		
262
		[clearCacheButton addTarget:self action:@selector(clearCache:) forControlEvents:UIControlEventTouchDown];
263
		[view addSubview:clearCacheButton];
264
		
265
		UIButton *goButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
266
		[goButton setTitle:@"Go!" forState:UIControlStateNormal];
267
		[goButton sizeToFit];
268
		[goButton setFrame:CGRectMake([clearCacheButton frame].origin.x-[goButton frame].size.width-10,7,[goButton frame].size.width,[goButton frame].size.height)];
269
		
270
		
271
		[goButton addTarget:self action:@selector(fetchWebPage:) forControlEvents:UIControlEventTouchDown];
272
		[view addSubview:goButton];
273
		
274
		[urlField setFrame:CGRectMake((tablePadding/2)-10,8,tableWidth-tablePadding-160,34)];
275
		[view addSubview:urlField];
276
		
277
		
278
		return view;
279
	}
280
	return nil;
281
}
282

    
283
- (NSInteger)tableView:(UITableView *)theTableView numberOfRowsInSection:(NSInteger)section
284
{
285
	if (section == 1) {
286
		return 2;
287
	} else if (section == 2) {
288
		return [requestsInProgress count];
289
	}
290
	return 1;
291
}
292

    
293
- (CGFloat)tableView:(UITableView *)theTableView heightForHeaderInSection:(NSInteger)section
294
{
295
	if (section == 1) {
296
		return 50;
297
	}
298
	return 34;
299
}
300

    
301
- (CGFloat)tableView:(UITableView *)theTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
302
{
303
	if ([indexPath section] == 0) {
304
		return [InfoCell neededHeightForDescription:intro withTableWidth:[tableView frame].size.width]+20;
305
	} else if ([indexPath section] == 1) {
306
		if ([indexPath row] == 0) {
307
			return 300;
308
		} else {
309
			return 50;
310
		}
311
	} else if ([indexPath section] == 3) {
312
		return 200;
313
	} else {
314
		return 34;
315
	}
316
}
317

    
318
- (NSString *)tableView:(UITableView *)theTableView titleForHeaderInSection:(NSInteger)section
319
{
320
	return nil;
321
}
322

    
323
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
324
{
325
	return 4;
326
}
327

    
328
@synthesize request;
329
@synthesize requestsInProgress;
330
@end