Skip to content

Commit 5a401dc

Browse files
committed
Implemented questions retrieval and presentation
1 parent c1bbaa9 commit 5a401dc

22 files changed

Lines changed: 963 additions & 275 deletions

File tree

NetworkingInOperations-Example.xcodeproj/project.pbxproj

Lines changed: 182 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,21 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10-
C284F0A220F63CBB009AF6E9 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C284F09520F63CBB009AF6E9 /* DetailViewController.swift */; };
11-
C284F0A320F63CBB009AF6E9 /* MasterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C284F09620F63CBB009AF6E9 /* MasterViewController.swift */; };
10+
3DA271FC20F7D1E6001642D8 /* QueueManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DA271F920F7D1E6001642D8 /* QueueManager.swift */; };
11+
3DFEAD1F210DE0310076C30A /* QuestionsDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DFEAD1E210DE0310076C30A /* QuestionsDataManager.swift */; };
12+
3DFEAD21210DE0860076C30A /* Question.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DFEAD20210DE0860076C30A /* Question.swift */; };
13+
3DFEAD24210DE1040076C30A /* QuestionsRetrievalOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DFEAD23210DE1040076C30A /* QuestionsRetrievalOperation.swift */; };
14+
3DFEAD26210DE14A0076C30A /* QuestionsURLRequestFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DFEAD25210DE14A0076C30A /* QuestionsURLRequestFactory.swift */; };
15+
3DFEAD28210DE26C0076C30A /* QuestionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DFEAD27210DE26C0076C30A /* QuestionsViewController.swift */; };
16+
3DFEAD2B210DE4B50076C30A /* QuestionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DFEAD2A210DE4B50076C30A /* QuestionTableViewCell.swift */; };
17+
3DFEAD2F210DE5E60076C30A /* NSObject+Name.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DFEAD2E210DE5E60076C30A /* NSObject+Name.swift */; };
18+
3DFEAD31210E159E0076C30A /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DFEAD30210E159E0076C30A /* User.swift */; };
19+
3DFEAD34210E1D060076C30A /* UserDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DFEAD33210E1D060076C30A /* UserDataManager.swift */; };
20+
3DFEAD37210E1DA10076C30A /* AvatarRetrievalOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DFEAD36210E1DA10076C30A /* AvatarRetrievalOperation.swift */; };
21+
C21F1CB020F902E100D4138F /* ConcurrentOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C21F1CA420F902E100D4138F /* ConcurrentOperation.swift */; };
22+
C21F1CB320F902E100D4138F /* URLRequest+HTTPBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = C21F1CAC20F902E100D4138F /* URLRequest+HTTPBody.swift */; };
23+
C21F1CB420F902E100D4138F /* RequestConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = C21F1CAD20F902E100D4138F /* RequestConfig.swift */; };
24+
C21F1CB520F902E100D4138F /* URLRequestFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = C21F1CAE20F902E100D4138F /* URLRequestFactory.swift */; };
1225
C284F0A420F63CBB009AF6E9 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C284F09820F63CBB009AF6E9 /* AppDelegate.swift */; };
1326
C284F0A620F63CBB009AF6E9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C284F09C20F63CBB009AF6E9 /* Assets.xcassets */; };
1427
C284F0A720F63CBB009AF6E9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C284F09E20F63CBB009AF6E9 /* LaunchScreen.storyboard */; };
@@ -27,8 +40,21 @@
2740
/* End PBXContainerItemProxy section */
2841

2942
/* Begin PBXFileReference section */
30-
C284F09520F63CBB009AF6E9 /* DetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = "<group>"; };
31-
C284F09620F63CBB009AF6E9 /* MasterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MasterViewController.swift; sourceTree = "<group>"; };
43+
3DA271F920F7D1E6001642D8 /* QueueManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueueManager.swift; sourceTree = "<group>"; };
44+
3DFEAD1E210DE0310076C30A /* QuestionsDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestionsDataManager.swift; sourceTree = "<group>"; };
45+
3DFEAD20210DE0860076C30A /* Question.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Question.swift; sourceTree = "<group>"; };
46+
3DFEAD23210DE1040076C30A /* QuestionsRetrievalOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestionsRetrievalOperation.swift; sourceTree = "<group>"; };
47+
3DFEAD25210DE14A0076C30A /* QuestionsURLRequestFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestionsURLRequestFactory.swift; sourceTree = "<group>"; };
48+
3DFEAD27210DE26C0076C30A /* QuestionsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestionsViewController.swift; sourceTree = "<group>"; };
49+
3DFEAD2A210DE4B50076C30A /* QuestionTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuestionTableViewCell.swift; sourceTree = "<group>"; };
50+
3DFEAD2E210DE5E60076C30A /* NSObject+Name.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSObject+Name.swift"; sourceTree = "<group>"; };
51+
3DFEAD30210E159E0076C30A /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
52+
3DFEAD33210E1D060076C30A /* UserDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDataManager.swift; sourceTree = "<group>"; };
53+
3DFEAD36210E1DA10076C30A /* AvatarRetrievalOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarRetrievalOperation.swift; sourceTree = "<group>"; };
54+
C21F1CA420F902E100D4138F /* ConcurrentOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConcurrentOperation.swift; sourceTree = "<group>"; };
55+
C21F1CAC20F902E100D4138F /* URLRequest+HTTPBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "URLRequest+HTTPBody.swift"; sourceTree = "<group>"; };
56+
C21F1CAD20F902E100D4138F /* RequestConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestConfig.swift; sourceTree = "<group>"; };
57+
C21F1CAE20F902E100D4138F /* URLRequestFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLRequestFactory.swift; sourceTree = "<group>"; };
3258
C284F09820F63CBB009AF6E9 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
3359
C284F09920F63CBB009AF6E9 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
3460
C284F09C20F63CBB009AF6E9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@@ -58,11 +84,141 @@
5884
/* End PBXFrameworksBuildPhase section */
5985

6086
/* Begin PBXGroup section */
87+
3DA271F720F7D1E6001642D8 /* Managers */ = {
88+
isa = PBXGroup;
89+
children = (
90+
3DA271F820F7D1E6001642D8 /* Queue */,
91+
);
92+
path = Managers;
93+
sourceTree = "<group>";
94+
};
95+
3DA271F820F7D1E6001642D8 /* Queue */ = {
96+
isa = PBXGroup;
97+
children = (
98+
3DA271F920F7D1E6001642D8 /* QueueManager.swift */,
99+
);
100+
path = Queue;
101+
sourceTree = "<group>";
102+
};
103+
3DFEAD1D210DE00A0076C30A /* Questions */ = {
104+
isa = PBXGroup;
105+
children = (
106+
3DFEAD22210DE0F50076C30A /* Operations */,
107+
3DFEAD1E210DE0310076C30A /* QuestionsDataManager.swift */,
108+
);
109+
path = Questions;
110+
sourceTree = "<group>";
111+
};
112+
3DFEAD22210DE0F50076C30A /* Operations */ = {
113+
isa = PBXGroup;
114+
children = (
115+
3DFEAD23210DE1040076C30A /* QuestionsRetrievalOperation.swift */,
116+
);
117+
path = Operations;
118+
sourceTree = "<group>";
119+
};
120+
3DFEAD29210DE4A30076C30A /* Cells */ = {
121+
isa = PBXGroup;
122+
children = (
123+
3DFEAD2A210DE4B50076C30A /* QuestionTableViewCell.swift */,
124+
);
125+
path = Cells;
126+
sourceTree = "<group>";
127+
};
128+
3DFEAD2C210DE5B80076C30A /* Extensions */ = {
129+
isa = PBXGroup;
130+
children = (
131+
3DFEAD2D210DE5B80076C30A /* NSObject */,
132+
);
133+
path = Extensions;
134+
sourceTree = "<group>";
135+
};
136+
3DFEAD2D210DE5B80076C30A /* NSObject */ = {
137+
isa = PBXGroup;
138+
children = (
139+
3DFEAD2E210DE5E60076C30A /* NSObject+Name.swift */,
140+
);
141+
path = NSObject;
142+
sourceTree = "<group>";
143+
};
144+
3DFEAD32210E1CF70076C30A /* User */ = {
145+
isa = PBXGroup;
146+
children = (
147+
3DFEAD35210E1D890076C30A /* Operations */,
148+
3DFEAD33210E1D060076C30A /* UserDataManager.swift */,
149+
);
150+
path = User;
151+
sourceTree = "<group>";
152+
};
153+
3DFEAD35210E1D890076C30A /* Operations */ = {
154+
isa = PBXGroup;
155+
children = (
156+
3DFEAD36210E1DA10076C30A /* AvatarRetrievalOperation.swift */,
157+
);
158+
path = Operations;
159+
sourceTree = "<group>";
160+
};
161+
C21F1CA220F902E100D4138F /* Data */ = {
162+
isa = PBXGroup;
163+
children = (
164+
C21F1CA320F902E100D4138F /* Abstract */,
165+
C21F1CA520F902E100D4138F /* Managers */,
166+
C21F1CB720F9049000D4138F /* Models */,
167+
C21F1CAA20F902E100D4138F /* Requests */,
168+
);
169+
path = Data;
170+
sourceTree = "<group>";
171+
};
172+
C21F1CA320F902E100D4138F /* Abstract */ = {
173+
isa = PBXGroup;
174+
children = (
175+
C21F1CA420F902E100D4138F /* ConcurrentOperation.swift */,
176+
);
177+
path = Abstract;
178+
sourceTree = "<group>";
179+
};
180+
C21F1CA520F902E100D4138F /* Managers */ = {
181+
isa = PBXGroup;
182+
children = (
183+
3DFEAD32210E1CF70076C30A /* User */,
184+
3DFEAD1D210DE00A0076C30A /* Questions */,
185+
);
186+
path = Managers;
187+
sourceTree = "<group>";
188+
};
189+
C21F1CAA20F902E100D4138F /* Requests */ = {
190+
isa = PBXGroup;
191+
children = (
192+
C21F1CAB20F902E100D4138F /* Abstract */,
193+
3DFEAD25210DE14A0076C30A /* QuestionsURLRequestFactory.swift */,
194+
);
195+
path = Requests;
196+
sourceTree = "<group>";
197+
};
198+
C21F1CAB20F902E100D4138F /* Abstract */ = {
199+
isa = PBXGroup;
200+
children = (
201+
C21F1CAC20F902E100D4138F /* URLRequest+HTTPBody.swift */,
202+
C21F1CAD20F902E100D4138F /* RequestConfig.swift */,
203+
C21F1CAE20F902E100D4138F /* URLRequestFactory.swift */,
204+
);
205+
path = Abstract;
206+
sourceTree = "<group>";
207+
};
208+
C21F1CB720F9049000D4138F /* Models */ = {
209+
isa = PBXGroup;
210+
children = (
211+
3DFEAD20210DE0860076C30A /* Question.swift */,
212+
3DFEAD30210E159E0076C30A /* User.swift */,
213+
);
214+
path = Models;
215+
sourceTree = "<group>";
216+
};
61217
C284F09420F63CBB009AF6E9 /* ViewControllers */ = {
62218
isa = PBXGroup;
63219
children = (
64-
C284F09520F63CBB009AF6E9 /* DetailViewController.swift */,
65-
C284F09620F63CBB009AF6E9 /* MasterViewController.swift */,
220+
3DFEAD29210DE4A30076C30A /* Cells */,
221+
3DFEAD27210DE26C0076C30A /* QuestionsViewController.swift */,
66222
);
67223
path = ViewControllers;
68224
sourceTree = "<group>";
@@ -123,6 +279,9 @@
123279
isa = PBXGroup;
124280
children = (
125281
C284F09720F63CBB009AF6E9 /* Application */,
282+
C21F1CA220F902E100D4138F /* Data */,
283+
3DFEAD2C210DE5B80076C30A /* Extensions */,
284+
3DA271F720F7D1E6001642D8 /* Managers */,
126285
C284F09A20F63CBB009AF6E9 /* Resources */,
127286
C284F09D20F63CBB009AF6E9 /* Storyboards */,
128287
C284F09420F63CBB009AF6E9 /* ViewControllers */,
@@ -243,8 +402,21 @@
243402
buildActionMask = 2147483647;
244403
files = (
245404
C284F0A420F63CBB009AF6E9 /* AppDelegate.swift in Sources */,
246-
C284F0A320F63CBB009AF6E9 /* MasterViewController.swift in Sources */,
247-
C284F0A220F63CBB009AF6E9 /* DetailViewController.swift in Sources */,
405+
3DFEAD2B210DE4B50076C30A /* QuestionTableViewCell.swift in Sources */,
406+
3DFEAD37210E1DA10076C30A /* AvatarRetrievalOperation.swift in Sources */,
407+
C21F1CB320F902E100D4138F /* URLRequest+HTTPBody.swift in Sources */,
408+
3DFEAD1F210DE0310076C30A /* QuestionsDataManager.swift in Sources */,
409+
3DFEAD26210DE14A0076C30A /* QuestionsURLRequestFactory.swift in Sources */,
410+
3DFEAD21210DE0860076C30A /* Question.swift in Sources */,
411+
C21F1CB520F902E100D4138F /* URLRequestFactory.swift in Sources */,
412+
3DFEAD2F210DE5E60076C30A /* NSObject+Name.swift in Sources */,
413+
3DFEAD24210DE1040076C30A /* QuestionsRetrievalOperation.swift in Sources */,
414+
C21F1CB020F902E100D4138F /* ConcurrentOperation.swift in Sources */,
415+
3DFEAD34210E1D060076C30A /* UserDataManager.swift in Sources */,
416+
3DFEAD28210DE26C0076C30A /* QuestionsViewController.swift in Sources */,
417+
3DFEAD31210E159E0076C30A /* User.swift in Sources */,
418+
3DA271FC20F7D1E6001642D8 /* QueueManager.swift in Sources */,
419+
C21F1CB420F902E100D4138F /* RequestConfig.swift in Sources */,
248420
);
249421
runOnlyForDeploymentPostprocessing = 0;
250422
};
@@ -337,7 +509,7 @@
337509
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
338510
GCC_WARN_UNUSED_FUNCTION = YES;
339511
GCC_WARN_UNUSED_VARIABLE = YES;
340-
IPHONEOS_DEPLOYMENT_TARGET = 11.4;
512+
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
341513
MTL_ENABLE_DEBUG_INFO = YES;
342514
ONLY_ACTIVE_ARCH = YES;
343515
SDKROOT = iphoneos;
@@ -391,7 +563,7 @@
391563
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
392564
GCC_WARN_UNUSED_FUNCTION = YES;
393565
GCC_WARN_UNUSED_VARIABLE = YES;
394-
IPHONEOS_DEPLOYMENT_TARGET = 11.4;
566+
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
395567
MTL_ENABLE_DEBUG_INFO = NO;
396568
SDKROOT = iphoneos;
397569
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
@@ -405,7 +577,6 @@
405577
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
406578
CODE_SIGN_STYLE = Automatic;
407579
INFOPLIST_FILE = "NetworkingInOperations-Example/Application/Info.plist";
408-
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
409580
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
410581
PRODUCT_BUNDLE_IDENTIFIER = "com.boles.NetworkingInOperations-Example";
411582
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -420,7 +591,6 @@
420591
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
421592
CODE_SIGN_STYLE = Automatic;
422593
INFOPLIST_FILE = "NetworkingInOperations-Example/Application/Info.plist";
423-
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
424594
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
425595
PRODUCT_BUNDLE_IDENTIFIER = "com.boles.NetworkingInOperations-Example";
426596
PRODUCT_NAME = "$(TARGET_NAME)";

NetworkingInOperations-Example/Application/AppDelegate.swift

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele
1313

1414
var window: UIWindow?
1515

16-
1716
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18-
// Override point for customization after application launch.
19-
let splitViewController = window!.rootViewController as! UISplitViewController
20-
let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController
21-
navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
22-
splitViewController.delegate = self
2317
return true
2418
}
2519

@@ -44,18 +38,5 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UISplitViewControllerDele
4438
func applicationWillTerminate(_ application: UIApplication) {
4539
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
4640
}
47-
48-
// MARK: - Split view
49-
50-
func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController:UIViewController, onto primaryViewController:UIViewController) -> Bool {
51-
guard let secondaryAsNavController = secondaryViewController as? UINavigationController else { return false }
52-
guard let topAsDetailController = secondaryAsNavController.topViewController as? DetailViewController else { return false }
53-
if topAsDetailController.detailItem == nil {
54-
// Return true to indicate that we have handled the collapse by doing nothing; the secondary controller will be discarded.
55-
return true
56-
}
57-
return false
58-
}
59-
6041
}
6142

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
//
2+
// ConcurrentOperation.swift
3+
// NetworkingInOperations-Example
4+
//
5+
// Created by William Boles on 11/07/2018.
6+
// Copyright © 2018 Boles. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import UIKit
11+
12+
enum DataRequestResult<T> {
13+
case success(T)
14+
case failure(Error)
15+
}
16+
17+
class ConcurrentOperation<T>: Operation {
18+
19+
typealias OperationCompletionHandler = (_ result: DataRequestResult<T>) -> Void
20+
21+
var completionHandler: (OperationCompletionHandler)?
22+
23+
// MARK: - Types
24+
25+
enum State: String {
26+
case ready = "isReady",
27+
executing = "isExecuting",
28+
finished = "isFinished"
29+
}
30+
31+
// MARK: - Properties
32+
33+
var state = State.ready {
34+
willSet {
35+
willChangeValue(forKey: newValue.rawValue)
36+
willChangeValue(forKey: state.rawValue)
37+
}
38+
didSet {
39+
didChangeValue(forKey: oldValue.rawValue)
40+
didChangeValue(forKey: state.rawValue)
41+
}
42+
}
43+
44+
// MARK: - Operation
45+
46+
override var isReady: Bool {
47+
return super.isReady && state == .ready
48+
}
49+
50+
override var isExecuting: Bool {
51+
return state == .executing
52+
}
53+
54+
override var isFinished: Bool {
55+
return state == .finished
56+
}
57+
58+
override var isAsynchronous: Bool {
59+
return true
60+
}
61+
62+
// MARK: - Control
63+
64+
override func start() {
65+
super.start()
66+
67+
if !isExecuting {
68+
state = .executing
69+
}
70+
}
71+
72+
func finish() {
73+
if isExecuting {
74+
state = .finished
75+
}
76+
}
77+
78+
func complete(result: DataRequestResult<T>) {
79+
finish()
80+
81+
completionHandler?(result)
82+
}
83+
84+
override func cancel() {
85+
super.cancel()
86+
87+
finish()
88+
}
89+
}

0 commit comments

Comments
 (0)