Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 219e7fd5c1 |
@@ -27,6 +27,12 @@
|
||||
09D796071BC73E8B003C68EB /* StoryboardConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D796061BC73E8B003C68EB /* StoryboardConstants.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
09D7960D1BC7431C003C68EB /* FetchableTrait.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D7960C1BC7431C003C68EB /* FetchableTrait.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
09D796111BC97809003C68EB /* mainPilot.plist in Resources */ = {isa = PBXBuildFile; fileRef = 09D796101BC97809003C68EB /* mainPilot.plist */; settings = {ASSET_TAGS = (); }; };
|
||||
09D796131BC9A5BC003C68EB /* SWAPIPersonProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D796121BC9A5BC003C68EB /* SWAPIPersonProvider.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
09D796151BC9A5FC003C68EB /* NetworkLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D796141BC9A5FC003C68EB /* NetworkLayer.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
09D796171BC9B53D003C68EB /* URLSessionNetworkLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D796161BC9B53D003C68EB /* URLSessionNetworkLayer.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
09D796191BC9BA49003C68EB /* DependencyContainers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D796181BC9BA49003C68EB /* DependencyContainers.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
09D7961B1BC9BE65003C68EB /* SWAPIStarshipProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D7961A1BC9BE65003C68EB /* SWAPIStarshipProvider.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
09D7961D1BC9C62E003C68EB /* SWAPICommon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09D7961C1BC9C62E003C68EB /* SWAPICommon.swift */; settings = {ASSET_TAGS = (); }; };
|
||||
607FACEC1AFB9204008FA782 /* SWAPIWebServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 607FACEB1AFB9204008FA782 /* SWAPIWebServiceTests.swift */; };
|
||||
7BBD849465D99D9D1987AE6D /* Pods_DipTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 304AD039660A2C58EB08D985 /* Pods_DipTests.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
|
||||
84D8EBE5B2D583BEFB17C45A /* Pods_DipSampleApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FE9C70E965FF88C3F20AC76 /* Pods_DipSampleApp.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
|
||||
@@ -56,6 +62,12 @@
|
||||
09D796061BC73E8B003C68EB /* StoryboardConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryboardConstants.swift; sourceTree = "<group>"; };
|
||||
09D7960C1BC7431C003C68EB /* FetchableTrait.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchableTrait.swift; sourceTree = "<group>"; };
|
||||
09D796101BC97809003C68EB /* mainPilot.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = mainPilot.plist; sourceTree = "<group>"; };
|
||||
09D796121BC9A5BC003C68EB /* SWAPIPersonProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SWAPIPersonProvider.swift; sourceTree = "<group>"; };
|
||||
09D796141BC9A5FC003C68EB /* NetworkLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkLayer.swift; sourceTree = "<group>"; };
|
||||
09D796161BC9B53D003C68EB /* URLSessionNetworkLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLSessionNetworkLayer.swift; sourceTree = "<group>"; };
|
||||
09D796181BC9BA49003C68EB /* DependencyContainers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DependencyContainers.swift; sourceTree = "<group>"; };
|
||||
09D7961A1BC9BE65003C68EB /* SWAPIStarshipProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SWAPIStarshipProvider.swift; sourceTree = "<group>"; };
|
||||
09D7961C1BC9C62E003C68EB /* SWAPICommon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SWAPICommon.swift; sourceTree = "<group>"; };
|
||||
2FE9C70E965FF88C3F20AC76 /* Pods_DipSampleApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DipSampleApp.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
304AD039660A2C58EB08D985 /* Pods_DipTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_DipTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
607FACE51AFB9204008FA782 /* DipTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DipTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -103,9 +115,11 @@
|
||||
0900121A1BC6FECA0079C600 /* Providers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
09D7961C1BC9C62E003C68EB /* SWAPICommon.swift */,
|
||||
090012371BC6FEEA0079C600 /* APIs */,
|
||||
090012381BC6FEFD0079C600 /* PersonProviders */,
|
||||
090012391BC6FF080079C600 /* StarshipProviders */,
|
||||
09D796161BC9B53D003C68EB /* URLSessionNetworkLayer.swift */,
|
||||
);
|
||||
path = Providers;
|
||||
sourceTree = "<group>";
|
||||
@@ -125,6 +139,7 @@
|
||||
children = (
|
||||
0900121B1BC6FECA0079C600 /* PersonProviderAPI.swift */,
|
||||
0900123C1BC7012A0079C600 /* StarshipProviderAPI.swift */,
|
||||
09D796141BC9A5FC003C68EB /* NetworkLayer.swift */,
|
||||
);
|
||||
name = APIs;
|
||||
sourceTree = "<group>";
|
||||
@@ -134,6 +149,7 @@
|
||||
children = (
|
||||
0900121C1BC6FECA0079C600 /* DummyPilotProvider.swift */,
|
||||
0900121E1BC6FECA0079C600 /* PlistPersonProvider.swift */,
|
||||
09D796121BC9A5BC003C68EB /* SWAPIPersonProvider.swift */,
|
||||
);
|
||||
name = PersonProviders;
|
||||
sourceTree = "<group>";
|
||||
@@ -143,6 +159,7 @@
|
||||
children = (
|
||||
090012431BC708A00079C600 /* DummyStarshipProvider.swift */,
|
||||
0900121D1BC6FECA0079C600 /* HardCodedStarshipProvider.swift */,
|
||||
09D7961A1BC9BE65003C68EB /* SWAPIStarshipProvider.swift */,
|
||||
);
|
||||
name = StarshipProviders;
|
||||
sourceTree = "<group>";
|
||||
@@ -161,6 +178,7 @@
|
||||
children = (
|
||||
0900123A1BC6FF4D0079C600 /* Main.storyboard */,
|
||||
099022611BC123C000E76F43 /* AppDelegate.swift */,
|
||||
09D796181BC9BA49003C68EB /* DependencyContainers.swift */,
|
||||
0900123E1BC704A80079C600 /* Model */,
|
||||
0900121A1BC6FECA0079C600 /* Providers */,
|
||||
090012201BC6FECA0079C600 /* ViewControllers */,
|
||||
@@ -442,15 +460,19 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
09D796151BC9A5FC003C68EB /* NetworkLayer.swift in Sources */,
|
||||
09D795FF1BC71F5A003C68EB /* PersonListViewController.swift in Sources */,
|
||||
0900122A1BC6FECA0079C600 /* PersonCell.swift in Sources */,
|
||||
09D796011BC722C0003C68EB /* StarshipListViewController.swift in Sources */,
|
||||
0900122C1BC6FECA0079C600 /* PersonProviderAPI.swift in Sources */,
|
||||
09D7961D1BC9C62E003C68EB /* SWAPICommon.swift in Sources */,
|
||||
090012291BC6FECA0079C600 /* BaseCell.swift in Sources */,
|
||||
0900122D1BC6FECA0079C600 /* DummyPilotProvider.swift in Sources */,
|
||||
099022621BC123C000E76F43 /* AppDelegate.swift in Sources */,
|
||||
09D796131BC9A5BC003C68EB /* SWAPIPersonProvider.swift in Sources */,
|
||||
090012421BC7059E0079C600 /* Starship.swift in Sources */,
|
||||
0900123D1BC7012A0079C600 /* StarshipProviderAPI.swift in Sources */,
|
||||
09D7961B1BC9BE65003C68EB /* SWAPIStarshipProvider.swift in Sources */,
|
||||
0900122E1BC6FECA0079C600 /* HardCodedStarshipProvider.swift in Sources */,
|
||||
09D796071BC73E8B003C68EB /* StoryboardConstants.swift in Sources */,
|
||||
09D796031BC72691003C68EB /* StarshipCell.swift in Sources */,
|
||||
@@ -458,6 +480,8 @@
|
||||
090012441BC708A00079C600 /* DummyStarshipProvider.swift in Sources */,
|
||||
09D7960D1BC7431C003C68EB /* FetchableTrait.swift in Sources */,
|
||||
0900122F1BC6FECA0079C600 /* PlistPersonProvider.swift in Sources */,
|
||||
09D796191BC9BA49003C68EB /* DependencyContainers.swift in Sources */,
|
||||
09D796171BC9B53D003C68EB /* URLSessionNetworkLayer.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -1,30 +1,12 @@
|
||||
//
|
||||
// AppDelegate.swift
|
||||
// DipSampleApp
|
||||
// Dip
|
||||
//
|
||||
// Created by Olivier Halligon on 04/10/2015.
|
||||
// Copyright © 2015 AliSoftware. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Dip
|
||||
|
||||
let dip: DependencyContainer<Int> = {
|
||||
let dip = DependencyContainer<Int>()
|
||||
|
||||
// 1) Register the PersonProviderAPI singleton, one generic and one specific for a specific personID
|
||||
dip.register(instance: DummyPilotProvider() as PersonProviderAPI)
|
||||
let mainPersonProvider = PlistPersonProvider(plist: "mainPilot")
|
||||
dip.register(0, instance: mainPersonProvider as PersonProviderAPI)
|
||||
|
||||
// 2) Register the StarshipProviderAPI factories, one generic and one specific for a specific starshipID
|
||||
dip.register() { HardCodedStarshipProvider() as StarshipProviderAPI }
|
||||
let pilotName = mainPersonProvider.people[0].name
|
||||
dip.register(0) { DummyStarshipProvider(pilotName: pilotName) as StarshipProviderAPI }
|
||||
|
||||
return dip
|
||||
}()
|
||||
|
||||
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// DependencyContainers.swift
|
||||
// Dip
|
||||
//
|
||||
// Created by Olivier Halligon on 10/10/2015.
|
||||
// Copyright © 2015 AliSoftware. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Dip
|
||||
|
||||
|
||||
enum WebService {
|
||||
case PersonWS
|
||||
case StarshipWS
|
||||
}
|
||||
|
||||
// Dependency Container for WebServices & NetworkLayer
|
||||
let wsDependencies: DependencyContainer<WebService> = {
|
||||
let dip = DependencyContainer<WebService>()
|
||||
|
||||
// Register the NetworkLayer, same for everyone here (but we have the ability to register a different one for a specific WebService if we wanted to)
|
||||
dip.register(instance: URLSessionNetworkLayer(baseURL: "http://swapi.co/api/")! as NetworkLayer)
|
||||
|
||||
return dip
|
||||
}()
|
||||
|
||||
|
||||
|
||||
/* Change this to toggle between real and fake data */
|
||||
let FAKE_PERSONS = false
|
||||
let FAKE_STARSHIPS = false
|
||||
|
||||
|
||||
// Dependency Container for Providers
|
||||
let providerDependencies: DependencyContainer<Int> = {
|
||||
let dip = DependencyContainer<Int>()
|
||||
|
||||
if FAKE_PERSONS {
|
||||
|
||||
// 1) Register the PersonProviderAPI singleton, one generic and one specific for a specific personID
|
||||
dip.register(instance: DummyPilotProvider() as PersonProviderAPI)
|
||||
dip.register(0, instance: PlistPersonProvider(plist: "mainPilot") as PersonProviderAPI)
|
||||
|
||||
} else {
|
||||
|
||||
// 1) Register the SWAPIPersonProvider (that hits the real swapi.co WebService)
|
||||
dip.register(instance: SWAPIPersonProvider() as PersonProviderAPI)
|
||||
|
||||
}
|
||||
|
||||
if FAKE_STARSHIPS {
|
||||
|
||||
// 2) Register the StarshipProviderAPI factories, one generic and one specific for a specific starshipID
|
||||
dip.register() { HardCodedStarshipProvider() as StarshipProviderAPI }
|
||||
dip.register(0) { DummyStarshipProvider(pilotName: "Main Pilot") as StarshipProviderAPI }
|
||||
|
||||
} else {
|
||||
|
||||
// 2) Register the SWAPIStarshipProvider (that hits the real swapi.co WebService)
|
||||
dip.register(instance: SWAPIStarshipProvider() as StarshipProviderAPI)
|
||||
|
||||
}
|
||||
|
||||
return dip
|
||||
}()
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// NetworkLayer.swift
|
||||
// Dip
|
||||
//
|
||||
// Created by Olivier Halligon on 10/10/2015.
|
||||
// Copyright © 2015 AliSoftware. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum NetworkResponse {
|
||||
case Success(NSData, NSHTTPURLResponse)
|
||||
case Error(NSError)
|
||||
|
||||
func unwrap() throws -> (NSData, NSHTTPURLResponse) {
|
||||
switch self {
|
||||
case Success(let data, let response):
|
||||
return (data, response)
|
||||
case Error(let error):
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
func json() throws -> AnyObject {
|
||||
let (data, _) = try self.unwrap()
|
||||
return try NSJSONSerialization.JSONObjectWithData(data, options: [])
|
||||
}
|
||||
}
|
||||
|
||||
protocol NetworkLayer {
|
||||
func request(path: String, completion: NetworkResponse -> Void)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// SWAPICommon.swift
|
||||
// Dip
|
||||
//
|
||||
// Created by Olivier Halligon on 11/10/2015.
|
||||
// Copyright © 2015 AliSoftware. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum SWAPIError: ErrorType {
|
||||
case InvalidJSON
|
||||
}
|
||||
|
||||
func idFromURLString(urlString: String) -> Int? {
|
||||
let url = NSURL(string: urlString)
|
||||
let idString = url.flatMap { $0.lastPathComponent }
|
||||
return idString.flatMap { Int($0) }
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// SWAPIPersonProvider.swift
|
||||
// Dip
|
||||
//
|
||||
// Created by Olivier Halligon on 10/10/2015.
|
||||
// Copyright © 2015 AliSoftware. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct SWAPIPersonProvider : PersonProviderAPI {
|
||||
let ws = wsDependencies.resolve(.PersonWS) as NetworkLayer
|
||||
|
||||
func fetchIDs(completion: [Int] -> Void) {
|
||||
ws.request("people") { response in
|
||||
do {
|
||||
let dict = try response.json()
|
||||
guard let results = dict["results"] as? [NSDictionary] else { throw SWAPIError.InvalidJSON }
|
||||
|
||||
// Extract URLs (flatten to ignore invalid ones)
|
||||
let urlStrings = results.flatMap({ $0["url"] as? String })
|
||||
let ids = urlStrings.flatMap(idFromURLString)
|
||||
|
||||
completion(ids)
|
||||
}
|
||||
catch {
|
||||
completion([])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fetch(id: Int, completion: Person? -> Void) {
|
||||
ws.request("people/\(id)") { response in
|
||||
do {
|
||||
let json = try response.json()
|
||||
guard let dict = json as? NSDictionary,
|
||||
let name = dict["name"] as? String,
|
||||
let heightStr = dict["height"] as? String, height = Int(heightStr),
|
||||
let massStr = dict["mass"] as? String, mass = Int(massStr),
|
||||
let hairColor = dict["hair_color"] as? String,
|
||||
let eyeColor = dict["eye_color"] as? String,
|
||||
let gender = dict["gender"] as? String,
|
||||
let starshipURLStrings = dict["starships"] as? [String]
|
||||
else {
|
||||
throw SWAPIError.InvalidJSON
|
||||
}
|
||||
|
||||
let person = Person(
|
||||
name: name,
|
||||
height: height,
|
||||
mass: mass,
|
||||
hairColor: hairColor,
|
||||
eyeColor: eyeColor,
|
||||
gender: Gender(rawValue: gender),
|
||||
starshipIDs: starshipURLStrings.flatMap(idFromURLString)
|
||||
)
|
||||
completion(person)
|
||||
}
|
||||
catch {
|
||||
completion(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// SWAPIStarshipProvider.swift
|
||||
// Dip
|
||||
//
|
||||
// Created by Olivier Halligon on 10/10/2015.
|
||||
// Copyright © 2015 AliSoftware. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct SWAPIStarshipProvider : StarshipProviderAPI {
|
||||
let ws = wsDependencies.resolve(.StarshipWS) as NetworkLayer
|
||||
|
||||
func fetchIDs(completion: [Int] -> Void) {
|
||||
ws.request("starships") { response in
|
||||
do {
|
||||
let dict = try response.json()
|
||||
guard let results = dict["results"] as? [NSDictionary] else { throw SWAPIError.InvalidJSON }
|
||||
|
||||
// Extract URLs (flatten to ignore invalid ones)
|
||||
let urlStrings = results.flatMap({ $0["url"] as? String })
|
||||
let ids = urlStrings.flatMap(idFromURLString)
|
||||
|
||||
completion(ids)
|
||||
}
|
||||
catch {
|
||||
completion([])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fetch(id: Int, completion: Starship? -> Void) {
|
||||
ws.request("starships/\(id)") { response in
|
||||
do {
|
||||
let json = try response.json()
|
||||
guard let dict = json as? NSDictionary,
|
||||
let name = dict["name"] as? String,
|
||||
let model = dict["model"] as? String,
|
||||
let manufacturer = dict["manufacturer"] as? String,
|
||||
let crewStr = dict["crew"] as? String, crew = Int(crewStr),
|
||||
let passengersStr = dict["passengers"] as? String, passengers = Int(passengersStr),
|
||||
let pilotIDStrings = dict["pilots"] as? [String]
|
||||
else {
|
||||
throw SWAPIError.InvalidJSON
|
||||
}
|
||||
|
||||
let ship = Starship(
|
||||
name: name,
|
||||
model: model,
|
||||
manufacturer: manufacturer,
|
||||
crew: crew,
|
||||
passengers: passengers,
|
||||
pilotIDs: pilotIDStrings.flatMap(idFromURLString)
|
||||
)
|
||||
completion(ship)
|
||||
}
|
||||
catch {
|
||||
completion(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// URLSessionNetworkLayer.swift
|
||||
// Dip
|
||||
//
|
||||
// Created by Olivier Halligon on 10/10/2015.
|
||||
// Copyright © 2015 AliSoftware. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct URLSessionNetworkLayer : NetworkLayer {
|
||||
let baseURL: NSURL
|
||||
let session: NSURLSession
|
||||
let responseQueue: dispatch_queue_t
|
||||
|
||||
init?(baseURL: String, session: NSURLSession = .sharedSession(), responseQueue: dispatch_queue_t = dispatch_get_main_queue()) {
|
||||
guard let url = NSURL(string: baseURL) else { return nil }
|
||||
self.init(baseURL: url, session: session)
|
||||
}
|
||||
|
||||
init(baseURL: NSURL, session: NSURLSession = .sharedSession(), responseQueue: dispatch_queue_t = dispatch_get_main_queue()) {
|
||||
self.baseURL = baseURL
|
||||
self.session = session
|
||||
self.responseQueue = responseQueue
|
||||
}
|
||||
|
||||
func request(path: String, completion: NetworkResponse -> Void) {
|
||||
let url = self.baseURL.URLByAppendingPathComponent(path)
|
||||
let task = session.dataTaskWithURL(url) { data, response, error in
|
||||
if let data = data, let response = response as? NSHTTPURLResponse {
|
||||
dispatch_async(self.responseQueue) {
|
||||
completion(NetworkResponse.Success(data, response))
|
||||
}
|
||||
}
|
||||
else {
|
||||
let err = error ?? NSError(domain: NSURLErrorDomain, code: NSURLError.Unknown.rawValue, userInfo: nil)
|
||||
dispatch_async(self.responseQueue) {
|
||||
completion(NetworkResponse.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
task.resume()
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ protocol FetchableTrait: class {
|
||||
|
||||
var fetchIDs: ([Int] -> Void) -> Void { get }
|
||||
var fetchOne: (Int, ObjectType? -> Void) -> Void { get }
|
||||
var fetchProgress: (current: Int, total: Int?) { get set }
|
||||
}
|
||||
|
||||
extension FetchableTrait {
|
||||
@@ -24,6 +25,7 @@ extension FetchableTrait {
|
||||
let batch = self.batchRequestID
|
||||
|
||||
objects?.removeAll()
|
||||
fetchProgress = (0,objectIDs.count)
|
||||
for objectID in objectIDs {
|
||||
fetchOne(objectID) { (object: ObjectType?) in
|
||||
// Exit if we failed to retrive an object for this ID, or if the request
|
||||
@@ -32,6 +34,7 @@ extension FetchableTrait {
|
||||
|
||||
if self.objects == nil { self.objects = [] }
|
||||
self.objects?.append(object)
|
||||
self.fetchProgress = (self.objects?.count ?? 0, objectIDs.count)
|
||||
self.tableView?.reloadData()
|
||||
}
|
||||
}
|
||||
@@ -40,10 +43,29 @@ extension FetchableTrait {
|
||||
func fetchAllObjects() {
|
||||
self.batchRequestID += 1
|
||||
let batch = self.batchRequestID
|
||||
|
||||
fetchProgress = (0, nil)
|
||||
fetchIDs() { objectIDs in
|
||||
guard batch == self.batchRequestID else { return }
|
||||
self.fetchObjects(objectIDs)
|
||||
}
|
||||
}
|
||||
|
||||
func displayProgressInNavBar(navigationItem: UINavigationItem) {
|
||||
let text: String
|
||||
if let total = fetchProgress.total {
|
||||
if fetchProgress.current == fetchProgress.total {
|
||||
text = "Done."
|
||||
} else {
|
||||
text = "Loading \(fetchProgress.current) / \(total)…"
|
||||
}
|
||||
} else {
|
||||
text = "Loading IDs…"
|
||||
}
|
||||
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
|
||||
label.text = text
|
||||
label.textColor = .grayColor()
|
||||
label.font = .systemFontOfSize(12)
|
||||
label.sizeToFit()
|
||||
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: label)
|
||||
}
|
||||
}
|
||||
@@ -12,11 +12,17 @@ class PersonListViewController: UITableViewController, FetchableTrait {
|
||||
var objects: [Person]?
|
||||
var batchRequestID = 0
|
||||
|
||||
lazy var fetchIDs: ([Int] -> Void) -> Void = (dip.resolve() as PersonProviderAPI).fetchIDs
|
||||
lazy var fetchIDs: ([Int] -> Void) -> Void = (providerDependencies.resolve() as PersonProviderAPI).fetchIDs
|
||||
lazy var fetchOne: (Int, Person? -> Void) -> Void = { personID, completion in
|
||||
let provider = dip.resolve(personID) as PersonProviderAPI
|
||||
let provider = providerDependencies.resolve(personID) as PersonProviderAPI
|
||||
return provider.fetch(personID, completion: completion)
|
||||
}
|
||||
|
||||
var fetchProgress: (current: Int, total: Int?) = (0, nil) {
|
||||
didSet {
|
||||
displayProgressInNavBar(self.navigationItem)
|
||||
}
|
||||
}
|
||||
|
||||
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
|
||||
guard
|
||||
|
||||
@@ -12,13 +12,19 @@ class StarshipListViewController : UITableViewController, FetchableTrait {
|
||||
var objects: [Starship]?
|
||||
var batchRequestID = 0
|
||||
|
||||
var provider: (Int? -> StarshipProviderAPI) = { dip.resolve($0) }
|
||||
var provider: (Int? -> StarshipProviderAPI) = { providerDependencies.resolve($0) }
|
||||
|
||||
lazy var fetchIDs: ([Int] -> Void) -> Void = self.provider(nil).fetchIDs
|
||||
lazy var fetchOne: (Int, Starship? -> Void) -> Void = { shipID, completion in
|
||||
self.provider(shipID).fetch(shipID, completion: completion)
|
||||
}
|
||||
|
||||
var fetchProgress: (current: Int, total: Int?) = (0, nil) {
|
||||
didSet {
|
||||
displayProgressInNavBar(self.navigationItem)
|
||||
}
|
||||
}
|
||||
|
||||
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
|
||||
guard
|
||||
let id = segue.identifier, segueID = UIStoryboard.Segue.Main(rawValue: id)
|
||||
|
||||
Reference in New Issue
Block a user