How can I get the currency symbols for the corresponding currency code with Swift (macOS).
Example:
EUR = €1.00
USD = $1.00
CAD = $1.00
GBP = £1.00
My code:
var formatter = NSNumberFormatter()
formatter.currencySymbol = getSymbol(currencyCode)
formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle
let number = NSNumber(double: (amount as NSString).doubleValue)
let amountWithSymbol = formatter.stringFromNumber(number)!
getSymbol(_ currencyCode: String) -> String
or.. is there a better way?
A bit late but this is a solution I used to get the $ instead of US$ etc. for currency symbol.
/*
* Bear in mind not every currency have a corresponding symbol.
*
* EXAMPLE TABLE
*
* currency code | Country & Currency | Currency Symbol
*
* BGN | Bulgarian lev | лв
* HRK | Croatian Kuna | kn
* CZK | Czech Koruna | Kč
* EUR | EU Euro | €
* USD | US Dollar | $
* GBP | British Pound | £
*/
func getSymbol(forCurrencyCode code: String) -> String? {
let locale = NSLocale(localeIdentifier: code)
return locale.displayNameForKey(NSLocaleCurrencySymbol, value: code)
}
Basically this creates NSLocale from your currency code and grabs the display attribute for the currency. In cases where the result matches the currency code for example SEK it will create new country specific locale by removing the last character from the currency code and appending "_en" to form SE_en. Then it will try to get the currency symbol again.
Swift 3 & 4
func getSymbol(forCurrencyCode code: String) -> String? {
let locale = NSLocale(localeIdentifier: code)
if locale.displayName(forKey: .currencySymbol, value: code) == code {
let newlocale = NSLocale(localeIdentifier: code.dropLast() + "_en")
return newlocale.displayName(forKey: .currencySymbol, value: code)
}
return locale.displayName(forKey: .currencySymbol, value: code)
}
The answer may be late but hopefully this helps clarify the root cause.
Problem
Currency code does not imply locale and region
The reason why CAD becomes CA$ is probably because NSLocale looks up the first matching currency code, and for CAD, these are the matching localeIdentifiers in order of NSLocale.availableLocaleIdentifiers
1. Optional("CA$") Optional("CA") iu_CA
2. Optional("$") Optional("CA") fr_CA
3. Optional("$") Optional("CA") en_CA
iu_CA is Inuktitut but I'm not sure why it's listed as CA$, but I hope the point is clear.
Similarly in CNY (Chinese Yuan):
1. Optional("CN¥") Optional("CN") en_CN
2. Optional("¥") Optional("CN") yue_CN
3. Optional("¥") Optional("CN") bo_CN
4. Optional("¥") Optional("CN") zh_CN
5. Optional("¥") Optional("CN") ug_CN
6. Optional("¥") Optional("CN") ii_CN
The reason for showing CN¥ when en_CN is probably because JPY also uses ¥.
In CHF (Switzerland Franc), they do not have a one-letter symbol:
1. Optional("CHF") Optional("LI") gsw_LI
2. Optional("CHF") Optional("CH") de_CH
...
9. Optional("CHF") Optional("CH") en_CH
10. Optional("CHF") Optional("CH") it_CH
Solution
Many apps vary, but this is the steps I took that I am happy with for my application:
Find matching locale candidates using currency code lookup from all locale identifiers
Pick the shortest symbol from the candidates
Store the symbol somewhere so that it doesn't have to be computed each time
Implementation
func getSymbolForCurrencyCode(code: String) -> String {
var candidates: [String] = []
let locales: [String] = NSLocale.availableLocaleIdentifiers
for localeID in locales {
guard let symbol = findMatchingSymbol(localeID: localeID, currencyCode: code) else {
continue
}
if symbol.count == 1 {
return symbol
}
candidates.append(symbol)
}
let sorted = sortAscByLength(list: candidates)
if sorted.count < 1 {
return ""
}
return sorted[0]
}
func findMatchingSymbol(localeID: String, currencyCode: String) -> String? {
let locale = Locale(identifier: localeID as String)
guard let code = locale.currencyCode else {
return nil
}
if code != currencyCode {
return nil
}
guard let symbol = locale.currencySymbol else {
return nil
}
return symbol
}
func sortAscByLength(list: [String]) -> [String] {
return list.sorted(by: { $0.count < $1.count })
}
Usage
let usd = getSymbolForCurrencyCode(code: "USD")
let jpy = getSymbolForCurrencyCode(code: "JPY")
let cny = getSymbolForCurrencyCode(code: "CNY")
let cad = getSymbolForCurrencyCode(code: "CAD")
let uah = getSymbolForCurrencyCode(code: "UAH")
let krw = getSymbolForCurrencyCode(code: "KRW")
let zar = getSymbolForCurrencyCode(code: "ZAR")
let chf = getSymbolForCurrencyCode(code: "CHF")
let all = [usd, jpy, cny, cad, uah, krw, zar, chf]
(lldb) po all
▿ 8 elements
- 0 : "$"
- 1 : "¥"
- 2 : "¥"
- 3 : "$"
- 4 : "₴"
- 5 : "₩"
- 6 : "R"
- 7 : "CHF"
Problems
Instinctively, I see that the one letter symbol approach can show an incorrect symbol if there are more than one distinct symbols for currency code, but I haven't seen such case.
Computing this each time is heavy lifting so when a user sets their currency setting, it's wise to store the computed result and use that result upon each lookup
The proper way to do this is to let the frameworks provide the information for you.
You can retrieve that information using an obscure class method on NSLocale called localeIdentifierFromComponents(). That method will take a dictionary that defines various attributes of your locale, and then returns an identifier you can use to actually construct an NSLocale instance. Once you have the NSLocale, you can ask it for its CurrencySymbol, like this:
let currencyCode = "CAD"
let localeComponents = [NSLocaleCurrencyCode: currencyCode]
let localeIdentifier = NSLocale.localeIdentifierFromComponents(localeComponents)
let locale = NSLocale(localeIdentifier: localeIdentifier)
let currencySymbol = locale.objectForKey(NSLocaleCurrencySymbol) as! String
// currencySymbol is "CA$"
I combined and improved all the suggestion here to have a drop-in(copy/paste) solution for the future readers(you).
It has its own local cache, case insensitive, and have an extension method to provide chaining for String. Swift 4/5 ready.
How to use:
"USD".currencySymbol //returns "$"
//OR
Currency.shared.findSymbol(currencyCode: "TRY") //returns "₺"
Tests:
XCTAssertEqual("$", "USD".currencySymbol)
XCTAssertEqual("₺", "TRY".currencySymbol)
XCTAssertEqual("€", "EUR".currencySymbol)
XCTAssertEqual("", "ASDF".currencySymbol)
Code:
class Currency {
static let shared: Currency = Currency()
private var cache: [String:String] = [:]
func findSymbol(currencyCode:String) -> String {
if let hit = cache[currencyCode] { return hit }
guard currencyCode.count < 4 else { return "" }
let symbol = findSymbolBy(currencyCode)
cache[currencyCode] = symbol
return symbol
}
private func findSymbolBy(_ currencyCode: String) -> String {
var candidates: [String] = []
let locales = NSLocale.availableLocaleIdentifiers
for localeId in locales {
guard let symbol = findSymbolBy(localeId, currencyCode) else { continue }
if symbol.count == 1 { return symbol }
candidates.append(symbol)
}
return candidates.sorted(by: { $0.count < $1.count }).first ?? ""
}
private func findSymbolBy(_ localeId: String, _ currencyCode: String) -> String? {
let locale = Locale(identifier: localeId)
return currencyCode.caseInsensitiveCompare(locale.currencyCode ?? "") == .orderedSame
? locale.currencySymbol : nil
}
}
extension String {
var currencySymbol: String { return Currency.shared.findSymbol(currencyCode: self) }
}
To simply get the currency symbol in Swift.
let locale = Locale.current // currency symbol from current location
//let locale = Locale(identifier: "fr_FR") // or you could specify the locale e.g fr_FR, en_US etc
let currencySymbol = locale.currencySymbol!
print("\(currencySymbol)")
SWIFT4
//converting USD to $a and GBP to £
viewDidLoad()
{
print(getSymbolForCurrencyCode(code: "USD")!) // prints $
print(getSymbolForCurrencyCode(code: "GBP")!) //prints £
}
func getSymbolForCurrencyCode(code: String) -> String?
{
let locale = NSLocale(localeIdentifier: code)
return locale.displayName(forKey: NSLocale.Key.currencySymbol, value: code)
}
I suggest a faster and more convenient solution.
You can get all possible symbols for a specific currency:
Currency.currency(for: "USD")! // Currency(code: "USD", symbols: ["US$", "USD", "$"])
Currency.currency(for: "CAD")! // Currency(code: "USD", symbols: ["$", "CA$"])
Or get the shortest symbol. This is usually what everyone wants:
Currency.currency(for: "CAD")!.shortestSymbol // "$"
Now about the speed. The first call to this method takes linear time proportional to the number of locales plus the number of codes. Each subsequent call for any code is executed in constant time. Therefore, if you are implementing a CurrencyPickerViewController or something similar, then this solution is optimal.
Also, this solution has one more plus. Since global constants and variables are always computed lazily, if you never call a method to get information about the currency, the cache will not take up any memory.
struct Currency {
/// Returns the currency code. For example USD or EUD
let code: String
/// Returns currency symbols. For example ["USD", "US$", "$"] for USD, ["RUB", "₽"] for RUB or ["₴", "UAH"] for UAH
let symbols: [String]
/// Returns shortest currency symbols. For example "$" for USD or "₽" for RUB
var shortestSymbol: String {
return symbols.min { $0.count < $1.count } ?? ""
}
/// Returns information about a currency by its code.
static func currency(for code: String) -> Currency? {
return cache[code]
}
// Global constants and variables are always computed lazily, in a similar manner to Lazy Stored Properties.
static fileprivate var cache: [String: Currency] = { () -> [String: Currency] in
var mapCurrencyCode2Symbols: [String: Set<String>] = [:]
let currencyCodes = Set(Locale.commonISOCurrencyCodes)
for localeId in Locale.availableIdentifiers {
let locale = Locale(identifier: localeId)
guard let currencyCode = locale.currencyCode, let currencySymbol = locale.currencySymbol else {
continue
}
if currencyCode.contains(currencyCode) {
mapCurrencyCode2Symbols[currencyCode, default: []].insert(currencySymbol)
}
}
var mapCurrencyCode2Currency: [String: Currency] = [:]
for (code, symbols) in mapCurrencyCode2Symbols {
mapCurrencyCode2Currency[code] = Currency(code: code, symbols: Array(symbols))
}
return mapCurrencyCode2Currency
}()
}
To see how this functionality works for all codes, you can use the code:
for code in Locale.commonISOCurrencyCodes {
guard let currency = Currency.currency(for: code) else {
// Three codes have no symbol. This is CUC, LSL and VEF
print("Missing symbols for code \(code)")
continue
}
print(currency)
}
An imperfect solution I found to get $ instead of US$ or CA$ was to attempt to match the user's current locale to the currency code first. This will work for situations where you're building a mobile app and an API is sending you currency code based on the settings in that user's account. For us the business case is that 99% of users have the same currency code set in their account on the backend (USD, CAD, EUR, etc.), where we're getting the information from, as they do on their mobile app where we're displaying currency the way a user would expect to see it (i.e. $50.56 instead of US$ 50.56).
Objective-C
- (NSLocale *)localeFromCurrencyCode:(NSString *)currencyCode {
NSLocale *locale = [NSLocale currentLocale];
if (![locale.currencyCode isEqualToString:currencyCode]) {
NSDictionary *localeInfo = #{NSLocaleCurrencyCode:currencyCode};
locale = [[NSLocale alloc] initWithLocaleIdentifier:[NSLocale localeIdentifierFromComponents:localeInfo]];
}
return locale;
}
Swift
func locale(from currencyCode: String) -> Locale {
var locale = Locale.current
if (locale.currencyCode != currencyCode) {
let identifier = NSLocale.localeIdentifier(fromComponents: [NSLocale.Key.currencyCode.rawValue: currencyCode])
locale = NSLocale(localeIdentifier: identifier) as Locale
}
return locale;
}
Swift 4 Version of Pancho's answer, As the String.characters is deprecated now.
We can simply apply dropLast() on String.
func getCurrencySymbol(from currencyCode: String) -> String? {
let locale = NSLocale(localeIdentifier: currencyCode)
if locale.displayName(forKey: .currencySymbol, value: currencyCode) == currencyCode {
let newlocale = NSLocale(localeIdentifier: currencyCode.dropLast() + "_en")
return newlocale.displayName(forKey: .currencySymbol, value: currencyCode)
}
return locale.displayName(forKey: .currencySymbol, value: currencyCode)
}
You can use static 'availableIdentifiers' collection, containing all posible identifiers as follows:
extension Locale {
static func locale(from currencyIdentifier: String) -> Locale? {
let allLocales = Locale.availableIdentifiers.map({ Locale.init(identifier: $0) })
return allLocales.filter({ $0.currencyCode == currencyIdentifier }).first
}
}
You can try this:
let formatter = NSNumberFormatter()
for locale in NSLocale.availableLocaleIdentifiers() {
formatter.locale = NSLocale(localeIdentifier: locale)
print("\(formatter.currencyCode) = \(formatter.currencySymbol)")
}
let countryCode = (Locale.current as NSLocale).object(forKey: .currencySymbol) as? String ?? "$"
Above will give current currency Symbol, For UK it gives me = £ Apple Doc
Related
I'm hoping someone may be able to help i'm using Xcode 8 and swift 3
I have a playground file Xcode 7 swift 2 that involves a Midi callback for Midi Input everything works fine in 7
I tried a conversion to 8 and it brought up errors regarding memory and a few name changes mostly of what i believe to be non serious i also redefined the infinite loop using PlaygroundSupport
However the error i cannot get over involves MyMIDIReadProc at
MIDIInputPortCreate(midiClient, "MidiTest_InPort", MyMIDIReadProc, nil, &inPort);
The error says
Cannot convert value of type '(pktList: UnsafePointer, readProcRefCon: UnsafeMutablePointer, srcConnRefCon: UnsafeMutablePointer) -> Void' to expected argument type 'MIDIReadProc' (aka '#convention(c) (UnsafePointer, Optional>, Optional>) -> ()')
My understanding is that it needs a #convention(c) wrapper of some description inserted. I think i'm on the right track because you can wrap a function but my knowledge of where to put it has run out. Again i was hoping some one might be able to advise
Thanks for reading
apologies for any bad language as i'm self taught
Here is the original Xcode 7 code
import Cocoa
import CoreMIDI
import XCPlayground
func getDisplayName(obj: MIDIObjectRef) -> String
{
var param: Unmanaged<CFString>?
var name: String = "Error";
let err: OSStatus = MIDIObjectGetStringProperty(obj, kMIDIPropertyDisplayName, ¶m)
if err == OSStatus(noErr)
{
name = param!.takeRetainedValue() as String
}
return name;
}
func MyMIDIReadProc(pktList: UnsafePointer<MIDIPacketList>,
readProcRefCon: UnsafeMutablePointer<Void>, srcConnRefCon: UnsafeMutablePointer<Void>) -> Void
{
let packetList:MIDIPacketList = pktList.memory;
let srcRef:MIDIEndpointRef = UnsafeMutablePointer<MIDIEndpointRef>(COpaquePointer(srcConnRefCon)).memory;
print("MIDI Received From Source: \(getDisplayName(srcRef))");
var packet:MIDIPacket = packetList.packet;
for _ in 1...packetList.numPackets
{
let bytes = Mirror(reflecting: packet.data).children;
var dumpStr = "";
// bytes mirror contains all the zero values in the ridiulous packet data tuple
// so use the packet length to iterate.
var i = packet.length;
for (_, attr) in bytes.enumerate()
{
dumpStr += String(format:"$%02X ", attr.value as! UInt8);
--i;
if (i <= 0)
{
break;
}
}
print(dumpStr)
packet = MIDIPacketNext(&packet).memory;
}
}
var midiClient: MIDIClientRef = 0;
var inPort:MIDIPortRef = 0;
var src:MIDIEndpointRef = MIDIGetSource(0);
MIDIClientCreate("MidiTestClient", nil, nil, &midiClient);
MIDIInputPortCreate(midiClient, "MidiTest_InPort", MyMIDIReadProc, nil, &inPort);
MIDIPortConnectSource(inPort, src, &src);
// Keep playground running
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true;
And here is the Xcode 8 code converted
var str = "Hello, playground"
import Cocoa
import CoreMIDI
import XCPlayground
import PlaygroundSupport
func getDisplayName(obj: MIDIObjectRef) -> String
{
var param: Unmanaged<CFString>?
var name: String = "Error";
let err: OSStatus = MIDIObjectGetStringProperty(obj, kMIDIPropertyDisplayName, ¶m)
if err == OSStatus(noErr)
{
name = param!.takeRetainedValue() as String
}
return name;
}
func MyMIDIReadProc(pktList: UnsafePointer<MIDIPacketList>,
readProcRefCon: UnsafeMutablePointer<Void>, srcConnRefCon: UnsafeMutablePointer<Void>) -> Void
{
let packetList:MIDIPacketList = pktList.pointee;
let srcRef:MIDIEndpointRef = UnsafeMutablePointer<MIDIEndpointRef>(OpaquePointer(srcConnRefCon)).pointee;
print("MIDI Received From Source: \(getDisplayName(obj: srcRef))");
var packet:MIDIPacket = packetList.packet;
for _ in 1...packetList.numPackets
{
let bytes = Mirror(reflecting: packet.data).children;
var dumpStr = "";
var i = packet.length;
for (_, attr) in bytes.enumerated()
{
dumpStr += String(format:"$%02X ", attr.value as! UInt8);
i -= 1;
if (i <= 0)
{
break;
}
}
print(dumpStr)
packet = MIDIPacketNext(&packet).pointee;
}
}
var midiClient: MIDIClientRef = 0;
var inPort:MIDIPortRef = 0;
var src:MIDIEndpointRef = MIDIGetSource(0);
MIDIClientCreate("MidiTestClient", nil, nil, &midiClient);
MIDIInputPortCreate(midiClient, "MidiTest_InPort", MyMIDIReadProc, nil, &inPort);
MIDIPortConnectSource(inPort, src, &src);
PlaygroundPage.current.needsIndefiniteExecution = true
Pointer types are drastically changed in Swift 3. Many C-based APIs' signatures are changed accordingly.
Following those changes manually would be painful. You can make Swift work for you, with a little modification.
Try changing the function header:
func MyMIDIReadProc(pktList: UnsafePointer<MIDIPacketList>,
readProcRefCon: UnsafeMutablePointer<Void>, srcConnRefCon: UnsafeMutablePointer<Void>) -> Void
{
to a closure declaration:
let MyMIDIReadProc: MIDIReadProc = {pktList, readProcRefCon, srcConnRefCon in
Swift infers argument types perfectly in this style.
You may need to fix pointer type conversion:
let srcRef:MIDIEndpointRef = UnsafeMutablePointer<MIDIEndpointRef>(OpaquePointer(srcConnRefCon)).pointee;
to something like this:
//I'm not sure using `!` is safe here...
let srcRef: MIDIEndpointRef = UnsafeMutablePointer(srcConnRefCon!).pointee
(By the way, the equivalent part in your Xcode 7 code is a little bit redundant. You have no need to use intermediate COpaquePointer there.)
In Swift 3, pointers cannot be nil, and nullable pointers are represented with Optionals. You may need many other fixes to work with C-based APIs in Swift 3.
OOPer is pointing (ahem) you in the right direction. Here is a blog post on using Swift 3 Core MIDI along with a working github repo.
Assuming that you're working with CoreMIDI 1.3 or later, you may have more luck using MIDIInputPortCreateWithBlock instead of MIDIInputPortCreate.
This method takes a Swift block as a parameter instead of requiring an #convention(c) function reference, making it more amenable to use within methods belonging to Swift classes, e.g.:
public func midiReadBlock(ptr: UnsafePointer<MIDIPacketList>, _: UnsafeMutableRawPointer?) -> Void {
let list: MIDIPacketList = ptr.pointee
...
}
You may also find these two extensions useful.
This one (derived from here) allows you to iterate directly over a MIDIPacketList using for pkt in list:
extension MIDIPacketList: Sequence {
public func makeIterator() -> AnyIterator<MIDIPacket> {
var iterator: MIDIPacket?
var nextIndex: UInt32 = 0
return AnyIterator {
nextIndex += 1
if nextIndex > self.numPackets { return nil }
if iterator != nil {
iterator = withUnsafePointer(to: &iterator!) { MIDIPacketNext($0).pointee }
} else {
iterator = self.packet;
}
return iterator
}
}
}
and this one adds a method to a MIDIPacket to extract the contents as a [UInt8] instead of having to use the really broken tuple syntax:
extension MIDIPacket {
public var asArray: [UInt8] {
let mirror = Mirror(reflecting: self.data)
let length = Int(self.length)
var result = [UInt8]()
result.reserveCapacity(length)
for (n, child) in mirror.children.enumerated() {
if n == length {
break
}
result.append(child.value as! UInt8)
}
return result
}
}
This is Swift 2.1.
How would you go about extracting an amount from a string that looks like "add egg (£2.00)"? In this example, I would need the "2.00" portion.
Would it be a hard-check looking for whatever's enclosed between the brackets? Or is there a more effective way to do so? I.e. regex or something?
'pure' Swift solution, no brackets necessary
let str = ["add egg £ 2.00",
"the price is $12.00 per unit",
"send €10.22 to somebody",
"invalid $(12)"]
func value(str: String, currency: String)->Double {
var chars = str.characters
let currs = currency.characters
while !currs.contains(chars.popFirst() ?? " ") {}
let arr = chars.split(" ")
guard let value = arr.first,
let d = Double(String(value)) else { return Double.NaN }
return d
}
let values = str.flatMap { value($0, currency: "£$€") }
print(values)
/*
[2.0, 12.0, 10.220000000000001, nan]
*/
if you really need the brackets there, no problem ...
let str = ["add egg (£2.00)",
"the price is ($12.00) per unit",
"send (€10.22) to somebody",
"invalid ($-12)"]
func value(str: String, currency: String)->Double {
var chars = str.characters
let currs = currency.characters
while !currs.contains(chars.popFirst() ?? " ") {}
let arr = chars.split(")")
guard let value = arr.first,
let d = Double(String(value)) else { return Double.NaN }
return d
}
let values = str.flatMap { value($0, currency: "£$€") }
print(values)
/*
[2.0, 12.0, 10.220000000000001, -12.0]
*/
There's many ways to achieve what you want - here's a simple example with a regex.
I'm using (?<=\\()[^\\)]+ to find anything between ( and ), then I use a couple of ranges to extract the values: one for the currency symbol, another for the value.
extension String {
func extractValueBetweenParenthesis() -> (currency: String?, value: String?) {
if let range = self.rangeOfString("(?<=\\()[^\\)]+", options: .RegularExpressionSearch) {
let cr = range.startIndex..<range.startIndex.advancedBy(1)
let vr = range.startIndex.advancedBy(1)..<range.endIndex
return (currency: self.substringWithRange(cr), value: self.substringWithRange(vr))
}
return (nil, nil)
}
}
Call the method on a String then safely unwrap the optional results:
let str = "add egg (£2.00)"
let result = str.extractValueBetweenParenthesis()
if let currency = result.currency, value = result.value {
print("Currency is '\(currency)' and value is '\(value)'")
}
Prints:
Currency is '£' and value is '2.00'
var myString = "add egg (£2.00)"
myString = myString.stringByReplacingOccurrencesOfString("", withString: "")
let components = myString.componentsSeparatedByString("add egg (£")
let finalString = components[1].stringByReplacingOccurrencesOfString(")", withString: "")
print(finalString)
//This prints 2.00
I use SwiftLocation for get coordinates:
try! SwiftLocation.shared.currentLocation(Accuracy.House, timeout: 20, onSuccess: { (location) -> Void in
print(location?.description)
}) { (error) -> Void in
print("something went wrong")
}
In location?.description I get it:
<+37.78583400,-122.40641700> +/- 5.00m (speed -1.00 mps / course
-1.00) # 2/22/16, 6:35:55 PM Indochina Time
And I need to take just coordinates. So I make loop for it:
while name.characters.last != ">" { // delete all after ">"
name = String(name.characters.dropLast())
}
name = String(name.characters.dropLast()) // delete ">"
name = String(name.characters.dropFirst()) // delete "<"
name = String(name.characters.dropFirst()) // delete "+"
print(name) // get 37.78583400,-122.40641700
tempMyLat = name
while tempMyLat.characters.last != "," { // delete all after ","
tempMyLat = String(tempMyLat.characters.dropLast())
}
tempMyLon = name
while tempMyLon.characters.first != "," { // delete all before ","
tempMyLon = String(tempMyLon.characters.dropFirst())
}
tempMyLon = String(tempMyLon.characters.dropFirst()) // delete ","
But this code work ONLY for string. When I get location?.description - I can't convert it for type - string, because "location" is a CLLocation type.
So, my question: How convert location?.description to String ?
or
how get only coordinates from the SwiftLocation
Thanks.
In Xcode 10+ and Swift 3, you may have to do something similar to the following:
let myLocation: CLLocation = locations[0] as CLLocations
var myLatitude: String = String(format: "%f", myLocation.coordinate.latitude)
var myLongitude: String = String(format:"%f", myLocation.coordinate.longitude)
If you want to get locations from CLLocation you dont need to convert string from CLLocation object. you can get locations directly from CLLocation object.
Here is an example :
var locationObj = locationArray.lastObject as CLLocation
var coord = locationObj.coordinate
var longitude = coord.longitude //Latitude & Longitude as String
var latitude = coord.latitude
I'd create an extension for CLLocation like this:
extension CLLocation {
/// Provide optional coordinate components labels
func locationString(with labels:[String]? = ["lat","lon"]) -> String {
return "\(latitudeString(with: labels!.first!))- \(longitudeString(with: labels!.last!))"
}
// Get string for each component
//This is not necessary, as you could combine this into formattedLabel: label
//But it's good to have these separate in case you need just one of the components
func latitudeString(with label: String?) -> String {
return "\(formattedLabel(from: label))\(self.coordinate.latitude)"
}
func longitudeString(with label: String?) -> String {
return "\(formattedLabel(from: label))\(self.coordinate.longitude)"
}
// Returns formatted label or nothing in case nothing is needed
func formattedLabel(from label: String?) -> String {
var sortedLabel = ""
if label != nil {
sortedLabel = "\(label!): "
}
return sortedLabel
}
}
And then call it like:
let locationString = someCLLocation.locationString()
// or someCLLocation.locationString(with: ["label 1", "label 2"])
I'm trying to implement an asynchronous function as told in this topic but I always get the following error from Xcode : Type 'dispatch_queue_t!' does not conform to protocol 'OS_dispatch_queue'
Here's my code:
#IBAction func buyButton(sender: AnyObject) {
// get wanted symbol
let symbol = symbolField.text!
// get price of share
var priceShare :Double = 0
_ = lookup(symbol) { name, symbol, price in
dispatch_async(dispatch_get_main_queue()) {
priceShare = price
}
}
buy(symbol, number: 1, price: priceShare)
}
Here's the lookup function:
func lookup(entry : NSString, completion: ((name :String, symbol :String, price :String) -> Void)) {
// define return values
var name = String()
var symbol = String()
var price = String()
// define URL
let url = NSURL(string: "http://yahoojson.gobu.fr/symbol.php?symbol=\(entry)")!
let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) in
if let urlContent = data {
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(urlContent, options: NSJSONReadingOptions.MutableContainers)
name = jsonResult["name"] as! String
symbol = jsonResult["symbol"] as! String
price = jsonResult["price"]!!.stringValue as String
completion(name: name, symbol: symbol, price: price)
} catch {
print(error)
}
}
}
// run the task
task.resume()
}
Any hint on what I could be doing wrong?
I figure it out by myself. There was a bug inside on my code.
On the line
priceShare = price
I needed to put
priceShare = Double(price)!
since priceShare require a Double. Don't understand why Xcode didn't tell me so.
I'm trying to get the contact details out of the address book on the Mac. I can get the first name and last name fields etc, but I'm struggling with the syntax for ABPersonCopyImageData.
Now according to the documentation ABPersonCopyImageData takes a single parameter of type ABPerson.
Here is my code:
import AddressBook
let thisPerson : ABPerson
let addressBook = ABAddressBook.sharedAddressBook()
rec = addressBook.recordForUniqueId("0005A360-327F-4E12-BBB9-24A842497E12:ABPerson")
let firstName = rec.valueForProperty(kABFirstNameProperty) as! String
let lastName = rec.valueForProperty(kABLastNameProperty) as! String
println("\(firstName) \(lastName)")
let contactImage = ABPersonCopyImageData(thisPerson)
The last line stops the compiler with an error: Cannot invoke 'ABPersonCopyImageData' with an argument list of type (ABPerson). As far as I can tell thisPerson is of type ABPerson. What is going wrong?
I found out how to do this in ElCapitan:
import Contacts
func getContactImage(name:String) -> NSImage?
{
let store = CNContactStore()
do
{
let contacts = try store.unifiedContactsMatchingPredicate(CNContact.predicateForContactsMatchingName(name), keysToFetch:[CNContactImageDataKey])
if contacts.count > 0
{
if let image = contacts[0].imageData
{
return NSImage.init(data: image)
}
}
}
catch
{
}
return nil
}