Open vinhnx opened 8 years ago
[updated] see http://khanlou.com/2016/05/protocol-oriented-programming/ for an updated
protocol Request {
var baseURL: NSURL? { get }
var method: String { get }
var path: String { get }
var parameters: Dictionary<String, String> { get }
var headers: Dictionary<String, String> { get }
}
extension Request {
var method : String { return "GET" }
var path : String { return "" }
var parameters : Dictionary<String, String> { return Dictionary() }
var headers : Dictionary<String, String> { return Dictionary() }
}
protocol ConstructableRequest: Request {
func buildRequest() -> NSURLRequest?
}
protocol JSONConstructableRequest: ConstructableRequest { }
extension JSONConstructableRequest {
func buildRequest() -> NSURLRequest? {
guard let baseURL = baseURL else { return nil }
guard let URLComponents = NSURLComponents(URL: baseURL, resolvingAgainstBaseURL: true) else { return nil }
URLComponents.path = (URLComponents.path ?? "") + path
guard let URL = URLComponents.URL else { return nil }
let request = NSMutableURLRequest(URL: URL)
if method != "GET" {
request.HTTPBody = try? NSJSONSerialization.dataWithJSONObject(parameters, options: [])
}
request.HTTPMethod = method
return request
}
}
protocol ResultParsing {
associatedtype ParsedType
func parseData(data: NSData) -> ParsedType?
}
protocol StringParsing: ResultParsing { }
extension StringParsing {
func parseData(data: NSData) -> String? {
return NSString(data: data, encoding: NSUTF8StringEncoding) as? String
}
}
protocol JSONConstructable {
static func fromData(data: NSData) -> Self?
}
struct User: JSONConstructable {
static func fromData(data: NSData) -> User? {
return User()
}
}
struct Tweet: JSONConstructable {
static func fromData(data: NSData) -> Tweet? {
return Tweet()
}
}
protocol JSONParsing: ResultParsing {
associatedtype JSONType: JSONConstructable
func parseData(data: NSData) -> JSONType?
}
extension JSONParsing {
func parseData(data: NSData) -> JSONType? {
return JSONType.fromData(data)
}
}
protocol SendableRequest: ConstructableRequest, ResultParsing { }
extension SendableRequest {
func sendRequest(success success: (result: ParsedType) -> (), failure: (error: ErrorType) -> ()) {
let session = NSURLSession.sharedSession()
guard let request = buildRequest() else { return }
let task = session.dataTaskWithRequest(request, completionHandler: { (taskData, taskResponse, taskError) -> Void in
if let taskError = taskError {
failure (error: taskError)
} else if let taskData = taskData {
guard let result = self.parseData(taskData) else { return }
success(result: result)
}
})
task.resume()
}
}
struct ZenRequest: Request, JSONConstructableRequest, SendableRequest, StringParsing {
let baseURL = NSURL(string: "https://api.github.com/")
let path: String = "zen"
}
ZenRequest().sendRequest(
success: { string in
print(string)
},
failure: { error in
print(error)
})
struct UserRequest: Request, JSONConstructableRequest, SendableRequest, JSONParsing {
let baseURL = NSURL(string: "https://api.github.com/")
let path: String = "zen"
typealias JSONType = User
}
UserRequest().sendRequest(
success: { string in
print(string)
},
failure: { error in
print(error)
})
protocol oririented networking, http://khanlou.com/2015/06/protocol-oriented-networking/
Handle optional protocol in Swift via protocol extension http://ashfurrow.com/blog/protocols-and-swift/
protocol FoodConsumer {
var calorieCount: Double { get set }
var hydrationLevel: Double { get set }
}
protocol Food {
func beConsumedBy<T: FoodConsumer>(consumer: T, grams: Double) -> T
}
extension FoodConsumer {
func eat(food: Food, grams: Double) -> Self {
return food.beConsumedBy(self, grams: grams)
}
}
struct Cat: FoodConsumer {
var calorieCount: Double = 0
var hydrationLevel: Double = 0
}
struct Kibble: Food {
let caloriesPerGram: Double = 40
func beConsumedBy<T: FoodConsumer>(consumer: T, grams: Double) -> T {
var newConsumer = consumer
newConsumer.calorieCount += grams * caloriesPerGram
return newConsumer
}
}
struct FancyFeast: Food {
let caloriesPerGram: Double = 80
let milliLitresWaterPerGram: Double = 0.2
func beConsumedBy<T: FoodConsumer>(consumer: T, grams: Double) -> T {
var newConsumer = consumer
newConsumer.calorieCount += grams * caloriesPerGram
newConsumer.hydrationLevel += grams * milliLitresWaterPerGram
return newConsumer
}
}
let catFood = Kibble()
let wetFood = FancyFeast()
var dave = Cat()
dave = dave.eat(catFood, grams: 30)
dave = dave.eat(wetFood, grams: 20)
http://code.tutsplus.com/tutorials/protocol-oriented-programming-in-swift-2--cms-24979