This is my URL
.
The problem is, that the address
field is not being appended to urlpath
.
Does anyone know why that is?
var address:string
address = "American Tourister, Abids Road, Bogulkunta, Hyderabad, Andhra Pradesh, India"
let urlpath = NSString(format: "http://maps.googleapis.com/maps/api/geocode/json?address="+"\(address)")
Adding to Bryan Chen's answer above:
Just incase anyone else is getting something similar with Alamofire:
error: Alamofire was compiled with optimization - stepping may behave oddly; variables may not be available.
It's not a very descriptive error. I was getting that error when constructing a URL for google geo services. I was appending a street address to the end of the URL WITHOUT encoding the street address itself first. I was able to fix it using Bryan Chen's solution:
var streetAdress = "123 fake street, new york, ny"
var escapedStreetAddress = streetAddress.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())
let url = "\(self.baseUrl)&address=\(escapedAddress!)"
That fixed it for me! It didnt like that the address had spaces and commas, etc.
Hope this helps someone else!
Updated for Swift 3:
var escapedAddress = address.addingPercentEncoding(
withAllowedCharacters: CharacterSet.urlQueryAllowed)
In Mac OS 10.9 Maverics and iOS 7 NSURLComponents
has been introduced which handles the encoding of the different URL parts in a pretty convenient way.
The NSURLComponents class is a class that is designed to parse URLs based on RFC 3986 and to construct URLs from their constituent parts. Its behavior differs subtly from the NSURL class, which conforms to older RFCs. However, you can easily obtain an NSURL object based on the contents of a URL components object or vice versa.
let address = "American Tourister, Abids Road, Bogulkunta, Hyderabad, Andhra Pradesh, India"
let components = NSURLComponents(string: "http://maps.googleapis.com/maps/api/geocode/json")!
// create a query item key=value
let queryItem = NSURLQueryItem(name: "address", value: address)
// add the query item to the URL, NSURLComponents takes care of adding the question mark.
components.queryItems = [queryItem]
// get the properly percent encoded string
let urlpath = components.string!
print(urlpath)
I needed to encode my parameters with ISO-8859-1, so the addingPercentEncoding() method doesn't work for me. I made a solution my self in Swift 4:
extension String {
// Url percent encoding according to RFC3986 specifications
// https://tools.ietf.org/html/rfc3986#section-2.1
func urlPercentEncoded(withAllowedCharacters allowedCharacters:
CharacterSet, encoding: String.Encoding) -> String {
var returnStr = ""
// Compute each char seperatly
for char in self {
let charStr = String(char)
let charScalar = charStr.unicodeScalars[charStr.unicodeScalars.startIndex]
if allowedCharacters.contains(charScalar) == false,
let bytesOfChar = charStr.data(using: encoding) {
// Get the hexStr of every notAllowed-char-byte and put a % infront of it, append the result to the returnString
for byte in bytesOfChar {
returnStr += "%" + String(format: "%02hhX", byte as CVarArg)
}
} else {
returnStr += charStr
}
}
return returnStr
}
}
Usage:
"aouäöü!".urlPercentEncoded(withAllowedCharacters: .urlQueryAllowed,
encoding: .isoLatin1)
// Results in -> "aou%E4%F6%FC!"
Swift 2.0
let needsLove = "string needin some URL love"
let safeURL = needsLove.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
In my case where the last component was non latin characters I did the following in Swift 2.2
:
extension String {
func encodeUTF8() -> String? {
//If I can create an NSURL out of the string nothing is wrong with it
if let _ = NSURL(string: self) {
return self
}
//Get the last component from the string this will return subSequence
let optionalLastComponent = self.characters.split { $0 == "/" }.last
if let lastComponent = optionalLastComponent {
//Get the string from the sub sequence by mapping the characters to [String] then reduce the array to String
let lastComponentAsString = lastComponent.map { String($0) }.reduce("", combine: +)
//Get the range of the last component
if let rangeOfLastComponent = self.rangeOfString(lastComponentAsString) {
//Get the string without its last component
let stringWithoutLastComponent = self.substringToIndex(rangeOfLastComponent.startIndex)
//Encode the last component
if let lastComponentEncoded = lastComponentAsString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.alphanumericCharacterSet()) {
//Finally append the original string (without its last component) to the encoded part (encoded last component)
let encodedString = stringWithoutLastComponent + lastComponentEncoded
//Return the string (original string/encoded string)
return encodedString
}
}
}
return nil;
}
}
Swift 4.1
Create a "Character Set" based on the option you want (urlQueryAllowed). Then remove the additional characters you do not want (+&). Then pass that character set to "addingPercentEncoding".
var address = "American Tourister, Abids Road, Bogulkunta, Hyderabad, Andhra Pradesh, India"
var queryCharSet = NSCharacterSet.urlQueryAllowed
queryCharSet.remove(charactersIn: "+&")
let escapedAddress = address.addingPercentEncoding(withAllowedCharacters: queryCharSet)!
let urlpath = String(format: "http://maps.googleapis.com/maps/api/geocode/json?address=\(escapedAddress)")
var urlString = originalString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
var address = "American Tourister, Abids Road, Bogulkunta, Hyderabad, Andhra Pradesh, India"
let escapedAddress = address.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
let urlpath = String(format: "http://maps.googleapis.com/maps/api/geocode/json?address=\(escapedAddress)")
Use stringByAddingPercentEncodingWithAllowedCharacters
:
var escapedAddress = address.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())
Use Deprecated in iOS 9 and OS X v10.11stringByAddingPercentEscapesUsingEncoding:
var address = "American Tourister, Abids Road, Bogulkunta, Hyderabad, Andhra Pradesh, India"
var escapedAddress = address.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
let urlpath = NSString(format: "http://maps.googleapis.com/maps/api/geocode/json?address=\(escapedAddress)")
Swift 3:
let escapedString = originalString.addingPercentEncoding(withAllowedCharacters:NSCharacterSet.urlQueryAllowed)
If it's possible that the value that you're adding to your URL can have reserved characters (as defined by section 2 of RFC 3986), you might have to refine your percent-escaping. Notably, while &
and +
are valid characters in a URL, they're not valid within a URL query parameter value (because &
is used as delimiter between query parameters which would prematurely terminate your value, and +
is translated to a space character). Unfortunately, the standard percent-escaping leaves those delimiters unescaped.
Thus, you might want to percent escape all characters that are not within RFC 3986's list of unreserved characters:
Characters that are allowed in a URI but do not have a reserved purpose are called unreserved. These include uppercase and lowercase letters, decimal digits, hyphen, period, underscore, and tilde.
unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
Later, in section 3.4, the RFC further contemplates adding ?
and /
to the list of allowed characters within a query:
The characters slash ("/") and question mark ("?") may represent data within the query component. Beware that some older, erroneous implementations may not handle such data correctly when it is used as the base URI for relative references (Section 5.1), apparently because they fail to distinguish query data from path data when looking for hierarchical separators. However, as query components are often used to carry identifying information in the form of "key=value" pairs and one frequently used value is a reference to another URI, it is sometimes better for usability to avoid percent- encoding those characters.
Nowadays, you'd generally use URLComponents
to percent escape the query value:
var address = "American Tourister, Abids Road, Bogulkunta, Hyderabad, Andhra Pradesh, India"
var components = URLComponents(string: "http://maps.googleapis.com/maps/api/geocode/json")!
components.queryItems = [URLQueryItem(name: "address", value: address)]
let url = components.url!
By the way, while it's not contemplated in the aforementioned RFC, section 5.2, URL-encoded form data, of the W3C HTML spec says that application/x-www-form-urlencoded
requests should also replace space characters with +
characters (and includes the asterisk in the characters that should not be escaped). And, unfortunately, URLComponents
won't properly percent escape this, so Apple advises that you manually percent escape it before retrieving the url
property of the URLComponents
object:
// configure `components` as shown above, and then:
components.percentEncodedQuery = components.percentEncodedQuery?.replacingOccurrences(of: "+", with: "%2B")
let url = components.url!
For Swift 2 rendition, where I manually do all of this percent escaping myself, see the previous revision of this answer.
Just completing Desmond Hume's answer to extend the String class for a RFC 3986 unreserved characters valid encoding function (needed if you are encoding query FORM parameters):
extension String {
var RFC3986UnreservedEncoded:String {
let unreservedChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
let unreservedCharsSet: CharacterSet = CharacterSet(charactersIn: unreservedChars)
let encodedString: String = self.addingPercentEncoding(withAllowedCharacters: unreservedCharsSet)!
return encodedString
}
}
XCODE 8, SWIFT 3.0
From grokswift
Creating URLs from strings is a minefield for bugs. Just miss a single / or accidentally URL encode the ? in a query and your API call will fail and your app won’t have any data to display (or even crash if you didn’t anticipate that possibility). Since iOS 8 there’s a better way to build URLs using NSURLComponents
and NSURLQueryItems
.
func createURLWithComponents() -> URL? {
var urlComponents = URLComponents()
urlComponents.scheme = "http"
urlComponents.host = "maps.googleapis.com"
urlComponents.path = "/maps/api/geocode/json"
let addressQuery = URLQueryItem(name: "address", value: "American Tourister, Abids Road, Bogulkunta, Hyderabad, Andhra Pradesh, India")
urlComponents.queryItems = [addressQuery]
return urlComponents.url
}
Below is the code to access url using guard
statement.
guard let url = createURLWithComponents() else {
print("invalid URL")
return nil
}
print(url)
Output:
http://maps.googleapis.com/maps/api/geocode/json?address=American%20Tourister,%20Abids%20Road,%20Bogulkunta,%20Hyderabad,%20Andhra%20Pradesh,%20India
Read More: Building URLs With NSURLComponents and NSURLQueryItems
URLQueryAllowedCharacterSet
should not be used for URL encoding of query parameters because this charset includes &
, ?
, /
etc. which serve as delimiters in a URL query, e.g.
/?paramname=paramvalue¶mname=paramvalue
These characters are allowed in URL queries as a whole but not in parameter values.
RFC 3986 specifically talks about unreserved characters, which are different from allowed:
2.3. Unreserved Characters
Characters that are allowed in a URI but do not have a reserved
purpose are called unreserved. These include uppercase and lowercase letters, decimal digits, hyphen, period, underscore, and tilde.unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
Accordingly:
extension String {
var URLEncoded:String {
var URLEncoded:String {
let unreservedChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
let unreservedCharsSet: CharacterSet = CharacterSet(charactersIn: unreservedChars)
let encodedString = self.addingPercentEncoding(withAllowedCharacters: unreservedCharsSet)!
return encodedString
}
}
}
The code above doesn't make a call to alphanumericCharacterSet
because of the enormous size of the charset it returns (103806 characters). And in view of how many Unicode characters alphanumericCharacterSet
allows for, using it for the purpose of URL encoding would be simply erroneous.
Usage:
let URLEncodedString = myString.URLEncoded
Source: Stackoverflow.com