views:

1696

answers:

5

In short, [NSURL URLWithString:] appears to be raising an exception. According to the documentation "If the string was malformed, returns nil." There is no mention of an exception being raised under any circumstance. In addition to this, I am both encoding the URL and checking for nil before converting the string to a URL.

Can anyone offer any advice as to which exception it could be or what other error checking I should be doing before converting the URL?

In case you're interested in the details, the calling code looks like this:

NSString* tmpText = [newUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
if (tmpText == nil) {
    // error handling
}
else {
    NSURL* tmpURL = [NSURL URLWithString:tmpText];

And this is a section from the crash report download from iTunes Connect:

8   libobjc.A.dylib                 0x300c1f84 objc_exception_throw
9   CoreFoundation                  0x3029a598 +[NSException raise:format:arguments:]
10  CoreFoundation                  0x3029a538 +[NSException raise:format:]
11  Foundation                      0x30696dde -[NSURL initWithString:relativeToURL:]
12  Foundation                      0x30696cd8 +[NSURL URLWithString:relativeToURL:]
13  Foundation                      0x30696cae +[NSURL URLWithString:]
14  Yummy                           0x000146ca -[DeliciousPostCell setUrl:] + 46

It seems that the URL was in a "bad" format somehow but that should really be returning a nil not an exception.

I have never seen the exception being raised myself so I can't use XCode to trap the code and see what's happening. And the user(s) that experienced the problem never contacted me directly so I can't ask for more details. Any suggestions greatly appreciated.

Update (14/7/2009): Seems like such a hack, but I added an exception block around the suspect line. I also raised a Radar bug report (#7031551) suggesting that the code should match the documentation.

+2  A: 

I have encountered some occasions where API throws exceptions that shouldn't according to documentation. My suggestion would be to be to make sure (in your actual code) that tmpText really isn't nil (in that case an exception is thrown, as most apis that expect NSStrings are not nil save there). After that, just add exception handling around it and file a bugreport to bugreporter.apple.com .

dom
+1  A: 

Your string, tmpText, must be somehow malformed (meaning something about it doesn't conform to RFC 2396). Unfortunately, since you cannot get the exact contents of that variable from the user, I can't help you figure out why it's malformed. See this post on Apple's Open Radar for a report filed on similar behavior. I know that report is about passing nil into URLWithString, but if it's treating nil the same as any other malformed string, the behavior (throwing an exception) may be the same.

I would suggest taking a look at how newUrl is created and see if you can find any edge cases where it might be possible that disallowed characters are getting in there. My guess is that's where your problem lies.

Marc W
The Radar report does look very familiar! Thanks for the link.
Stephen Darlington
+1  A: 

It would be worth logging the original value of the string to see what the input to -initWithString: is. One thing to be aware of is that -stringByAddingPercentEscapesUsingEncoding: will only escape characters which are illegal in urls, they aren't context-sensitive in any way. So if the input string is 'http::::host;:', then it won't have any characters escaped, and will remain an invalid URL.

Jim Dovey
Do you think using CFURLCreateStringByAddingPercentEscapes instead of stringByAddingPercentEscapes: would help? I ended up using that in some parts of the code.
Stephen Darlington
The only thing you will gain from using the CF method is that you can specify a list of legal URL characters to escape, which is useful when you're building form-encoded argument lists, or are putting username/password information (which might contain URL formatting characters) into a URL of your own devising.When dealing with user input, it's often better to ask for the components separately, or to trim standard parts of an entered URL string to ensure you have a valid host/path pairing. Then you can use the CF method to sanitize these components before stringing them together.
Jim Dovey
A: 

Can you do a log and see what is present in newUrl and tmpText before using them. That should give you an idea where to start looking.

stringByAddingPercent... won't return a nil ever (unless newUrl is nil).

The URLWithString: call will return a nil if the string passed to it is malformed. So the url object is what you should be watching for nil checks (before calling the openURL: method)

lostInTransit
If URLWithString: was returning nil everything would be fine -- I check for that later on in the code. Unfortunately it's throwing some unknown exception.
Stephen Darlington
A: 

NSURL returns nil for malformed urls, NSLog your string and set breakpoints to see exactly what is being passed to your NSURL creation method. If your URLWithString works with a hard coded value, that's further proof that whatever you are passing is malformed. Be careful with stringByAddingPercentEscapesUsingEncoding and other string methods because they can also add some additional crap that your NSURL recipient might choke on.

Iggy