Last active
January 12, 2017 14:50
-
-
Save thekoc/59117cf1c289060e4ac0148149d6c141 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//: 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