NSURL errors with caret ^ in string - xcode

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 NSURLwith 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.

Related

Is there an API for com.apple.TextEncoding?

When you save an NSString (or Swift.String) using a method like this, it writes the xattr "com.apple.TextEncoding". When you load it back with one of the corresponding methods, it checks this xattr and uses that as the default encoding.
Is there any API to determine the encoding of a file, according to this xattr, without having to load the contents of the file?
I know it's not that hard to parse "IANA name, semicolon, CFString​Encoding uint32, (optional other stuff)", but I'd rather avoid it if there's a built-in way.
If I understand your question correctly, you're asking for a way to read the value of the "com.apple.TextEncoding" extended file attribute. This is possible via API declared in <sys/xattr.h>.
Here's a post that extends URL with extended attributes capabilities:
Write extend file attributes swift example
Example usage:
func getTextEncodingAttribute(for url: URL) -> String? {
do {
let data = try url.extendedAttribute(forName: "com.apple.TextEncoding")
return String(data: data, encoding: .utf8)
} catch _ {
}
return nil
}

How do I pass connection-time websocket parameters to Phoenix from Elm?

I was following along Programming Phoenix but using Elm for my front end, rather than Javascript. The second part of that book describes how to use websockets. The book's running example has you create an authentication token for the client side to pass to Phoenix at connection creation time. The Javascript Socket class provided with Phoenix allows that, but there's no obvious way to do it in Elm (as of 0.17 and the date of this question).
As in the book, make the token visible to Javascript by attaching it to window.
<script>window.auth_token = "<%= assigns[:auth_token] %>"</script>
In web/static/js/app.js, you'll have code that starts Elm. Pass the token there.
const c4uDiv = document.querySelector('#c4u-target');
if (c4uDiv) {
Elm.C4u.embed(c4uDiv, {authToken: window.auth_token});
}
On the Elm side, you'll use programWithFlags instead of program.
Your init function will take a flags argument. (I'm using the Navigation library for a single-page app, which is why there's a PageChoice argument as well.)
type alias Flags =
{ authToken : String
}
init : Flags -> MyNav.PageChoice -> ( Model, Cmd Msg )
Within init, tack on the token as a URI query pair. Note that you have to uri-encode because the token contains odd characters. Here's the crude way to do that. Note: I am using the elm-phoenix-socket library below, but the same hackery would be required with others.
let
uri = "ws://localhost:4000/socket/websocket?auth_token=" ++
(Http.uriEncode flags.authToken)
in
uri
|> Phoenix.Socket.init
|> Phoenix.Socket.withDebug
|> Phoenix.Socket.on "ping" "c4u" ReceiveMessage
I got here by a Tweet by Brian, about encoding from Elm.
In this case I like to handle it from the JavaScript side.
I tried to replicate the way the Phoenix client sets it up.
Instead of passing the token I passed the complete endpoint...
I've put the token in JSON a hash
<script id="app-json" type="application/json"><%= raw #json %></script>
Which I read on the client, and pass to the Elm embed
var data = JSON.parse(document.getElementById("app-json").innerHTML)
var token = encodeURIComponent(data.token)
var elm = window.Elm.App.embed(document.getElementById("elm-container"), {
socketEndpoint: "ws://" + window.location.host + "/socket/websocket?token=" + token
})

ABRecordCopyValue not working when object doesn't exist

This line of code in Swift causes me problems when the address book has a contact with no last name.
I've tried to resolve it a number of ways to no avail. Is there some sort of try catch statement or error handling I can use? Or check if AnyObject is null (the return type of
ABRecordCopyValue(person, kABPersonLastNameProperty).takeRetainedValue()).
I've tried using optional types but it doesn't seem to work since the app stops running the moment you select a contact with no last name - and the line of code below gets highlighted with the error Thread
1: EXC_BAD_ACCESS
let lName = ABRecordCopyValue(person, kABPersonLastNameProperty).takeRetainedValue() as String
ABRecordCopyValue can actually return nil so you should unwrap it. Also, casting to String didn't work for me so I'm using NSString.
if let firstName = ABRecordCopyValue(abContact, kABPersonFirstNameProperty)?.takeRetainedValue() as? NSString {
println("FIRST NAME: \(firstName)")
}
else {
println("No Name")
}
Another thing you could try is instead of getting the first and lastName individually, you could also try to get the composed name.
if let fullName = ABRecordCopyCompositeName(abContact)?.takeRetainedValue() as String? {
println("Full Name: \(fullName)")
}
P.S: I've also tried all the answers from this question but despite of making perfect sense and working when debugging the app, they crashed when I deployed the archive directly into the phone.

Passing a filepath over url

I need to pass this filepath over via route to my actionmethod:
<p>#car.Name</p>
so for example #car.ContainerPath is a string of "34_Creating%20Cars%20Forms/Exercise%20Cars/Audi%202010%20Parts%20Reference.pdf"
I need to escape this somehow I think? I would prefer not to send this over url but with a hyperlink I don't see a way not to.
UPDATE:
For additional info, here's the actionmethod it's going to:
public string GetFileZipDownloadUrl(CarViewModel model, string fileContainerPath)
{
string downloadUrl = string.Empty;
downloadUrl = GetFileZipDownloadUrl(model.CarId,fileContainerPath, model.UserId);
return downloadUrl;
}
so I'm sending over for that fileContainerPath paths like this in the url for that #car.ContainerPath param:
"55_Creating Cars Forms/Exercise Cars/Audi Parts Reference.pdf"
so the route url before it's requested looks like this when formed in that hyperlink:
http://Cars/55/55_Creating Cars Forms/Exercise Cars/Audi Parts Reference.pdf/20/Url
My action method just needs to use that path to go get a reference to a file under the hood.
If you want to just get rid of %20 in the url use encoding/decoding like in #Xander's answer. However if any of your data is very dynamic and can have weird characters you should consider adding a Safe() and Unsafe() methods that will strip out all the "Dangerous" characters for url, and then turn it back to original value.
Raw Url:
HttpUtility.UrlEncode(rawurl);
Decode encoded url:
HttpUtility.UrlDecode(encodedurl);
http://msdn.microsoft.com/en-us/library/system.web.httputility.urlencode.aspx
http://msdn.microsoft.com/en-us/library/system.web.httputility.urldecode.aspx

CFData vs CFString

I have a CFMutableDictionaryRef, part of which in debugger is:
"device-id" = <72270000>;
model = <474d4120 39353000>;
"vendor-id" = <86800000>;
Now I can get value of the key model using CFDataRef which returns string like "GMA 950", as compared to the value above.
But I cannot get value of "vendor-id"using same method so I try with CFString, which returns <86800000> instead of a string. So how to retreive correct value of the vendor id (which I already know should return 0x8086 for Intel) ??
found it:
have to format the string retreived with CFString as:
NSString *id = [NSString stringWithFormat:#"0x%X",*((UInt32*)CFDataGetBytePtr(cfstr))];

Resources