Skip to content

Instantly share code, notes, and snippets.

@thekoc
Last active January 12, 2017 14:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thekoc/59117cf1c289060e4ac0148149d6c141 to your computer and use it in GitHub Desktop.
Save thekoc/59117cf1c289060e4ac0148149d6c141 to your computer and use it in GitHub Desktop.
//: Playground - noun: a place where people can play
import Cocoa
import CoreFoundation
//import PlaygroundSupport
//PlaygroundPage.current.needsIndefiniteExecution = true
class CurrencyConverter {
private let requester = FixerRequester()
private var rateDict = [String: Double]()
func getRateAsync(fromType: String, toType: String, date: Date? = nil, callBack: @escaping (Double?) -> ()) {
requester.forData(date: date, base: fromType, symbols: [toType]) {
data in
guard let dict = data as? [String: Any], let rates = dict["rates"] as? [String: Double] else {
return
}
guard let toRate = rates[toType.uppercased()] else {
callBack(nil)
return
}
callBack(toRate)
}
}
func getRate(fromType: String, toType: String, date: Date? = nil) -> Double? {
let semaphore = DispatchSemaphore(value: 0)
var r: Double? = nil
getRateAsync(fromType: fromType, toType: toType, date: date) {
rate in
r = rate
semaphore.signal()
}
semaphore.wait(timeout: DispatchTime.distantFuture)
return r
}
private func _convert(fromType: String, toType: String, amount: Double, date: Date? = nil) -> Double? {
if let rate = getRate(fromType: fromType, toType: toType, date: date) {
return amount * rate
} else {
return nil
}
}
func convert(fromType: String, toType: String, amount: Double, date: Date? = nil) -> Double? {
// memorize
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
if let rate = rateDict[[fromType, toType, dateFormatter.string(from: date ?? Date())].joined(separator: "-")] {
return rate
} else {
if let rate = _convert(fromType: fromType, toType: toType, amount: amount, date: date) {
rateDict[[fromType, toType, dateFormatter.string(from: date ?? Date())].joined(separator: "-")] = amount * rate
return amount * rate
} else {
return nil
}
}
}
}
class FixerRequester {
private var baseURLCompoents = URLComponents()
init() {
baseURLCompoents.scheme = "https"
baseURLCompoents.host = "api.fixer.io"
}
func forData(date: Date? = nil, base: String? = nil, symbols: [String]? = nil, completion: @escaping (Any) -> ()) {
var queryItems = [URLQueryItem]()
if let d = date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
baseURLCompoents.path = "/\(dateFormatter.string(from: d))"
} else {
baseURLCompoents.path = "/latest"
}
if let b = base {
queryItems.append(URLQueryItem(name: "base", value: b))
}
if let s = symbols {
queryItems.append(URLQueryItem(name: "symbols", value: s.joined(separator: ",")))
}
baseURLCompoents.queryItems = queryItems != [] ? queryItems : nil
let task = URLSession.shared.dataTask(with: baseURLCompoents.url!) {
data, response, error in
let json = try! JSONSerialization.jsonObject(with: data!, options: [])
completion(json)
}
task.resume()
}
}
// usage
// latest rate
var c = CurrencyConverter()
print(
c.convert(fromType: "USD", toType: "CNY", amount: 10)!
)
// rate by date
let formatter = DateFormatter()
formatter.dateFormat = "yyyy MM dd"
let date = formatter.date(from: "2010 2 13")
print(
c.convert(fromType: "USD", toType: "CNY", amount: 10, date: date)!
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment