Skip to content

Commit 49030f3

Browse files
committed
Merge branch 'develop'
2 parents 6b13c61 + 7ba3784 commit 49030f3

27 files changed

+645
-134
lines changed

AutocompleteClient.xcodeproj/project.pbxproj

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,11 @@
141141
F6D2E9C420DBDDBB007F8761 /* Data+ToJSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6D2E9C320DBDDBB007F8761 /* Data+ToJSON.swift */; };
142142
F6D2E9CC20E21022007F8761 /* CIOTrackSearchResultsLoadedData.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6D2E9CB20E21022007F8761 /* CIOTrackSearchResultsLoadedData.swift */; };
143143
F6DF7B9420849E8D00A7CDAD /* CIOTrackSearchResultClickData.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6DF7B9320849E8D00A7CDAD /* CIOTrackSearchResultClickData.swift */; };
144+
F6EC29AB2175161300DCFA07 /* ClosureSessionManagerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6EC29AA2175161300DCFA07 /* ClosureSessionManagerDelegate.swift */; };
145+
F6EC29AD2175EF1700DCFA07 /* Session.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6EC29AC2175EF1700DCFA07 /* Session.swift */; };
146+
F6EC29AF2176014C00DCFA07 /* SessionLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6EC29AE2176014C00DCFA07 /* SessionLoader.swift */; };
147+
F6EC29B2217601D700DCFA07 /* CIOSessionLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6EC29B1217601D700DCFA07 /* CIOSessionLoader.swift */; };
148+
F6EC29B421762BD700DCFA07 /* NoSessionLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6EC29B321762BD700DCFA07 /* NoSessionLoader.swift */; };
144149
/* End PBXBuildFile section */
145150

146151
/* Begin PBXContainerItemProxy section */
@@ -328,6 +333,11 @@
328333
F6D2E9C320DBDDBB007F8761 /* Data+ToJSON.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+ToJSON.swift"; sourceTree = "<group>"; };
329334
F6D2E9CB20E21022007F8761 /* CIOTrackSearchResultsLoadedData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIOTrackSearchResultsLoadedData.swift; sourceTree = "<group>"; };
330335
F6DF7B9320849E8D00A7CDAD /* CIOTrackSearchResultClickData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIOTrackSearchResultClickData.swift; sourceTree = "<group>"; };
336+
F6EC29AA2175161300DCFA07 /* ClosureSessionManagerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClosureSessionManagerDelegate.swift; sourceTree = "<group>"; };
337+
F6EC29AC2175EF1700DCFA07 /* Session.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Session.swift; sourceTree = "<group>"; };
338+
F6EC29AE2176014C00DCFA07 /* SessionLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionLoader.swift; sourceTree = "<group>"; };
339+
F6EC29B1217601D700DCFA07 /* CIOSessionLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CIOSessionLoader.swift; sourceTree = "<group>"; };
340+
F6EC29B321762BD700DCFA07 /* NoSessionLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoSessionLoader.swift; sourceTree = "<group>"; };
331341
/* End PBXFileReference section */
332342

333343
/* Begin PBXFrameworksBuildPhase section */
@@ -396,18 +406,16 @@
396406
088F7D25210FA43C005B9FB4 /* CurrentTimeDateProvider.swift */,
397407
088F7D24210FA43C005B9FB4 /* DateProvider.swift */,
398408
);
399-
name = Date;
400-
path = "/Users/rubikzube/Github/constructor.io/constructorio-client-swift/AutocompleteClient/FW/Logic/Session/Date";
401-
sourceTree = "<absolute>";
409+
path = Date;
410+
sourceTree = "<group>";
402411
};
403412
08CCD3ED216675C700C3F234 /* ABTesting */ = {
404413
isa = PBXGroup;
405414
children = (
406415
08CCD3EE216675DD00C3F234 /* CIOABTestCell.swift */,
407416
);
408-
name = ABTesting;
409-
path = "/Users/rubikzube/Github/constructor.io/constructorio-client-swift/AutocompleteClient/FW/Logic/ABTesting";
410-
sourceTree = "<absolute>";
417+
path = ABTesting;
418+
sourceTree = "<group>";
411419
};
412420
08F771702162C277005FDF06 /* FW */ = {
413421
isa = PBXGroup;
@@ -617,10 +625,12 @@
617625
F62510C62052CC5E0040E3DF /* Session */ = {
618626
isa = PBXGroup;
619627
children = (
628+
F6EC29B0217601C400DCFA07 /* Persistence */,
620629
088F7D23210FA429005B9FB4 /* Date */,
621630
088F7D1B210FA3B4005B9FB4 /* CIOSessionManagerDelegate.swift */,
622631
F62510C72052CC6B0040E3DF /* CIOSessionManager.swift */,
623632
F62510C92052CF240040E3DF /* SessionManager.swift */,
633+
F6EC29AC2175EF1700DCFA07 /* Session.swift */,
624634
);
625635
path = Session;
626636
sourceTree = "<group>";
@@ -630,6 +640,8 @@
630640
children = (
631641
F62510D020568F250040E3DF /* SessionManagerTests.swift */,
632642
F62510D2205690670040E3DF /* ClosureDateProvider.swift */,
643+
F6EC29AA2175161300DCFA07 /* ClosureSessionManagerDelegate.swift */,
644+
F6EC29B321762BD700DCFA07 /* NoSessionLoader.swift */,
633645
);
634646
path = Session;
635647
sourceTree = "<group>";
@@ -1160,6 +1172,15 @@
11601172
path = JSON;
11611173
sourceTree = "<group>";
11621174
};
1175+
F6EC29B0217601C400DCFA07 /* Persistence */ = {
1176+
isa = PBXGroup;
1177+
children = (
1178+
F6EC29AE2176014C00DCFA07 /* SessionLoader.swift */,
1179+
F6EC29B1217601D700DCFA07 /* CIOSessionLoader.swift */,
1180+
);
1181+
path = Persistence;
1182+
sourceTree = "<group>";
1183+
};
11631184
/* End PBXGroup section */
11641185

11651186
/* Begin PBXHeadersBuildPhase section */
@@ -1233,9 +1254,9 @@
12331254
isa = PBXNativeTarget;
12341255
buildConfigurationList = F688A4531F56B4B600F169C1 /* Build configuration list for PBXNativeTarget "AutocompleteClient" */;
12351256
buildPhases = (
1257+
F688A43C1F56B4B600F169C1 /* Headers */,
12361258
F688A43A1F56B4B600F169C1 /* Sources */,
12371259
F688A43B1F56B4B600F169C1 /* Frameworks */,
1238-
F688A43C1F56B4B600F169C1 /* Headers */,
12391260
F688A43D1F56B4B600F169C1 /* Resources */,
12401261
);
12411262
buildRules = (
@@ -1453,6 +1474,7 @@
14531474
isa = PBXSourcesBuildPhase;
14541475
buildActionMask = 2147483647;
14551476
files = (
1477+
F6EC29AD2175EF1700DCFA07 /* Session.swift in Sources */,
14561478
F672F6BA20ABE9EC00EA1525 /* CIOTrackConversionData.swift in Sources */,
14571479
F1B17CB21F58E5830015FF62 /* AutocompleteResult.swift in Sources */,
14581480
F65015481F586A42008E50C0 /* UIView+FadeInOut.swift in Sources */,
@@ -1475,6 +1497,7 @@
14751497
F650154E1F58724B008E50C0 /* UIColor+RGB.swift in Sources */,
14761498
F60BEA1A1F571956008F0053 /* CIOAutocompleteDelegate.swift in Sources */,
14771499
F61A6B091F698877007826CA /* CIOGroup.swift in Sources */,
1500+
F6EC29B2217601D700DCFA07 /* CIOSessionLoader.swift in Sources */,
14781501
F6B220EB209C68F8003A5D48 /* CustomSearchBar.swift in Sources */,
14791502
F1F68DDA1F58B6A300B42602 /* CIOAutocompleteResponseParser.swift in Sources */,
14801503
F6852559213D604900A27FAA /* AutocompleteResultCount.swift in Sources */,
@@ -1498,6 +1521,7 @@
14981521
F63808FB1F5D49AF00C3B322 /* TaskResponse.swift in Sources */,
14991522
F685255B21413D4D00A27FAA /* CIORequestData.swift in Sources */,
15001523
F1F68DE31F58B8BB00B42602 /* CIOError.swift in Sources */,
1524+
F6EC29AF2176014C00DCFA07 /* SessionLoader.swift in Sources */,
15011525
088F7D1E210FA3C6005B9FB4 /* CIOTrackInputFocusData.swift in Sources */,
15021526
F62510C82052CC6B0040E3DF /* CIOSessionManager.swift in Sources */,
15031527
F68A73131F56E5FB00FA4D1B /* String+Trim.swift in Sources */,
@@ -1541,6 +1565,7 @@
15411565
F64E94E6212D87E200E50EDE /* CIOBuilder.swift in Sources */,
15421566
F62510D120568F250040E3DF /* SessionManagerTests.swift in Sources */,
15431567
0879E93F215F290D00018BBA /* TrackAutocompleteSelectRequestBuilderTests.swift in Sources */,
1568+
F6EC29AB2175161300DCFA07 /* ClosureSessionManagerDelegate.swift in Sources */,
15441569
F63808FF1F5D6C1000C3B322 /* ConstructorIOTests.swift in Sources */,
15451570
0874A32E216BCE2700812CDC /* ConstructorIOABTestCellTests.swift in Sources */,
15461571
F64F46B71F59767D0094C697 /* AutocompleteViewModelTests.swift in Sources */,
@@ -1550,6 +1575,7 @@
15501575
F60FE90A1F5C5B9D0037A0AB /* AutocompleteQueryRequestBuilderTests.swift in Sources */,
15511576
F64F46A61F595B980094C697 /* ResponseParserTests.swift in Sources */,
15521577
F64E94DD212D7EC300E50EDE /* ConstructorIOTrackingTests.swift in Sources */,
1578+
F6EC29B421762BD700DCFA07 /* NoSessionLoader.swift in Sources */,
15531579
089399DF2161B92600BFE3D9 /* TrackInputFocusRequestBuilderTests.swift in Sources */,
15541580
089399E32161C67D00BFE3D9 /* TrackSearchResultsLoadedRequestBuilder.swift in Sources */,
15551581
F64F46AD1F5963AF0094C697 /* Bundle+Test.swift in Sources */,

AutocompleteClient/Constants/Constants.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,4 +150,10 @@ struct Constants {
150150

151151
static let performURLRequest: (_ request: URLRequest) -> String = { request in return Logging.format("Performing URL Request \(request)") }
152152
}
153+
154+
struct Session{
155+
static let key = "constructor.io/session"
156+
static let id = "constructor.io/session/id"
157+
static let createdAt = "constructor.io/session/createdAt"
158+
}
153159
}

AutocompleteClient/FW/API/Network/Client/URLSessionNetworkClient.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ class URLSessionNetworkClient: NetworkClient {
1313
func execute(_ request: URLRequest, completionHandler: @escaping (_ response: NetworkResponse) -> Void) {
1414
let task = URLSession.shared.dataTask(with: request) { data, response, error in
1515
// Check for errors
16-
if let err = error {
16+
if let error = error {
17+
let err: Error = CIOError(rawValue: (error as NSError).code) ?? error
1718
completionHandler(NetworkResponse(error: err))
1819
return
1920
}
@@ -27,6 +28,7 @@ class URLSessionNetworkClient: NetworkClient {
2728
// Check if response code corresponds to a ConstructorIOError
2829
if let constructorError = CIOError(rawValue: httpResponse.statusCode) {
2930
completionHandler(NetworkResponse(error: constructorError))
31+
return
3032
}
3133

3234
// No errors

AutocompleteClient/FW/Logic/Error/CIOError.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import Foundation
1212
Represents any error that may occur in using ConstructorIO services.
1313
*/
1414
public enum CIOError: Int, Error {
15+
case noConnection = -1009
1516
case badRequest = 400
1617
case unauthorized = 401
1718
case forbidden = 403
@@ -30,6 +31,7 @@ extension CIOError: CustomStringConvertible {
3031
/// The string representation of this CIOError.
3132
public var string: String {
3233
switch self {
34+
case .noConnection: return "No Connection"
3335
case .badRequest: return "Bad Request"
3436
case .unauthorized: return "Unauthorized"
3537
case .forbidden: return "Forbidden"
@@ -48,6 +50,7 @@ extension CIOError: CustomStringConvertible {
4850
public var description: String {
4951
let errorMessage: String
5052
switch self {
53+
case .noConnection: errorMessage = "The Internet connection appears to be offline."
5154
case .badRequest: errorMessage = "Your request is invalid."
5255
case .unauthorized: errorMessage = "Your api key is wrong."
5356
case .forbidden: errorMessage = "You are not authorized to access the requested resource."

AutocompleteClient/FW/Logic/Session/CIOSessionManager.swift

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,48 +7,66 @@
77
//
88

99
import Foundation
10-
10+
1111
public class CIOSessionManager: SessionManager {
1212

1313
public weak var delegate: CIOSessionManagerDelegate?
1414

15-
public var sessionID: Int{
15+
private(set) public var session: Session{
1616
didSet{
17-
self.delegate?.sessionDidChange(from: oldValue, to: self.sessionID)
17+
self.sessionLoader.saveSession(self.session)
18+
self.delegate?.sessionDidChange(from: oldValue.id, to: self.session.id)
1819
}
1920
}
20-
var lastSessionRequest: TimeInterval
2121
let timeout: TimeInterval
2222
let dateProvider: DateProvider
23+
let sessionLoader: SessionLoader
2324

24-
init(dateProvider: DateProvider, timeout: TimeInterval){
25-
self.sessionID = 1
25+
init(dateProvider: DateProvider, timeout: TimeInterval, sessionLoader: SessionLoader = CIOSessionLoader()){
2626
self.dateProvider = dateProvider
2727
self.timeout = timeout
28-
self.lastSessionRequest = self.dateProvider.provideDate().timeIntervalSince1970
28+
29+
self.sessionLoader = sessionLoader
30+
self.session = self.sessionLoader.loadSession() ?? Session(id: 1, createdAt: dateProvider.provideDate().timeIntervalSince1970)
31+
32+
NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterForeground(_:)), name: Notification.Name.UIApplicationWillEnterForeground, object: nil)
33+
}
34+
35+
public func setup(){
36+
self.reloadSession()
37+
self.sessionLoader.saveSession(self.session)
2938
}
3039

31-
public func getSession() -> Int{
40+
@objc
41+
public func applicationDidEnterForeground(_ notification: Notification){
42+
self.reloadSession()
43+
}
44+
45+
public func getSessionWithIncrement() -> Int{
46+
self.reloadSession()
47+
return self.session.id
48+
}
49+
50+
public func getSessionWithoutIncrement() -> Int{
51+
return self.session.id
52+
}
53+
54+
func reloadSession(){
3255
if self.shouldIncrementSession(){
33-
self.setSessionHasBeenRequested()
3456
self.incrementSession()
35-
}else{
36-
self.setSessionHasBeenRequested()
3757
}
38-
39-
return self.sessionID
40-
}
41-
42-
private func setSessionHasBeenRequested(){
43-
self.lastSessionRequest = self.dateProvider.provideDate().timeIntervalSince1970
4458
}
4559

4660
func shouldIncrementSession() -> Bool{
47-
let diff = (self.dateProvider.provideDate().timeIntervalSince1970 - self.lastSessionRequest)
61+
let diff = (self.dateProvider.provideDate().timeIntervalSince1970 - self.session.createdAt)
4862
return diff >= self.timeout
4963
}
5064

5165
func incrementSession(){
52-
self.sessionID += 1
66+
self.session = Session(id: self.session.id + 1, createdAt: self.dateProvider.provideDate().timeIntervalSince1970)
67+
}
68+
69+
deinit {
70+
NotificationCenter.default.removeObserver(self)
5371
}
5472
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//
2+
// CIOSessionLoader.swift
3+
// AutocompleteClient
4+
//
5+
// Copyright © Constructor.io. All rights reserved.
6+
// http://constructor.io/
7+
//
8+
9+
import Foundation
10+
11+
public struct CIOSessionLoader: SessionLoader{
12+
13+
public func loadSession() -> Session?{
14+
if let data = UserDefaults.standard.object(forKey: Constants.Session.key) as? Data{
15+
return NSKeyedUnarchiver.unarchiveObject(with: data) as? Session
16+
}else{
17+
return nil
18+
}
19+
}
20+
21+
public func saveSession(_ session: Session){
22+
let data = NSKeyedArchiver.archivedData(withRootObject: session)
23+
UserDefaults.standard.set(data, forKey: Constants.Session.key)
24+
}
25+
26+
public func clearSession() {
27+
UserDefaults.standard.removeObject(forKey: Constants.Session.key)
28+
}
29+
30+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// SessionLoader.swift
3+
// Constructor.io
4+
//
5+
// Copyright © Constructor.io. All rights reserved.
6+
// http://constructor.io/
7+
//
8+
9+
import Foundation
10+
11+
public protocol SessionLoader{
12+
13+
func loadSession() -> Session?
14+
func saveSession(_ session: Session)
15+
16+
func clearSession()
17+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//
2+
// Session.swift
3+
// Constructor.io
4+
//
5+
// Copyright © Constructor.io. All rights reserved.
6+
// http://constructor.io/
7+
//
8+
9+
import Foundation
10+
11+
public class Session: NSObject, NSCoding{
12+
let id: Int
13+
let createdAt: TimeInterval
14+
15+
public init(id: Int, createdAt: TimeInterval){
16+
self.id = id
17+
self.createdAt = createdAt
18+
}
19+
20+
public required init?(coder aDecoder: NSCoder) {
21+
self.id = aDecoder.decodeInteger(forKey: Constants.Session.id)
22+
self.createdAt = aDecoder.decodeDouble(forKey: Constants.Session.createdAt)
23+
}
24+
25+
public func encode(with aCoder: NSCoder) {
26+
aCoder.encode(self.id, forKey: Constants.Session.id)
27+
aCoder.encode(self.createdAt, forKey: Constants.Session.createdAt)
28+
}
29+
}

AutocompleteClient/FW/Logic/Session/SessionManager.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,8 @@ import Foundation
1111
public protocol SessionManager: class{
1212
var delegate: CIOSessionManagerDelegate? { get set }
1313

14-
func getSession() -> Int
14+
func getSessionWithIncrement() -> Int
15+
func getSessionWithoutIncrement() -> Int
16+
17+
func setup()
1518
}

0 commit comments

Comments
 (0)