Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
Controller.m
/* |
File:<Controller.m> |
Version: <1.0> |
Disclaimer: IMPORTANT: This Apple software is supplied to you by |
Apple Inc. ("Apple") in consideration of your agreement to the |
following terms, and your use, installation, modification or |
redistribution of this Apple software constitutes acceptance of these |
terms. If you do not agree with these terms, please do not use, |
install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and |
subject to these terms, Apple grants you a personal, non-exclusive |
license, under Apple's copyrights in this original Apple software (the |
"Apple Software"), to use, reproduce, modify and redistribute the Apple |
Software, with or without modifications, in source and/or binary forms; |
provided that if you redistribute the Apple Software in its entirety and |
without modifications, you must retain this notice and the following |
text and disclaimers in all such redistributions of the Apple Software. |
Neither the name, trademarks, service marks or logos of Apple Inc. |
may be used to endorse or promote products derived from the Apple |
Software without specific prior written permission from Apple. Except |
as expressly stated in this notice, no other rights or licenses, express |
or implied, are granted by Apple herein, including but not limited to |
any patent rights that may be infringed by your derivative works or by |
other works in which the Apple Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE |
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION |
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS |
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND |
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL |
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, |
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED |
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), |
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE |
POSSIBILITY OF SUCH DAMAGE. |
Copyright (C) 2008 Apple Inc. All Rights Reserved. |
*/ |
#import "Controller.h" |
/* maximum cache sizes in megabytes */ |
const double kMemoryCacheSize = 50.0; |
const double kDiskCacheSize = 100.0; |
/* Private methods. Instead of declaring them in the header, |
we declare them here in a category that extends the class. */ |
@interface Controller (InternalMethods) |
- (void) createConnectionWithPath:(NSString *)thePath; |
- (void) controlsEnabled:(BOOL)flag; |
- (void) reset; |
- (void) terminate; |
@end |
@implementation Controller |
@synthesize diskPath; |
@synthesize connectionTime; |
@synthesize receivedData; |
@synthesize connection; |
@synthesize loadButton; |
@synthesize clearButton; |
@synthesize comboBox; |
@synthesize sizeField; |
@synthesize timeField; |
@synthesize memoryField; |
@synthesize diskField; |
@synthesize memoryUsage; |
@synthesize diskUsage; |
@synthesize imageView; |
@synthesize progressIndicator; |
@synthesize memoryCacheSlider; |
@synthesize diskCacheSlider; |
/* |
------------------------------------------------------------------------ |
Initialization |
------------------------------------------------------------------------ |
*/ |
- (id)init |
{ |
self = [super init]; |
/* Defines a temporary directory for the on-disk URL cache. */ |
self.diskPath = [[NSMutableString alloc] initWithString:NSTemporaryDirectory()]; |
NSString *appName = [[NSProcessInfo processInfo] processName]; |
[self.diskPath appendString:appName]; |
/* Creates a custom URL cache that uses both memory and disk. */ |
NSURLCache *sharedCache = |
[[NSURLCache alloc] initWithMemoryCapacity:kMemoryCacheSize * 1000000 |
diskCapacity:kDiskCacheSize * 1000000 |
diskPath:diskPath]; |
[NSURLCache setSharedURLCache:sharedCache]; |
[sharedCache release]; |
return self; |
} |
/* Do some UI initialization after loading the nib file. */ |
- (void)awakeFromNib { |
/* Initializes the memory and disk cache sliders. */ |
[self.memoryCacheSlider setMaxValue:kMemoryCacheSize]; |
[self.memoryCacheSlider setDoubleValue:kMemoryCacheSize]; |
[self.diskCacheSlider setMaxValue:kDiskCacheSize]; |
[self.diskCacheSlider setDoubleValue:kDiskCacheSize]; |
[self onMemorySlider:self]; |
[self onDiskSlider:self]; |
/* Initializes the cache usage fields. */ |
[self onClearCache:self]; |
/* Adds list of URLs to the NSComboBox control. */ |
NSString *path = [[NSBundle mainBundle] pathForResource:@"URL" ofType:@"plist"]; |
if (path) { |
NSArray *urlArray = [NSArray arrayWithContentsOfFile:path]; |
[comboBox addItemsWithObjectValues:urlArray]; |
/* Displays the first URL in the list. Also triggers the |
comboBoxSelectionDidChange: notification. */ |
[comboBox selectItemAtIndex:0]; |
} |
} |
- (void)dealloc |
{ |
[diskPath release]; |
[super dealloc]; |
} |
/* |
------------------------------------------------------------------------ |
Action methods that respond to UI events or change the UI |
------------------------------------------------------------------------ |
*/ |
#pragma mark IBAction methods |
- (IBAction)onLoadResource:(id)sender |
{ |
/* starts loading the resource (possibly cached) */ |
[self createConnectionWithPath:[comboBox stringValue]]; |
} |
- (IBAction)onMemorySlider:(id)sender |
{ |
/* displays the memory cache size in megabytes */ |
double value = [self.memoryCacheSlider doubleValue]; |
[self.memoryField setDoubleValue:value]; |
/* set size of memory cache in bytes */ |
NSUInteger memoryCacheSize = value * 1000000; |
[[NSURLCache sharedURLCache] setMemoryCapacity:memoryCacheSize]; |
} |
- (IBAction)onDiskSlider:(id)sender |
{ |
/* displays the disk cache size in megabytes */ |
double value = [self.diskCacheSlider doubleValue]; |
[self.diskField setDoubleValue:value]; |
/* sets size of the disk cache in bytes */ |
NSUInteger diskCacheSize = value * 1000000; |
[[NSURLCache sharedURLCache] setDiskCapacity:diskCacheSize]; |
} |
- (IBAction)onClearCache:(id)sender |
{ |
/* clears the shared cache */ |
NSURLCache *sharedCache = [NSURLCache sharedURLCache]; |
[sharedCache removeAllCachedResponses]; |
/* resets the cache usage fields */ |
[self.memoryUsage setDoubleValue:[sharedCache currentMemoryUsage] / 1000000.0]; |
[self.diskUsage setDoubleValue:[sharedCache currentDiskUsage] / 1000000.0]; |
} |
/* NSResponder sends this message when the user presses Escape or |
Command-Period. To receive this message, we need to be the window |
delegate. */ |
- (IBAction)cancel:(id)sender |
{ |
/* User cancelled operation. If a load operation is in progress, |
we cancel it. */ |
if (self.connection) { |
[self.connection cancel]; |
[self terminate]; |
} |
} |
/* |
------------------------------------------------------------------------ |
Private methods |
------------------------------------------------------------------------ |
*/ |
#pragma mark Internal methods |
/* Used to disable the controls during an uncached load. */ |
- (void)controlsEnabled:(BOOL)flag |
{ |
[comboBox setEnabled:flag]; |
[loadButton setEnabled:flag]; |
[clearButton setEnabled:flag]; |
} |
/* Resets the resource fields. */ |
- (void) reset |
{ |
[self.imageView setImage:nil]; |
[self.sizeField setStringValue:@""]; |
[self.timeField setStringValue:@""]; |
[self.timeField setTextColor:[NSColor blackColor]]; |
} |
/* Called when connection is no longer active. */ |
- (void) terminate |
{ |
/* releases the connection */ |
if (self.connection) { |
[self.connection release]; |
self.connection = nil; |
} |
/* shows the user that loading activity has stopped */ |
[self.progressIndicator stopAnimation:self]; |
[self controlsEnabled:YES]; |
} |
/* Initiates a load request when the user clicks the Load Resource button. |
The URL connection is asynchronous, and we implement a set of delegate |
methods that act as callbacks during the load. */ |
- (void) createConnectionWithPath:(NSString *)thePath |
{ |
/* Creates the URL request. The cache policy specifies that the |
existing cached data should be used to satisfy the request, |
regardless of its age or expiration date. */ |
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:thePath] |
cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:60]; |
/* Finds out if the request response is found in the shared cache. |
If so, displays the elapsed time in gray to indicate a cache hit. */ |
NSURLCache *sharedCache = [NSURLCache sharedURLCache]; |
NSCachedURLResponse *response = [sharedCache cachedResponseForRequest:theRequest]; |
if (response) { |
[timeField setTextColor:[NSColor grayColor]]; |
} |
else { |
[self reset]; |
[self controlsEnabled:NO]; |
[timeField setTextColor:[NSColor blackColor]]; |
} |
/* Creates the URL connection with the request and starts loading the |
data. */ |
self.connection = [[NSURLConnection alloc] initWithRequest:theRequest |
delegate:self startImmediately:YES]; |
if (self.connection) { |
/* record the start time of the connection */ |
self.connectionTime = [NSDate date]; |
/* create an object to hold the received data */ |
self.receivedData = [NSMutableData data]; |
/* show the user that loading activity has begun */ |
[self.progressIndicator startAnimation:self]; |
} |
} |
/* |
------------------------------------------------------------------------ |
NSURLConnection delegate methods for asynchronous requests |
------------------------------------------------------------------------ |
*/ |
#pragma mark NSURLConnection delegate methods |
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response |
{ |
/* Called when the server has determined that it has enough |
information to create the NSURLResponse. It can be called |
multiple times (for example in the case of a redirect), so |
each time we reset the data. */ |
[self.receivedData setLength:0]; |
} |
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data |
{ |
/* appends the new data to the received data */ |
[self.receivedData appendData:data]; |
} |
- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error |
{ |
/* inform the user here */ |
/* logs the error */ |
NSLog(@"Connection failed! Error - %@ %@", |
[error localizedDescription], |
[[error userInfo] objectForKey:NSErrorFailingURLStringKey]); |
/* prepares for a new connection */ |
[self terminate]; |
} |
/* This method demonstrates how to control response caching. Our policy |
is to only cache HTTP requests. If the resource is loaded from the |
shared cache, this method is not called. */ |
- (NSCachedURLResponse *) connection:(NSURLConnection *)connection |
willCacheResponse:(NSCachedURLResponse *)cachedResponse |
{ |
NSCachedURLResponse *newCachedResponse = nil; |
if ([[[[cachedResponse response] URL] scheme] isEqual:@"http"]) { |
newCachedResponse = [[[NSCachedURLResponse alloc] |
initWithResponse:[cachedResponse response] |
data:[cachedResponse data] |
userInfo:nil |
storagePolicy:[cachedResponse storagePolicy]] |
autorelease]; |
} |
return newCachedResponse; |
} |
/* |
------------------------------------------------------------------------ |
connectionDidFinishLoading: |
------------------------------------------------------------------------ |
*/ |
- (void) connectionDidFinishLoading:(NSURLConnection *)connection |
{ |
/* displays the elapsed time in milliseconds */ |
NSTimeInterval elapsedTime = [[NSDate date] timeIntervalSinceDate:self.connectionTime]; |
[self.timeField setDoubleValue:elapsedTime * 1000.0]; |
/* displays length of the received data in bytes */ |
NSUInteger length = [self.receivedData length]; |
[self.sizeField setIntegerValue:length]; |
/* displays memory and disk cache usage in megabytes */ |
NSUInteger currentMemoryUsage = [[NSURLCache sharedURLCache] currentMemoryUsage]; |
[self.memoryUsage setDoubleValue:currentMemoryUsage / 1000000.0]; |
NSUInteger currentDiskUsage = [[NSURLCache sharedURLCache] currentDiskUsage]; |
[self.diskUsage setDoubleValue: currentDiskUsage / 1000000.0]; |
/* assumes the received data is an image and tries to display it */ |
NSImage *theImage = [[NSImage alloc] initWithData:receivedData]; |
if (theImage) { |
[imageView setImage:theImage]; |
[theImage release]; |
} |
[self terminate]; |
} |
/* |
------------------------------------------------------------------------ |
Other delegate methods |
------------------------------------------------------------------------ |
*/ |
#pragma mark Other delegate methods |
/* This NSComboBox delegate method is called when the user selects a |
different URL. We clear the fields that contain the previous connection |
data. */ |
- (void) comboBoxSelectionDidChange:(NSNotification *)notification |
{ |
[self reset]; |
} |
/* This NSApplication delegate method is called when the user closes the |
application window. */ |
- (BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication |
{ |
return YES; |
} |
/* This NSApplication delegate method is called when the application is |
about to terminate. */ |
- (void) applicationWillTerminate:(NSNotification *)aNotification |
{ |
/* deletes the disk cache */ |
[[NSFileManager defaultManager] removeItemAtPath:self.diskPath error:NULL]; |
} |
@end |
Copyright © 2008 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2008-06-05