Protocol Oriented Programing - POP (Tales Pinheiro)
-
Upload
concrete-solutions -
Category
Technology
-
view
86 -
download
0
Transcript of Protocol Oriented Programing - POP (Tales Pinheiro)
Protocol Oriented Programming
Colocando em prática
Conteúdo
• Tales Pinheiro de Andrade
• @talesp, [email protected] • - Mestre em computação pelo IME-USP
• - Líder do Capítulo iOS na Concrete Solutions
• - Líder do Capítulo São Paulo do CocoaHeads Brasil • - Desenvolvedor C desde 2002
• - Objective-C desde 2007 (coisas básicas antes do iPhone!)
• - Swift desde 08/2015
• - iOS desde 2010
O que é?
– Protocolos
– contratos, assinaturas
– Já existiam no Objective-C – Categorias – Protocolos – Extensões
Classe
#import <Foundation/Foundation.h>
@interface Foo : NSObject
- (void)doSomething;
@end
#import "Foo.h"
@implementation Foo
- (void)doSomething { NSLog(@"doSomething"); }
@end
Categoria
#import "Foo.h"
@interface Foo (Bar)
- (void)doSomethingElse;
@end
#import "Foo+Bar.h"
@implementation Foo (Bar)
- (void)doSomethingElse { NSLog(@"doSomethingElse"); }
@end
Extensão
@interface Foo ()
- (void)privatelyDoAnotherThing;
@end
Extensão@interface Foo ()
- (void)privatelyDoAnotherThing;
@end
@implementation Foo
- (void)doSomething { NSLog(@"doSomething"); }
- (void)privatelyDoAnotherThing { NSLog(@"privatelyDoAnotherThing"); }
@end
Extensão
@protocol Baz <NSObject>
- (void)doAnotherThing;
@end
Classe
#import <Foundation/Foundation.h> #import "Baz.h"
@interface Wibbly : NSObject <Baz>
@end
@implementation Wibbly
- (void)doAnotherThing { //empty }
@end
E no Swift?
“Novidades” do Swift 1.0 ~ 1.2
• Unifica as categories e extensions
• Remove separação de interface/implementação
• Não é necessário declarar a extensão
“Novidades” do Swift 1.0 ~ 1.2
protocol Wheeled { var numberOfWheels: Int { get } }
class Car: Wheeled { let numberOfWheels = 4 }
class Motorcycle: Wheeled { let numberOfWheels = 2 }
“Novidades” do Swift 1.0 ~ 1.2
protocol Wheeled { var numberOfWheels: Int { get } }
class Car: Wheeled { let numberOfWheels = 4 }
class Motorcycle: Wheeled { }
“Novidades” do Swift 1.0 ~ 1.2
class Hello { }
extension Hello { static func world() { print("Hello, world") } }
Hello.world() //"Hello, world\n"
E no Swift 2.0?
class Hello { }
extension Hello { static func world() { print("Hello, world") } }
Hello.world() //"Hello, world\n"
E no Swift 2.0?
protocol Greeter { }
class Car: Greeter { }
class Motorcycle: Greeter { }
Extendendo um protocolo Implementação padrão
extension Greeter { static func greeting() { print("Hello, \(String(describing: self))") } }
Extendendo um protocolo Implementação padrão
extension Greeter { static func greeting() { print("Hello, \(String(describing: self))") } } Car.greeting() //Hello, Car
Extendendo um protocolo Implementação padrão
extension Greeter { static func greeting() { print("Hello, \(String(describing: self))") } } Car.greeting() //Hello, Car Motorcycle.greeting() //Hello, Motorcycle
Protocol Oriented Programming
Extensão de protocolos com implementações padrão
POP Everything
• Views
• Networking
• Models
POPing table view controllers
class DataViewcontroller: UITableViewController { override func viewDidLoad() { super.viewDidLoad() let dataCellNIB = UINib(nibName: "DataCell", bundle: nil) tableView.register(dataCellNIB, forCellReuseIdentifier: "DataCell") } }
POPing table view controllers
class DataViewcontroller: UITableViewController { override func viewDidLoad() { super.viewDidLoad() let dataCellNIB = UINib(nibName: String(describing: DataCell.self), bundle: nil) tableView.register(dataCellNIB, forCellReuseIdentifier: String(describing: DataCell.self)) } }
POPing table view controllers
protocol ReusableView: class {}
extension ReusableView where Self: UIView { static var reuseIdentifier: String { return String(describing: self) } }
POPing table view controllers
protocol ReusableView: class {}
extension ReusableView where Self: UIView { static var reuseIdentifier: String { return String(describing: self) } }
extension UITableViewCell: ReusableView {} DataCell.reuseIdentifier
POPing table view controllers
class DataViewcontroller: UITableViewController { override func viewDidLoad() { super.viewDidLoad() let dataCellNIB = UINib(nibName: String(describing: DataCell.self), bundle: nil) tableView.register(dataCellNIB, forCellReuseIdentifier: DataCell.reuseIdentifier) } }
POPing table view controllers
protocol NibLoadableView: class {}
extension NibLoadableView where Self: UIView { static var nibName: String { return String(describing: self) } }
extension UITableViewCell: ReusableView {} DataCell.nibName
POPing table view controllers
class DataViewcontroller: UITableViewController { override func viewDidLoad() { super.viewDidLoad() let dataCellNIB = UINib(nibName: DataCell.nibName, bundle: nil) tableView.register(dataCellNIB, forCellReuseIdentifier: DataCell.reuseIdentifier) } }
POPing table view controllers
extension UITableView { func register<T: UITableViewCell>(class: T.Type) where T: ReusableView, T: NibLoadableView {
let nib = UINib(nibName: T.nibName, bundle: nil) register(nib, forCellReuseIdentifier: T.reuseIdentifier)
} }
POPing table view controllers
let dataCellNIB = UINib(nibName: "DataCell", bundle: nil) tableView.register(dataCellNIB, forCellReuseIdentifier: "DataCell")
POPing table view controllers
tableView.register(class: DataCell.self)
POPing table view controllers
extension UITableView { func dequeueReusableCell<T: UITableViewCell>(forIndexPath indexPath: IndexPath) -> T where T: ReusableView { guard let cell = dequeueReusableCell(withIdentifier: T.reuseIdentifier, for: indexPath) as? T else { fatalError("Could not dequeue cell with identifier: \(T.reuseIdentifier)") } return cell } }
POPing table view controllers
extension DataViewcontroller { override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "DataCel", for: indexPath) as? DataCell else { fatalError("Could not dequeue cell with identifier: DataCell") } return cell } }
POPing table view controllers
extension DataViewcontroller { override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { return tableView.dequeueReusableCell(forIndexPath: indexPath) as DataCell } }
POPing networking
class Session { static func sendRequest<R: Request>(request: R, handler: (Result<R.Response, Error>) -> Void) { } }
POPing networking
let request = CreateBucketRequest(name: "Bucket", description: "My short description")
Session.sendRequest(request: request) { result in switch result { case let .success(response): // show response break case let .failure(error): // handle error break } }
POPing networking
protocol Request { associatedtype Response var baseURL: URL { get } var method: HTTPMethod { get } var path: String { get } var paramenters: [String : Any] { get } func responseFromObject(object: AnyObject, URLResponse: HTTPURLResponse) throws -> Response }
POPing networking
struct CreateBucketRequest: Request {
var baseURL = URL(string: "https: //api.dribbble.com/v1")! var method: HTTPMethod = .POST var path = "/buckets" var paramenters = [String : Any]() init(name: String, description: String) { paramenters["name"] = name paramenters["description"] = description } func responseFromObject(object: AnyObject, URLResponse: HTTPURLResponse) throws -> Bucket { guard let bucketDictionary = object as? [String : Any] else { throw ServiceError.InvalidObject(object) } let issue = Bucket(dictionary: bucketDictionary) return issue } }
POPing networking
extension Request { var baseURL: URL { return URL(string: "https: //api.dribbble.com/v1")! } }
POPing networking
extension Request where Response: Decodable { func responseFromObject(object: AnyObject, URLResponse: HTTPURLResponse) throws -> Bucket { return try Response.decode(object: object) as! Bucket } }
POPing model
protocol Decodable { static func decode(object: AnyObject) throws -> Self }
POPing model
protocol Decodable { static func decode(object: AnyObject) throws -> Self }
struct Bucket: Decodable { let id: Int var name: String var shots: [Shot] // ... static func decode(object: AnyObject) throws -> Bucket { var bucket = Bucket() //parsing ... return bucket } }
POPing model
extension Collection where Iterator.Element: Shot { func filter(tag: String) -> [Iterator.Element] { let result = self.filter { shot in return shot.tags.contains(tag) } return result } }
POPing model
extension Collection where Iterator.Element: Shot { func filter(tag: String) -> [Iterator.Element] { let result = self.filter { shot in return shot.tags.contains(tag) } return result } }
let bucket = Bucket() let shots = try! bucket.shots.filter(tag: "nature")
POPing model
extension Collection where Iterator.Element: Bucket { func filter(tag: String) -> [Bucket] { return self.filter { bucket in return bucket.shots.filter(tag: tag).count > 0 } } }
POPing model
extension Collection where Iterator.Element: Bucket { func filter(tag: String) -> [Bucket] { return self.filter { bucket in return bucket.shots.filter(tag: tag).count > 0 } } }
let buckets: [Bucket] = ... let natureBuckets = buckets.filter(tag: "nature")
Conclusão
• POP é MUITO util
• principalmente com generics, mas isso fica para depois
• Elimina boilerplate
• Composição, flexibilidade dinamismo
• Apliquem :D
Obrigado :D
www.concretesolutions.com.br blog.concretesolutions.com.br
Rio de Janeiro – Rua São José, 90 – cj. 2121 Centro – (21) 2240-2030
São Paulo - Rua Sansão Alves dos Santos, 433 4º andar - Brooklin - (11) 4119-0449