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.
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
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.
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.
I'm trying to send the contents of UITextView or UITextField as parameters to a php file
NSString *urlstr = [[NSString alloc] initWithFormat:#"http://server.com/file.php?name=%#&tags=%#&entry=%#",nameField.text, tagsField.text, dreamEntry.text];
When i log urlstr, the url format is ok just as long as the UITextView or UITextField don't contain spaces. How would i go about converting the spaces to %20 ?
edit
here is the code at present, which not only crashes but isn't encoding the url properly.
name=John Doe&tags=recurring nightmare&entry=Testing testing testing
is converted to
name=John -1844684964oe&tags=recurringightmare&entry=Testing 4.214929e-307sting -1.992836e+00sting
- (IBAction)sendButtonPressed:(id)sender
{
NSString *urlString = [[NSString alloc] initWithFormat:#"http://server.com/file.php?name=%#&tags=%#&entry=%#", nameField.text, tagsField.text, dreamEntry.text];
NSString *encodedString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [[NSURL alloc] initWithString:encodedString];
NSLog(encodedString);
NSLog(urlString);
[urlString release];
[url release];
[encodedString release];
}
Actually, all of the previous answers contain at least some inaccuracies, which for many common values of user provided text in the TextFields would not correctly communicate with the server
stringByAddingPercentEscapesUsingEncoding: percent escapes all characters which are not valid URL characters. This method should applied once to the entire URL.
A previous answer claims that stringByAddingPercentEscapesUsingEncoding: works like the URL building classes in many scripting languages, where you should not apply it to the entire URL string, but it doesn't. Anyone can easily verify this by checking its output for unescaped &s and ?s. So it is fine to apply to the entire string, but it is not enough to apply to your 'dynamic' url content.
The previous answer is right in that you have to do some more work to the names and values that go into your CGI query string. Since CGI is specified by RFC3875, this is often referred to as RFC3875 percent escaping. It makes sure that your names and values don't contain characters that are valid URL characters but which are significant in other parts of the URL (;, ?, :, #, &, =, $, +, {, }, <, >, and ,)
However, it is very important to also finish by doing plain URL percent escapes on the full string to make sure that all characters in the string are valid URL characters. While you don't in your example, in general there could be characters in a 'static' part of the string which are not valid URL characters, so you do need to escape those as well.
Unfortunately, NSString doesn't give us the power to escape the RFC3875 significant characters so we have to dip down into CFString to do so. Obviously using CFString is a pain so I generally add a Category onto NSString like so:
#interface NSString (RFC3875)
- (NSString *)stringByAddingRFC3875PercentEscapesUsingEncoding:(NSStringEncoding)encoding;
#end
#implementation NSString (RFC3875)
- (NSString *)stringByAddingRFC3875PercentEscapesUsingEncoding:(NSStringEncoding)encoding {
CFStringEncoding cfEncoding = CFStringConvertNSStringEncodingToEncoding(encoding);
NSString *rfcEscaped = (NSString *)CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)self,
NULL,
(CFStringRef)#";/?:#&=$+{}<>,",
cfEncoding);
return [rfcEscaped autorelease];
}
#end
With this Category in place, the original problem could be correctly solved with the following:
NSString *urlEscapedBase = [#"http://server.com/file.php" stringByAddingPercentEscapesUsingEncoding:
NSUTF8StringEncoding];
NSString *rfcEscapedName = [nameField.text stringByAddingRFC3875PercentEscapesUsingEncoding:
NSUTF8StringEncoding];
NSString *rfcEscapedTags = [tagsField.text stringByAddingRFC3875PercentEscapesUsingEncoding:
NSUTF8StringEncoding];
NSString *rfcEscapedEntry = [dreamEntry.text stringByAddingRFC3875PercentEscapesUsingEncoding:
NSUTF8StringEncoding];
NSString *urlStr = [NSString stringWithFormat:#"%#?name=%#&tags=%#&entry=%#",
urlEscapedBase,
rfcEscapedName,
rfcEscapedTags,
rfcEscapedEntry];
NSURL *url = [NSURL URLWithString:urlStr];
This is a little variable heavy just be more clear. Also note that the variable list provided to stringWithFormat: should not be nil terminated. The format string describes the precise number of variables that should follow it. Also, technically the strings for query string names (name, tags, entry,..) should be run through stringByAddingPercentEscapesUsingEncoding: as a matter of course but in this small example we can easily see that they contain no invalid URL characters.
To see why the previous solutions are incorrect, imagine that the user input text in dreamEntry.text contains an &, which is not unlikely. With the previous solutions, all text following that character would be lost by the time the server got that text, since the unescaped ampersand would be interpreted by the server as ending the value portion of that query string pair.
You're not supposed to URL-escape the entire string, you're supposed to URL-escape the dynamic components. Try
NSString *urlStr = [NSString stringWithFormat:#"http://server.com/file.php?name=%#&tags=%#&entry=%#",
[nameField.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
[tagsField.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
[dreamEntry.text stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
nil];
NSURL *url = [NSURL URLWithString:urlStr];
The second issue with your code (and undoubtedly the reason for the odd printing) is you're passing the string directly to NSLog, so it's being treated as a format string. You need to use
NSLog(#"%#", encodedString);
instead. That will make it print as expected.
Edit: A third issue with your code is you're mixing autoreleased and owned objects, then releasing them all at the end. Go look at the 3 objects you create, and which you subsequently release later. One of them shouldn't be released later because it was produced by a method that did not start with the words alloc, copy, or new. Identifying the object in question is an exercise left to the reader.
You can take your URL and use:
NSString *urlStr = [[NSString alloc] initWithFormat:#"http://server.com/file.php?name=%#&tags=%#&entry=%#",nameField.text, tagsField.text, dreamEntry.text];
NSString *encStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];