Say, I have an address bar which is a UITextField called textField, and a UIWebView named webView. Most of the time the follow code works:
[webView loadURL:[NSURL URLWithString:textField.text]];
When I put in some long string with special characters, URLWithString: simply returns null. The Readability bookmarklet is a good example:
javascript:(function(){readConvertLinksToFootnotes=true;readStyle='style-newspaper';readSize='size-medium';readMargin='margin-wide';_readability_script=document.createElement('script');_readability_script.type='text/javascript';_readability_script.src='http://lab.arc90.com/experiments/readability/js/readability.js?x='+(Math.random());document.documentElement.appendChild(_readability_script);_readability_css=document.createElement('link');_readability_css.rel='stylesheet';_readability_css.href='http://lab.arc90.com/experiments/readability/css/readability.css';_readability_css.type='text/css';_readability_css.media='all';document.documentElement.appendChild(_readability_css);_readability_print_css=document.createElement('link');_readability_print_css.rel='stylesheet';_readability_print_css.href='http://lab.arc90.com/experiments/readability/css/readability-print.css';_readability_print_css.media='print';_readability_print_css.type='text/css';document.getElementsByTagName('head')[0].appendChild(_readability_print_css);})();
According to this answer, I can use stringByAddingPercentEscapesUsingEncoding to escape the string, and indeed it works fine for this case.
My question is: Is this safe to always call stringByAddingPercentEscapesUsingEncoding: before passing the string to the webView? Does the following have any consequences?
[webView loadURL:[NSURL URLWithString:[textField.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]
Thanks!
EDIT: What I mean by 'safe' is that while this works with URLs containing Unicode characters, does it still work fine with 'normal' URLs?
EDIT 2: If this is 'safe', why isn't it the default behaviour?
Since there's no other answers to my question, I decided to use the following - (NSURL *)URLValue method instead of - (NSURL *)URLWithString: as a safe measure:
- (NSURL *)URLValue {
NSURL *URL = [NSURL URLWithString:self];
if (URL) return URL;
return [NSURL URLWithString:[self stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
}
No problems. All the returned objects are autoreleased, so no leaks.
Related
I have the following code - note it has to objects with temp, but I will explain.
NSString *temp = _passedOnURL;
NSString *temp = #"http://google.com"; //I comment the one out that I do not use.
NSLog(#"TEMP - %#", temp);
NSURL *feedURL = [NSURL URLWithString:temp];
NSLog(#"FEED URL - %#", feedURL);
The _passedOnURL is a string with the contents passed from a Segue.
Now when I use the 1st temp, the FEED URL returns (null), but when I Log Temp it is still there, so somehow the NSURL does not read the string.
When I hardcode the string with the second temp - there is no issue.
In my mind there is no difference for the NSURL when it is reading the NSString yet, it seems to behave different.
Is there any reason for this??
EDIT
When I do the following code I have no issues:
_passedOnURL = #"http://www.google.com";
so I really have no explanation for this???
try escaping it : [NSURL URLWithString: [temp stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding]]
It seems you have an invalid url string stored in temp. Not every string can be converted to a url but the valid url. Invalid chars and format will lead a nil object after +URLWithString:. So would you let us know what is stored in temp when you try this?
According to the doc for URLWithString:
Parameters
URLString
The string with which to initialize the NSURL object. Must be a URL
that conforms to RFC 2396. This method parses URLString according to
RFCs 1738 and 1808.
Return Value
An NSURL object initialized with URLString. If the string was
malformed, returns nil.
So my guess is that your _passedOnURL is not a valid URL.
I would do a NSLog on your _passedOnURL to check if you are getting the string correctly from the other segue.
In order to obtain URL, I usually follow this way.
NSString *userText = urlText.text;
NSURL *url = [NSURL URLWithString:userText];
Of coursely, urlText is linked with UITextField.
However, Recently, I saw this code in audioStreaming program.
(This is the program.)
NSString *escapedValue =
[(NSString *)CFURLCreateStringByAddingPercentEscapes(nil, (CFStringRef)downloadSourceField.text, NULL, NULL,
kCFStringEncodingUTF8) autorelease];
NSURL *url = [NSURL URLWithString:escapedValue];
downloadSourceField is linked with UITextField.
What is diffence between these two methodes?
When I replaced the second method (escapedValue = ~~~ ) with (escapedValue = downloadSourceField.text;), the program worked well.
Could you let me know what is difference?
And What is the best method to obtain URL for streaming?
The second method will percent-escape some characters which are typically not allowed in URLs. As an example, the space character is not allowed and will be encoded as %20. NSURL does not support passing a string containing a non-allowed character which has not been escaped to +URLWithString:, therefore passing the string through CFURLCreateStringByAddingPercentEscapes first will let you support such URLs.
interesting,
however, digging in the NSString docs you find these two functions:
- (NSString *)stringByReplacingPercentEscapesUsingEncoding:(NSStringEncoding)encoding
- (NSString *)stringByAddingPercentEscapesUsingEncoding:(NSStringEncoding)encoding
I think those are the "official" way of doing this
I have a URL and want to extract part of the string.
The URL is in a similar format to this: www.google.com?id=10&jkhsds=fg.php.
I want to extract the value of id. How would I do this?
If you create an NSURL object, like so:
NSURL *url = [NSURL URLWithString:#"http://www.google.com"];
You can use the methods of the NSURL object to get whatever you need, e.g. scheme, host, port, path, and query.
See here:
http://developer.apple.com/library/mac/#documentation/cocoa/reference/Foundation/Classes/NSURL_Class/Reference/Reference.html
See the NSString class reference. Methods which are likely to be of interest to you include rangeOfString, componentsSeparatedByString, substringFromIndex, and substringToIndex
You can access the string through the absoluteString property of the NSURL class. Then you can extract some parts from the string with methods like
- (NSString *)substringFromIndex:(NSUInteger)anIndex;
- (NSString *)substringToIndex:(NSUInteger)anIndex;
- (NSString *)substringWithRange:(NSRange)aRange;
You might be able to get exactly what you want from various properties of the NSURL class such as baseURL,host,path,query etc...
If your URL is an NSString you can create an NSURL with [NSURL URLWithString:string]
I've been modifying some code to work between Mac OS X and iPhone OS.
I came across some code that was using NSURL's URLByAppendingPathComponent: (added in 10.6), which as some may know, isn't available in the iPhone SDK.
My solution to make this code work between OS's is to use
NSString *urlString = [myURL absoluteString];
urlString = [urlString stringByAppendingPathComponent:#"helloworld"];
myURL = [NSURL urlWithString:urlString];
The problem with this is that NSString's stringByAppendingPathComponent: seems to remove one of the /'s from the http:// part of the URL.
Is this intended behaviour or a bug?
Edit
Ok, So I was a bit too quick in asking the question above. I re-read the documentation and it does say:
Note that this method only works with file paths (not, for example, string representations of URLs)
However, it doesn't give any pointers in the right direction for what to do if you need to append a path component to a URL on the iPhone...
I could always just do it manually, adding a /if necessary and the extra string, but I was looking to keep it as close to the original Mac OS X code as possible...
I would implement a myURLByAppendingPathComponent: method on NSURL that does the same thing. The reason to give it a different name is so it doesn't override the Apple-provided method when Apple gets around to porting the 10.6 API to the iPhone (so the "my" is just an example — the point is that it's unlikely somebody else would write a method with that name).
It seems to me you just want to mess with the path rather than the whole URL. Here's an untested example:
- (NSURL *)myURLByAppendingPathComponent:(NSString *)component {
NSString *newPath = [[self path] stringByAppendingPathComponent:component];
return [[[NSURL alloc] initWithScheme: [self scheme]
host: [self host]
path: newPath]
autorelease];
}
It would only work correctly with URLs that have file-like paths, but I'm pretty sure the Apple method works the same way. At any rate, hopefully it helps you in the right direction.
URLByAppendingPathComponent
Since iOS 4, URLByAppendingPathComponent is available on iOS and handles the two slashes correctly. (OS X had it since 10.6., as Chuck points out)
myURL = [myURL URLByAppendingPathComponent:#"hello world"]
// http://foo/bar/hello%20world
Note that unlike stringByAppendingPathComponent, this method escapes the argument.
URLWithString:relativeToURL:
Alternatively, there is URLWithString:relativeToURL:, which does not escape. So if the url component is already escaped, use:
myURL = [NSURL URLWithString:#"hello%20world" relativeToURL:myURL]
// http://foo/bar/hello%20world
Note that myURL needs to end with a slash here and the added segment must not have a leading slash.
The NSString Reference says this about stringByAppendingPathComponent:
Note that this method only works with
file paths (not, for example, string
representations of URLs).
So, I think it's a case of "Don't Do That".
Use -stringByAppendingString: instead?
There is a simple work around.
Using [NSString stringWithFormat:#"%#/%#", server, file] works fine.
E.g. server : ftp://www.server.com and file : file.txt
+ (NSString *)urlStringPathWithComponents:(NSArray *)paths
{
NSString *url = #"";
for( NSString *item in paths)
{
if([item isEqualToString:paths.firstObject])
{
url = [url stringByAppendingString:[NSString stringWithFormat:#"%#", item]];
}else{
url = [url stringByAppendingString:[NSString stringWithFormat:#"/%#", item]];
}
}
return url;
}
As you see the code above is a class method and this permit use in anywhere without a instance of an object.
Note: Always the first object of the array must be a base url.
it may be very easy, but I don't seems to find out why is URLWithString: returning nil here.
//localisationName is a arbitrary string here
NSString* webName = [localisationName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString* stringURL = [NSString stringWithFormat:#"http://maps.google.com/maps/geo?q=%#,Montréal,Communauté-Urbaine-de-Montréal,Québec,Canadae&output=csv&oe=utf8&sensor=false&key=", webName];
NSURL* url = [NSURL URLWithString:stringURL];
You need to escape the non-ASCII characters in your hardcoded URL as well:
//localisationName is a arbitrary string here
NSString* webName = [localisationName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString* stringURL = [NSString stringWithFormat:#"http://maps.google.com/maps/geo?q=%#,Montréal,Communauté-Urbaine-de-Montréal,Québec,Canadae&output=csv&oe=utf8&sensor=false", webName];
NSString* webStringURL = [stringURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL* url = [NSURL URLWithString:webStringURL];
You can probably remove the escaping of the localisationName since it will be handled by the escaping of the whole string.
Use This Function if you deal with file saved on file manager.
NSURL *_url = [NSURL fileURLWithPath:path];
I guess you need to use -[NSString stringByAddingPercentEscapesUsingEncoding:]. See Apple doc.
Another comment is that, as an old timer, I find it a bit uneasy to put non-ASCII characters in a source file.
That said, this Apple doc says, starting from 10.4, UTF-16 strings are OK inside #"...".
Somehow GCC seems to correctly convert the source file in Latin-1 into UTF-16 in the binary, but I think it's safest to use
7-bit ASCII characters only inside the source code, and use NSLocalizedString.
I think your accented characters are throwing things off; they won't be handled by -stringByAddingPercentEscapesUsingEncoding:.
NSURL URLWithString:#"" will return nil if the URL does not conform to RFC 2396 and they must be escaped
If you read through rfc2396 in the link you will get loads of details
A great site I found for checking where the offending character is, choose the path option for URL
http://www.websitedev.de/temp/rfc2396-check.html.gz
UPDATE:
Since stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding is deprecated now, you should use stringByAddingPercentEncodingWithAllowedCharacters
[stringURL stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
Here's the list of allowed characters set depending on your case.
+ (NSCharacterSet *)URLUserAllowedCharacterSet;
+ (NSCharacterSet *)URLPasswordAllowedCharacterSet;
+ (NSCharacterSet *)URLHostAllowedCharacterSet;
+ (NSCharacterSet *)URLPathAllowedCharacterSet;
+ (NSCharacterSet *)URLQueryAllowedCharacterSet;
+ (NSCharacterSet *)URLFragmentAllowedCharacterSet;
Reference: https://developer.apple.com/reference/foundation/nsstring/1411946-stringbyaddingpercentencodingwit
The URLWithString: call will return a nil if the string passed to it is malformed.
Since 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.see
You can use NSURL directly without NSString.
//.h file
#interface NewsBrowser : UIViewController {
UIWebView *webView;
NSURL *NewsUrl;
}
#property (nonatomic, retain) IBOutlet UIWebView *webView;
#property(nonatomic,assign)NSURL *NewsUrl;
#end
//.m file
[webView loadRequest:[NSURLRequest requestWithURL:NewsUrl]];
And I pass the URL from another view (using NewsUrl variable) to this view.
Try it.