Skip to content

Instantly share code, notes, and snippets.

@AliSoftware
Last active August 29, 2015 14:16
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 AliSoftware/80bef0d64cae97d527b3 to your computer and use it in GitHub Desktop.
Save AliSoftware/80bef0d64cae97d527b3 to your computer and use it in GitHub Desktop.
Swift-Concepts
// Without currying
func multiplier(x: Int) -> (by: Int) -> Int {
func mult(y: Int) -> Int {
return x*y
}
return mult
}
let doubler = multiplier(2)
doubler(by: 7) // returns 14
// The exact same function written using currying
func multiplier2(x: Int)(by: Int) -> Int {
return x*by
}
let doubler2 = multiplier2(2)
doubler2(by: 7) // returns 14
// For implementing the Promises pattern, I suggest http://promisekit.org
// But here we will build a very simple, naive and limited implementation just to show very basic concepts
import Foundation
/////////////////////
// Promise Pattern (very simplified and naive)
/////////////////////
class Promise<T> {
private var completion: (T->Void)?
init() { }
init(forwardValue value: T) {
self.fulfill(value)
}
// Naive fulfill, for simplicity's sake of this simple demo.
// This implementation does not work if we `fulfill()` *before* we `then()`
// (Whereas in the official Promise pattern, it should)
func fulfill(value: T) {
dispatch_async(dispatch_get_main_queue()) {
self.completion?(value)
}
}
func then(completion: T->Void) {
self.completion = completion
}
func then<U>(completion: T->U) -> Promise<U> {
let p = Promise<U>()
self.completion = { t in
let u = completion(t)
p.fulfill( u )
}
return p
}
func then<U>(completion: T->Promise<U>) -> Promise<U> {
let p = Promise<U>()
self.completion = { t in
completion(t).resolve(p)
}
return p
}
func resolve(other: Promise<T>) {
self.then { other.fulfill($0) }
}
}
///////////////////////////
// Fetch JSON WebService
///////////////////////////
typealias JSONDict = [String:AnyObject]
// Send network request and parse the JSON response
func fetch(urlString: String) -> Promise<JSONDict?> {
let p = Promise<JSONDict?>()
if let url = NSURL(string: urlString) {
NSURLSession.sharedSession().dataTaskWithURL(url) { (data, resp, err) in
let obj = NSJSONSerialization.JSONObjectWithData(data, options: .allZeros, error: nil) as? JSONDict
p.fulfill(obj)
}.resume()
} else {
println("Invalid URL!")
p.fulfill(nil)
}
return p
}
/////////////////////
// Data Structures
/////////////////////
struct GeoLoc : Printable {
let latitude: Double
let longitude: Double
var description: String { return "(lat:\(latitude), lng:\(longitude))" }
}
struct City : Printable {
let name: String? = nil
let zipcode: String? = nil
let country: (code: String?, name: String?) = (nil,nil)
let geoloc: GeoLoc? = nil
var description: String {
let na = "N/A"
let latlng = geoloc?.description ?? na
let countryStr = country.name ?? country.code ?? na
return "\(zipcode ?? na) \(name ?? na), \(countryStr) \(latlng)"
}
}
struct Weather : Printable {
let condition: String?
let temp: Double
var description: String {
return (condition ?? "N/A") + ", \(temp)°C"
}
}
/////////////////////
// Functional Code
/////////////////////
func fetchCityFromIP() -> Promise<City?> {
let p = Promise<City?>()
println(">>> Geolocation in progress...")
fetch("https://freegeoip.net/json/").then { dict in
if let dict = dict {
let geoloc: GeoLoc?
if let lat = dict["latitude"] as? Double, let lng = dict["longitude"] as? Double {
geoloc = GeoLoc(latitude: lat, longitude: lng)
} else {
geoloc = nil
}
let city = City(
name: dict["city"] as? String,
zipcode: dict["zip_code"] as? String,
country: (
code: dict["country_code"] as? String,
name: dict["country_name"] as? String
),
geoloc: geoloc
)
p.fulfill(city)
} else {
p.fulfill(nil)
}
}
return p
}
let apibase = "http://api.openweathermap.org/data/2.5/weather?units=metric&lang=fr"
func fetchCurrentWeather(geoloc: GeoLoc) -> Promise<Weather?> {
println(">>> Fetching weather for position \(geoloc)...")
let url = "\(apibase)&lat=\(geoloc.latitude)&lon=\(geoloc.longitude)"
return fetch(url).then(parseWeather)
}
func fetchCurrentWeather(cityName: String) -> Promise<Weather?> {
println(">>> Fetching weather for city \(cityName)...")
let url = "\(apibase)&q=\(cityName)"
return fetch(url).then(parseWeather)
}
func fetchCurrentWeather(city: City?) -> Promise<Weather?> {
if let geoloc = city?.geoloc {
// We have a latitude & longitude
return fetchCurrentWeather(geoloc)
} else if let name = city?.name {
// We have a city name
if let cc = city?.country.code {
// If we also have a country code, use it
return fetchCurrentWeather(name + "," + cc)
} else {
// Otherwise, use only the city name
return fetchCurrentWeather(name)
}
} else {
println(">>> This city has no geoloc nor city name!")
return Promise(forwardValue: nil)
}
}
func parseWeather(dict: JSONDict?) -> Weather {
let weathers = dict?["weather"] as! [JSONDict]
let cond = weathers[0]["description"] as? String
let main = dict?["main"] as! JSONDict
let temp = main["temp"] as! Double
return Weather(condition: cond, temp: temp)
}
func getWeatherTip(weather: Weather?) -> Promise<String?> {
let p = Promise<String?>()
if let weather = weather {
switch(weather.temp) {
case let t where t < 0:
p.fulfill( "Ice-skating time!" )
case 0..<10:
p.fulfill( "It's cold, get your scarf!" )
case 10..<15:
p.fulfill( "It's chilly, get your coat" )
default:
p.fulfill( "It's hot, go with a tee-shirt!" )
}
}
return p
}
func printResult<T>(label: String)(_ obj: T?) -> Promise<T?> {
let desc = (obj != nil) ? "\(obj!)" : "nil"
println("\(label)\(desc)")
return Promise(forwardValue: obj)
}
////////////////
// Demo
////////////////
fetchCityFromIP()
.then(printResult("Your current position is: "))
.then(fetchCurrentWeather)
.then(printResult("Current weather there: "))
.then(getWeatherTip)
.then(printResult("Tip of the day: "))
// If you are testing this in the Playground, add those lines so that the execution
// of the playground code waits for the asynchronous responses (instead of stopping
// before the web services asynchronous responses arrived)
import XCPlayground
XCPSetExecutionShouldContinueIndefinitely(continueIndefinitely: true)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment