views:

802

answers:

2

I'm using NSURLConnection as listed below. I have three questions about this class. When I concatenate the url value, the debugger hits this line twice but not the line above it:

if (theConnection){

The second time I get EXC_BAD_ACCESS. Using the first url assignment (commented out) works fine.

1.) What's the difference?

- (void)applicationDidFinishLaunching:(UIApplication *)application {

//NSString *url = @"http://www.abc.com/afile.mp4";

NSString *temp = @"afile.mp4";
NSString *url = [@"http://www.abc.com/" stringByAppendingString:temp];

theRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] 
          cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30.0];
[url release]; 

NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
 receivedData=[[NSMutableData data] retain];
}

2.) If I change the file name to afile.mp, the request goes through and [receivedData length] has a value of around 1600 when

    - (void)connectionDidFinishLoading:(NSURLConnection   *)connection

gets hit. Is there a way to accurately check if receivedData has the actual data you are requesting. The target file is about 7MB but can vary from 1.5MB to 9MB. The resource I requested wasn't there but does anything indicate that?

3.) I'm doing this in my app delegate. The only protocol there is UIApplicationDelegate. How do all of the NSURLConnection methods work if there isn't a delegate for them?

+3  A: 

1.) What's the difference?

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    //NSString *url = @"http://www.abc.com/afile.mp4";
    NSString *temp = @"afile.mp4";
    NSString *url = [@"http://www.abc.com/" stringByAppendingString:temp];

    theRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] 
                                                                             cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30.0];
    [url release];

The difference is that one of these lets you get away with releasing something you don't own and the other doesn't.

You didn't alloc it, copy it, or retain it, so you don't own it, so don't release it.

As an implementation detail, string literals don't implement reference-counting. String literal objects will ignore you when you try to retain or release them. That's why the version where you release a string literal doesn't crash, and the version where you create a new string and release that does. But this is an implementation detail—don't rely on it for anything. Always assume that releasing something you don't own will cause a crash.

Is there a way to accurately check if receivedData has the actual data you are requesting.

As opposed to an error document? Check the response code.

As opposed to some other data? You could use hashes, although how you determine the correct hash to expect would be up to you. However, it's probably easier to just have faith that the server won't give you the wrong file.

The resource I requested wasn't there but does anything indicate that?

Yes. Implement connection:didReceiveResponse: and check the response code.

Note that if the server is using mod_speling or something similar, it may correct your URL instead of returning an error—for example, by changing the “afile.mp” that you requested to the “afile.mp4” that actually exists.

3.) I'm doing this in my app delegate. The only protocol there is UIApplicationDelegate. How do all of the NSURLConnection methods work if there isn't a delegate for them?

You said delegate:self, so you're the connection's delegate.

On the Mac, at least, NSURLConnection categories the methods onto NSObject, so they're always available, at least in no-op form. You override these implementations, so when NSURLConnection sends your connection delegate (you) those messages, they go through to the implementations you provided.

Peter Hosey
1.) How is it able to do that? Neither alloc. 2.) When you say response code, do you mean suggestedFileName or MIMEType? Don't see responsecode. 3.) Cool - where is that documented? Thanks.
4thSpace
1. As I said, the ref-counting methods are no-ops on a string literal object. But don't rely on that. Also, as I said, I know you didn't alloc: That's why you shouldn't release it. 2. No, I meant response code. Implement the delegate method I told you about. 3. In the NSURLConnection documentation.
Peter Hosey
Once you have the response object (in the delegate method), you'll send it the statusCode message to get the response code. http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSHTTPURLResponse_Class/Reference/Reference.html#//apple_ref/occ/instm/NSHTTPURLResponse/statusCode
Peter Hosey
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response doesn't have a statusCode. That's in NSHTTPURLResponse, which I'm not using. What do you mean?
4thSpace
I mean exactly what you thought I meant. That response object is an NSHTTPURLResponse any time you're using HTTP, as documented (somewhat obliquely) in http://developer.apple.com/documentation/Cocoa/Conceptual/URLLoadingSystem/Concepts/URLOverview.html .
Peter Hosey
Simple answer: NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; statusCode = [httpResponse statusCode];
4thSpace
Yup. You have it now. ☺ If your actual application is more generic, accepting URLs from schemes other than HTTP (such as FTP), you should make that code conditional upon a respondsToSelector: message.
Peter Hosey
A: 

NSURLConnection predates the ability to specify a @protocol with optional methods. So instead they use what is known as an informal protocol (a category on NSObject). The end result is that you just call -setDelegate: and implement the right methods as per normal.

Mike Abdullah