Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Build Better Apps Faster

Build Better Apps Faster

Pierluigi Cifani

May 30, 2016
Tweet

More Decks by Pierluigi Cifani

Other Decks in Programming

Transcript

  1. IN ANY UITableViewDataSource - (void)requestWithCompletionBlock:(AAPLCompletionBlock)block { self.executingRequest = YES; [self

    showLoadingView]; [self requestUsersWithPage:self.currentPagination completionBlock:^(NSArray *array, NSError *error) { if (error) { [self showError]; } else { self.array = array; [self.tableView reloadData]; } self.executingRequest = NO; block(array, error); }]; }
  2. private func fetchData() { collectionView.state = .Loading searchUserInteractor.fetchLocationAndUsers() { [weak

    self] result in guard let strongSelf = self else { return } switch result { case .Failure(let error): strongSelf.collectionView.state = .Failure(error: error) case .Success(let users): strongSelf.collectionView.state = .Loaded(data: users) } } }
  3. However, last time I tried to do collectionView.state = .Loading

    this happened: error: value of type 'UICollectionView' has no member 'state' collectionView.state = .Loading ^~~~~~~~~~~~~~ ~~~~~ !!!!!!
  4. OBJECTIVES: 1. Enforce MVVM1 2. Map one model object to

    one cell kind at compile time 3. Support for ListState 4. Customization for the .Loading and .Error state 5. Independence from any Layout 1 The one good thing that came out of Microsoft.
  5. ENFORCE MVVM public protocol ViewModelConfigurable { associatedtype VM func configureFor(viewModel

    viewModel: VM) -> Void } public protocol ViewModelReusable: ViewModelConfigurable { static var reuseType: ReuseType { get } static var reuseIdentifier: String { get } } public enum ReuseType { case NIB(UINib) case ClassReference(AnyClass) }
  6. //MARK:- Extensions extension ViewModelReusable where Self: UICollectionViewCell { public static

    var reuseIdentifier: String { return NSStringFromClass(self) } public static var reuseType: ReuseType { return .ClassReference(Self) } }
  7. class CollectionViewStatefulDataSource <Model, Cell:ViewModelReusable where Cell:UICollectionViewCell > { typealias ModelMapper

    = (Model) -> (Cell.VM) weak var collectionView: UICollectionView? let mapper: ModelMapper var state: ListState<Model> { didSet { collectionView?.reloadData() } } }
  8. ConfigurationLogic *logic = [ConfigurationLogic currentConfiguration]; [NetworkFetcher callService:@"/users" host:[logic baseURL] method:GET

    postData:nil bodyInJSON:NO hasCache:YES timeoutInterval:[logic servicesTimeOut] successHandler:successHandler failureHandler:failureHandler];
  9. func lookForStockForSymbols (symbol : String, handler : FetchSymbolHandler?) -> StockFetcherOperation

    { let parameters = [ "input" : symbol ] let request = networkFetcher.request( .GET, "http://dev.markitondemand.com/Api/v2/Lookup/json", parameters:parameters , encoding:.URL ) request.responseJSON { (_, _, operationResult) -> Void in /** Some code */ } return StockFetcherOperation(request: request) }
  10. /** Protocol used to describe what is needed in order

    to send REST API requests. */ public protocol Endpoint { /// The path for the request var path: String { get } /// The HTTPMethod for the request var method: HTTPMethod { get } /// Optional parameters for the request var parameters: [String : AnyObject]? { get } /// How the parameters should be encoded var parameterEncoding: HTTPParameterEncoding { get } /// The HTTP headers to be sent var httpHeaderFields: [String : String]? { get } }
  11. // This is the default implementation for Endpoint extension Endpoint

    { public var method: HTTPMethod { return .GET } var parameters: [String : AnyObject]? { return nil } public var parameterEncoding: HTTPParameterEncoding { return .URL } public var httpHeaderFields: [String : String]? { return nil } }
  12. extension AuthenticationAPI: Endpoint { var path: String { switch self

    { case .LoginFacebook(_): return "/authentication" } } var method: HTTPMethod { switch self { case .LoginFacebook(_): return .POST } } var parameters: [String : AnyObject]? { switch self { case .LoginFacebook(let token): return [ "token" : token ] } } }
  13. extension UsersAPI: Endpoint { public var path: String { switch

    self { case .SearchUsers(_): return "/users" case .UserDetails(let uuid): return "/users/\(uuid)" case .UserPictures(let uuid): return "/users/\(uuid)/pictures" } } public var parameters: [String : AnyObject]? { switch self { case .SearchUsers(let filter): var params = [String : AnyObject]() params["min_age"] = filter.minAge params["max_age"] = filter.maxAge params["min_dist"] = filter.minDistance params["max_dist"] = filter.maxDistance params["lat"] = filter.latitude params["long"] = filter.longitude return params default: return nil } } }
  14. "Apps interacting with web services are encouraged to have custom

    types conform to URLRequestConvertible as a way to ensure consistency of requested endpoints." -- @mattt2 2 Alamofire's Readme.
  15. /** Types adopting the `URLRequestConvertible` protocol can be used to

    construct URL requests. */ public protocol URLRequestConvertible { /// The URL request. var URLRequest: NSMutableURLRequest { get } } protocol Endpoint: URLRequestConvertible { /* The other stuff */ var URLRequest: NSMutableURLRequest { let request = NSMutableURLRequest(URL: NSURL(string: path)!) request.HTTPMethod = method.rawValue request.allHTTPHeaderFields = httpHeaderFields let requestTuple = parameterEncoding.encode(request, parameters: parameters) return requestTuple.0 } }