您的位置:首页 > 其它

Brief Intro to URL Handling of Foundation Framework (Examples: Downloading from a URL)

2013-11-20 10:43 465 查看
URL Handling

The URL handling classes are used for interacting with URLs and communicating with resources using standard Internet protocols (ftp, http, https, local files). The classes provide the following functionality:

URL loading
Cache management
Authentication and credentials management
Cookie management
Protocol support

These classes also support proxy servers and SOCKET Secure (SOCKS) gateways per the user’s system preferences.

URL Loading

NSURL objects are used to manage URLs and the resources they refer to. The class includes methods for creating and initializing NSURL objects,
querying a URL, and accessing the components of a URL (e.g., host, port, etc.). NSURL also provides methods for working
with bookmark data. Abookmark is
a persistent reference to the location of a file. It is a valuable tool for locating files because it can be used to re-create a URL to a file, even if the file is moved or renamed. The following code fragment demonstrates the use of the NSURL APIs
to create an NSURLobject and access its components.
NSURL *url = [NSURL URLWithString:@"http://www.apress.com:80
"];
NSLog(@"URL: scheme %@, host %@, port %@", url.scheme, url.host, url.port);


The classes NSURLRequest and NSMutableURLRequest are
used to represent a URL load request. NSURLRequest is independent of the network protocol and URL scheme. The class includes methods to create and initialize a URL request,
and to retrieve request properties.NSMutableURLRequest is a subclass of NSURLRequest that
provides methods that enable you to change a URL and its component parts. The following statement creates a mutable URL request, and then uses thesetHTTPMethod: method
to set the HTTP request method value.
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:
[NSURL URLWithString:@"http://www.apress.com:80
"]];
[req setHTTPMethod:@"GET"];


NSURLResponse and NSHTTPURLResponse classes
are used to represent the response returned by a URL request. An NSURLConnection object is created by either an object that performs a synchronous load of a URL request
(sendSynchronousRequest:returningResponse:error:) or objects that conform to the NSURLConnectionDataDelegate protocol.
The NSHTTPURLResponse class is a subclass of NSURLResponse that provides methods
for accessing HTTP-specific information returned by a URL request.

The NSURLConnection and NSURLDownload classes
are used to download the contents of a resource identified by a URL. NSURLConnectionsupports synchronous and asynchronous resource loading, starting and stopping a connection,
and managing a delegate object used to control various aspects of a URL connection (i.e., cache management, authentication and credentials, protocol support, and cookie management). For asynchronous loading, a delegate object must be set. This object must
conform to the NSURLConnectionDelegate protocol and thus implement, at a minimum, the following methods:

connection:didReceiveData: (to retrieve data loaded)
connection:didFailWithError: (to handle connection errors
connection:didFinishLoading: (to perform processing after a connection has finished loading
data)

Listing
11-13 demonstrates use of various URL loading APIs to synchronously load the data from a URL.

Listing
11-13. Using NSURLConnection to Synchronously Load the Contents of a URL
NSURL *url = [NSURL URLWithString:@"http://www.apress.com/index.html
"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLResponse *response;
NSError *aerror;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&aerror];
NSLog(@"Expected content length = %lld; loaded %lu bytes",
[response expectedContentLength], [data length]);


As shown in Listing
11-13, the code creates an NSURL instance and then a corresponding NSURLRequest.
It then creates a connection and loads the data using the NSURLConnectionsendSynchronousRequest:returningResponse:error: method. The result is returned in an NSData object.

The NSURLDownload class is used to asynchronously download the contents of a URL to a file. It includes methods to initialize a download (set
request and delegate), set the destination path, resume a partial download, and cancel loading the request. The class also provides support for decoding files stored in the MacBinary, BinHex, and gzip formats. The delegate object must conform to theNSURLDownloadDelegate protocol
and thus implement, at a minimum, the following methods:

download:didFailWithError: (to handle connection errors)
downloadDidFinish: (to perform processing after a connection has finished loading data)

The NSURLDownload class is available for use on the OS X platform only (i.e., this class is not available for the iOS platform).

Cache Management

The cache management classes (NSURLCache and NSCachedURLResponse)
provide a cache memory for responses to URL requests. The NSURLCacheclass provides a general-purpose cache for URLs, whereas theNSCachedURLResponse encapsulates
a URL response (NSURLResponseobject) and the data loaded from the URL (an NSData object).
AnNSURLConnection delegate object implements theconnection:willCacheResponse: method,
providing aNSCachedURLResponse object initialized with an NSURLCache, to manage
caching. How this works is best illustrated by an example; so now you’ll create a program that uses the URL loading classes to download a resource. Let’s begin!

Downloading a Resource with the URL Loading APIs

In Xcode, create a new project by selecting New

Project
. . .
from the Xcode File menu. In the New Project Assistant pane create a command-line application. In the Project Options window, specifyNetConnector for the Product Name, choose Foundation for
the Project Type, and select ARC memory management by selecting the Use Automatic Reference Counting check box. Specify the location in your file system where you want the project to be created (if necessary selectNew Folder and
enter the name and location for the folder), uncheck the Source Control check box, and then click the Create button.

Now you’re going to create a class that downloads a URL resource using the URL loading APIs. Select New

File
. . .
from the Xcode File menu, select the Objective-C class template, and name the classNetConnector. Select the NetConnector folder for the files location and the NetConnector project
as the target, and then click the Createbutton. Next, in the Xcode project navigator pane, select the resulting header file named NetConnector.h and update the interface, as shown in Listing
11-14.

Listing
11-14. NetConnector Interface
#import <Foundation/Foundation.h>
#define HTTP_SCHEME       @"http"
#define CACHE_MEMORY_SIZE (4 * 1024 * 1024)

@interface NetConnector : NSObject <NSURLConnectionDelegate>

@property (readonly) BOOL finishedLoading;

- (id) initWithRequest:(NSURLRequest *)request;
- (void) reloadRequest;

@end


The NetConnector interface adopts the NSURLConnectionDelegateprotocol,
thereby enabling it to asynchronously load data from anNSURLConnection instance. The property finishedLoading is
used to indicate when the NSURLConnection instance is finished loading data. The initWithRequest: method
initializes a NetConnector object and loads a URL using the input NSURLRequest.
The reloadRequest method is used to reload the input NSURLRequest. Now select
theNetConnector.m file and update the implementation, as shown inListing
11-15.

Listing
11-15. NetConnector Implementation
#import "NetConnector.h"

// Extension to declare provide properties
@interface NetConnector()

@property NSURLRequest *request;
@property BOOL finishedLoading;
@property NSURLConnection *connector;
@property NSMutableData *receivedData;

@end

@implementation NetConnector

- (id) initWithRequest:(NSURLRequest *)request
{
if ((self = [super init]))
{
_request = request;
// Create URL cache with appropriate in-memory storage
NSURLCache *URLCache = [[NSURLCache alloc] init];
[URLCache setMemoryCapacity:CACHE_MEMORY_SIZE];
[NSURLCache setSharedURLCache:URLCache];
// Create connection and begin downloading data from resource
_connector = [NSURLConnection connectionWithRequest:request delegate:self];
}
return self;
}

- (void) reloadRequest
{
self.finishedLoading = NO;
self.connector = [NSURLConnection connectionWithRequest:self.request
delegate:self];
}

#pragma mark -
#pragma mark Delegate methods

- (void)connection:(NSURLConnection *)connection
didReceiveResponse:(NSURLResponse *)response
{
if (self.receivedData != nil)
{
[self.receivedData setLength:0];
}
}

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
NSURLResponse *response = [cachedResponse response];
NSURL *url = [response URL];
if ([[url scheme] isEqualTo:HTTP_SCHEME])
{
NSLog(@"Downloaded data, caching response");
return cachedResponse;
}
else
{
NSLog(@"Downloaded data, not caching response");
return nil;
}
}

- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
{
if (self.receivedData != nil)
{
[self.receivedData appendData:data];
}
else
{
self.receivedData = [[NSMutableData alloc] initWithData:data];
}
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSUInteger length = [self.receivedData length];
NSLog(@"Downloaded %lu bytes from request %@", length, self.request);
// Loaded data, set flag to exit run loop
self.finishedLoading = YES;
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"Error loading request %@", [error localizedDescription]);
self.finishedLoading = YES;
}

@end


OK, so I know that this is a lot of code, but don’t worry, you’ll take it one step at a time!. The file begins with a category extension that declares private properties used within the NetConnector implementation.
The implementation defines both the methods declared by the interface and methods declared by the NSURLConnectionDelegate protocol. TheinitWithRequest: method
assigns the input NSURLRequest to the private NetConnector request property, creates
and initializes anNSURLCache instance for caching responses, and ends by creating anNSURLConnection object
and starting the download of the URL. The following statements from Listing
11-15 create the cache, configure it with in-memory storage, and then set it to be the shared cache used with the connection.
NSURLCache *URLCache = [[NSURLCache alloc] init];
[URLCache setMemoryCapacity:CACHE_MEMORY_SIZE];
[NSURLCache setSharedURLCache:URLCache];


The reloadRequest method reloads the URL. It first resets thefinishedLoading flag,
and then creates a new NSURLConnection object with the saved request and downloads the URL.

The remaining methods implemented here areNSURLConnectionDelegate protocol
methods. Theconnection:didReceiveResponse: message
is sent when a connection is able to send a response to the request. As shown in Listing
11-15, this method sets the receivedData object to a length of zero, thereby discarding data received from previous requests.

The connection:willCacheResponse: message is sent before
a connection stores the response in the cache. This enables the method implementation to modify the response or prevent it from being cached. As shown in Listing
11-15, the method performs conditional logic that enables/disables caching of the response based on whether or not the scheme for the URL is http.

The connection:didReceiveData: message is
sent as the data is received from the resource. This method may be called multiple times during a single request if the data is received incrementally. As shown inListing
11-15, the method appends the received data to thereceivedData object.

The connectionDidFinishLoading: message is sent when a connection
has finished loading the data successfully. The method implementation here just logs a message to the output pane, indicating that the connection has finished loading the resource, and then
sets thefinishedLoading flag
used to exit the run loop.

Finally, the connection:didFailWithError: message is sent when a connection fails to load a request successfully. Here you just log a message
to the output pane, indicating the error that occurred, and set the finishedLoading flag.

OK, now that you have implemented the NetConnector class,
let’s use this to load a URL. In the Xcode project navigator, select the main.m file and update the main() function,
as shown in Listing
11-16.

Listing
11-16. NetConnector main( ) Function
#import <Foundation/Foundation.h>
#import "NetConnector.h"

#define INDEX_URL       @"http://www.wikipedia.com/index.html
"

int main(int argc, const char * argv[])
{
@autoreleasepool
{
// Retrieve the current run loop
NSRunLoop *loop = [NSRunLoop currentRunLoop];

// Create the request with specified cache policy, then begin downloading!
NSURLRequest *request = [NSURLRequest
requestWithURL:[NSURL URLWithString:INDEX_URL]
cachePolicy:NSURLRequestReturnCacheDataElseLoad
timeoutInterval:5];
NetConnector *netConnect = [[NetConnector alloc] initWithRequest:request];
// Loop until finished loading the resource (Note the empty statement!)
while (!netConnect.finishedLoading &&
[loop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);

// Log the amount of memory being used by the cache
NSLog(@"Cache memory usage = %lu bytes", [[NSURLCache sharedURLCache]
currentMemoryUsage]);

// Reload data from request, this time it will be retrieved from the cache!
[netConnect reloadRequest];
while (!netConnect.finishedLoading &&
[loop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
// Zero out cache
[[NSURLCache sharedURLCache] removeAllCachedResponses];
}
return 0;
}


The main() function begins by retrieving the current run loop, required for asynchronous URL loading with NSURLConnection objects.
Next, anNSURLRequest instance is created using the convenience constructorrequestWithURL:cachePolicy:timeoutInterval:.
This constructor enables you to select the cache policy for the request. The policyNSURLRequestReturnCacheDataElseLoad specifies
that a cache value should be used (even if out of date) if available; otherwise, the data should be loaded from the resource. Note that if a URL does not support caching, the
data will not be loaded from the cache, even if the policy specifies otherwise. A NetConnector instance is then created using the request and its NSURLConnection object
begins downloading the resource. The next statement is a loop used to keep the application running until the connection has finished loading the resource.
while (!netConnect.finishedLoading &&
[loop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);


Looks familiar, doesn’t it? This loop is identical to the one used for the Bonjour service browser program that you implemented earlier in this chapter. It runs the loop, receiving events from its input sources and executing any
corresponding delegate methods, until the connection has finished loading the resource. The next statement logs the cache memory usage to the output pane, enabling us to view cache utilization. Then you reload the request. As shown in Listing
11-16, the next set of statements reloads the URL. As the data is already stored in the cache and the cache policy specifies that a cache value should be used, it is immediately
retrieved without being loaded from the URL. Finally, the in-memory cache is zeroed out, thereby freeing this memory. Now when you compile and run the NetConnector program, you should observe the messages in the output pane, as shown in Figure
11-2



Figure
11-2. NetConnector program output

.

As shown in the output pane, the response is cached after the data is downloaded. The total amount of data is then logged to the console, along with the URL of the request. Next, the cache memory utilization is output. This is identical
to the data downloaded. The request is then reloaded. Because the response is already in the cache, it is retrieved from there (notice that the delegate methodconnection:willCacheResponse: is
not invoked). OK, that was pretty involved, wasn’t it? Well, you now have a pretty good handle on the use of the URL loading APIs to asynchronously download a URL. Once you’re ready, let’s move on and look
into handling authentication challenges when trying to load a resource.

Authentication and Credentials Management

The authentication and credentials classes ( NSURLProtectionSpace,NSURLCredentialStorage, NSURLCredential,NSURLAuthenticationChallenge,
andNSURLAuthenticationChallengeSender ) provide support for authenticating users requesting access to protected URLs. A resource that requires authentication
requests credentials from a client attempting to load the resource. The Foundation FrameworkNSURLAuthenticationChallenge class
encapsulates a challenge from a server that requires authentication from the client. NSURLCredentialrepresents
an authentication credential returned by a user in response to an authentication challenge. The delegate protocols for NSURLConnectionand NSURLDownload instances
are sent messages when a connection request issues an authentication challenge. The corresponding methods should be implemented to return the appropriate credential.

For the NSURLConnectionDelegate protocol, the messageconnection:willSendRequestForAuthenticationChallenge: should
be implemented to return the appropriate credential. An example implementation of this method for the NetConnector program is shown inListing
11-17.

Listing
11-17. Handling Authentication Challenges
- (void)connection:(NSURLConnection *)connection
willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
NSURLCredential *credential =
[NSURLCredential credentialWithUser:@"TestUser"
password:@"TestPassword"
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:credential
forAuthenticationChallenge:challenge];
}


As shown in Listing
11-17, the method creates a credential with a user name of TestUser and a password of TestPassword;.
TheuseCredential:forAuthenticationChallenge: message
uses this credential to respond to an authentication challenge for the connection.

Cookie Management

The Foundation Framework classes NSHTTPCookie andNSHTTPCookieStorage facilitate
the creation and management of HTTP cookies, which are used to provide persistent storage of data across URL requests.
An NSHTTPCookie instance represents a cookie, andNSHTTPCookieStorage is
a singleton object used to manage cookies. For OS X applications, cookies are shared and kept in sync across processes.Session
cookies are local to a single process and not shared between programs. The NSHTTPCookie class provides methods to create cookies, convert cookies to request headers,
and retrieve cookie properties. TheNSHTTPCookieStorage class provides methods for retrieving the shared cookie storage instance, managing the cookie accept policy, and
managing (i.e., adding, removing, retrieving) cookies.

Protocol Support

The Foundation Framework classes NSURLProtocol andNSURLProtocolClient enable
the creation of custom protocols for loading data from a URL. NSURLProtocol is an abstract class that provides the basic structure to perform protocol-specific URL loading.
It includes methods for creating NSURLProtocol objects, registering/unregistering protocol classes, request management, retrieving protocol attributes, and starting/stopping
downloads.NSURLProtocolClient is a protocol used by NSURLProtocol subclasses to
communicate with the URL loading system.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: