Attempting to get data on the S&P500 (symbol: ^GSPC) from Yahoo Finance. In playgrounds and scripts, the presence of a caret (^) in the string passed to NSURL errors with "Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_1386_INVOP, sub code=0x0)". Xcode 6b6 and b7.
Works fine with other ticker symbols (AAPL, MSFT, etc).
Any suggestions for how to get this working?
let symbols:String = "^GSPC"
let financeURL:String = "http://finance.yahoo.com/d/quotes.csv?s=\(symbols)&f=sl1c6p2"
var financeNSURL: NSURL = NSURL(string: financeURL) // ERROR (see above)
let tickerNSData: NSData = NSData(contentsOfURL: financeNSURL)
var output:NSString = NSString(data:tickerNSData, encoding:NSUTF8StringEncoding)
It's crashing because Swift (at least in Xcode6-Beta7) doesn't support returning nil
from an object initializer. From the release notes:
Swift does not support object initializers that fail by returning
null. (16480364)
Workaround: If there is a factory method, use it instead. Otherwise,
capture the result in an optional. For example:
let url: NSURL? = NSURL(string: "not a url")
So, to avoid a crash, declare your financeNSURL
as NSURL?
(as in the example from the docs above), or use NSURL.URLWithString()
instead of init(string:)
.
However, the root of the problem is that you're not encoding your URL parameters correctly.
If you call stringByAddingPercentEncodingWithAllowedCharacters(...)
on symbols
it works:
let symbols:String = "^GSPC".stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
let financeURL:String = "http://finance.yahoo.com/d/quotes.csv?s=\(symbols)&f=sl1c6p2"
let financeNSURL: NSURL? = NSURL(string: financeURL)
if let url = financeNSURL {
let tickerNSData: NSData = NSData(contentsOfURL: url)
var output:NSString = NSString(data:tickerNSData, encoding:NSUTF8StringEncoding)
}
Output:
"^GSPC",1999.83,"-2.45","-0.12%"
When creating a NSURL
with init method NSURLWithString:
the parameter URLString must be a properly encoded URL string. Your's is not. So, what is this a "properly encoded URL string"?
The corresponding official documentation gives a few more hints where to read:
"URLString: The URL string with which to initialize the NSURL
object. This URL string must conform to URL format as described in RFC 2396, and must not be nil
. This method parses URLString
according to RFCs 1738 and 1808."
(links are mine).
So basically, you need to separately encode each URL component from your source string component using the correct variant of the percent encoding algorithm. Then, compose all encoded string components to the final URL string.
This can be tedious and is certainly error prone. Thus, since iOS 8 there is NSURLComponents
(see docs here) which can aid you in this task.