Skip to content

Commit b232415

Browse files
Merge pull request #390 from Iterable/feature/mob-2088-dependency
[MOB-2088] - Use dependency container to create request processor
2 parents 9820ffb + deadd05 commit b232415

12 files changed

+165
-87
lines changed

swift-sdk/Internal/DependencyContainer.swift

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ protocol DependencyContainerProtocol {
2020
var apnsTypeChecker: APNSTypeCheckerProtocol { get }
2121

2222
func createInAppFetcher(apiClient: ApiClientProtocol) -> InAppFetcherProtocol
23+
func createPersistenceContextProvider() -> IterablePersistenceContextProvider?
2324
}
2425

2526
extension DependencyContainerProtocol {
@@ -47,6 +48,66 @@ extension DependencyContainerProtocol {
4748
localStorage: localStorage,
4849
dateProvider: dateProvider)
4950
}
51+
52+
func createRequestProcessor(apiKey: String,
53+
config: IterableConfig,
54+
authProvider: AuthProvider,
55+
authManager: IterableInternalAuthManagerProtocol,
56+
deviceMetadata: DeviceMetadata) -> RequestProcessorProtocol {
57+
if #available(iOS 10.0, *) {
58+
return RequestProcessor(onlineCreator: {
59+
OnlineRequestProcessor(apiKey: apiKey,
60+
authProvider: authProvider,
61+
authManager: authManager,
62+
endPoint: config.apiEndpoint,
63+
networkSession: networkSession,
64+
deviceMetadata: deviceMetadata) },
65+
offlineCreator: {
66+
guard let persistenceContextProvider = createPersistenceContextProvider() else {
67+
return nil
68+
}
69+
70+
return OfflineRequestProcessor(apiKey: apiKey,
71+
authProvider: authProvider,
72+
authManager: authManager,
73+
endPoint: config.apiEndpoint,
74+
deviceMetadata: deviceMetadata,
75+
taskScheduler: createTaskScheduler(persistenceContextProvider: persistenceContextProvider),
76+
taskRunner: createTaskRunner(persistenceContextProvider: persistenceContextProvider),
77+
notificationCenter: notificationCenter) },
78+
strategy: DefaultRequestProcessorStrategy(selectOffline: config.enableOfflineMode))
79+
} else {
80+
return OnlineRequestProcessor(apiKey: apiKey,
81+
authProvider: authProvider,
82+
authManager: authManager,
83+
endPoint: config.apiEndpoint,
84+
networkSession: networkSession,
85+
deviceMetadata: deviceMetadata)
86+
}
87+
}
88+
89+
func createPersistenceContextProvider() -> IterablePersistenceContextProvider? {
90+
if #available(iOS 10.0, *) {
91+
return CoreDataPersistenceContextProvider(dateProvider: dateProvider)
92+
} else {
93+
fatalError("Unable to create persistence container for iOS < 10")
94+
}
95+
}
96+
97+
@available(iOS 10.0, *)
98+
private func createTaskScheduler(persistenceContextProvider: IterablePersistenceContextProvider) -> IterableTaskScheduler {
99+
IterableTaskScheduler(persistenceContextProvider: persistenceContextProvider,
100+
notificationCenter: notificationCenter,
101+
dateProvider: dateProvider)
102+
}
103+
104+
@available(iOS 10.0, *)
105+
private func createTaskRunner(persistenceContextProvider: IterablePersistenceContextProvider) -> IterableTaskRunner {
106+
IterableTaskRunner(networkSession: networkSession,
107+
persistenceContextProvider: persistenceContextProvider,
108+
notificationCenter: notificationCenter,
109+
connectivityManager: NetworkConnectivityManager())
110+
}
50111
}
51112

52113
struct DependencyContainer: DependencyContainerProtocol {

swift-sdk/Internal/IterableAPIInternal.swift

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -387,24 +387,12 @@ final class IterableAPIInternal: NSObject, PushTrackerProtocol, AuthProvider {
387387
deviceMetadata: deviceMetadata)
388388
}()
389389

390-
lazy var requestProcessor: RequestProcessorProtocol = {
391-
if #available(iOS 10.0, *) {
392-
return RequestProcessor(apiKey: apiKey,
393-
authProvider: self,
394-
authManager: authManager,
395-
endPoint: config.apiEndpoint,
396-
deviceMetadata: deviceMetadata,
397-
networkSession: networkSession,
398-
notificationCenter: dependencyContainer.notificationCenter,
399-
strategy: DefaultRequestProcessorStrategy(selectOffline: config.enableOfflineMode))
400-
} else {
401-
return OnlineRequestProcessor(apiKey: apiKey,
402-
authProvider: self,
403-
authManager: authManager,
404-
endPoint: config.apiEndpoint,
405-
networkSession: networkSession,
406-
deviceMetadata: deviceMetadata)
407-
}
390+
private lazy var requestProcessor: RequestProcessorProtocol = {
391+
dependencyContainer.createRequestProcessor(apiKey: apiKey,
392+
config: config,
393+
authProvider: self,
394+
authManager: authManager,
395+
deviceMetadata: deviceMetadata)
408396
}()
409397

410398
private var deviceAttributes = [String: String]()

swift-sdk/Internal/IterableCoreDataPersistence.swift

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,15 @@ extension Foundation.Bundle {
5252

5353
@available(iOS 10.0, *)
5454
class PersistentContainer: NSPersistentContainer {
55-
static let shared: PersistentContainer = {
56-
// TODO: @tqm remove force unwrapping
57-
let url = Bundle.current.url(forResource: PersistenceConst.dataModelFileName, withExtension: PersistenceConst.dataModelExtension)!
58-
let managedObjectModel = NSManagedObjectModel(contentsOf: url)!
55+
static let shared: PersistentContainer? = {
56+
guard let url = Bundle.current.url(forResource: PersistenceConst.dataModelFileName, withExtension: PersistenceConst.dataModelExtension) else {
57+
ITBError("Could not find \(PersistenceConst.dataModelFileName) in bundle")
58+
return nil
59+
}
60+
guard let managedObjectModel = NSManagedObjectModel(contentsOf: url) else {
61+
ITBError("Could not initialize managed object model")
62+
return nil
63+
}
5964

6065
let container = PersistentContainer(name: PersistenceConst.dataModelFileName, managedObjectModel: managedObjectModel)
6166
container.loadPersistentStores { desc, error in
@@ -82,18 +87,23 @@ class PersistentContainer: NSPersistentContainer {
8287

8388
@available(iOS 10.0, *)
8489
struct CoreDataPersistenceContextProvider: IterablePersistenceContextProvider {
85-
init(dateProvider: DateProviderProtocol = SystemDateProvider()) {
90+
init?(dateProvider: DateProviderProtocol = SystemDateProvider()) {
91+
guard let persistentContainer = PersistentContainer.shared else {
92+
return nil
93+
}
94+
self.persistentContainer = persistentContainer
8695
self.dateProvider = dateProvider
8796
}
8897

8998
func newBackgroundContext() -> IterablePersistenceContext {
90-
CoreDataPersistenceContext(managedObjectContext: PersistentContainer.shared.newBackgroundContext(), dateProvider: dateProvider)
99+
return CoreDataPersistenceContext(managedObjectContext: persistentContainer.newBackgroundContext(), dateProvider: dateProvider)
91100
}
92101

93102
func mainQueueContext() -> IterablePersistenceContext {
94-
CoreDataPersistenceContext(managedObjectContext: PersistentContainer.shared.viewContext, dateProvider: dateProvider)
103+
return CoreDataPersistenceContext(managedObjectContext: persistentContainer.viewContext, dateProvider: dateProvider)
95104
}
96105

106+
private let persistentContainer: PersistentContainer
97107
private let dateProvider: DateProviderProtocol
98108
}
99109

swift-sdk/Internal/IterableTaskRunner.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,8 @@ import UIKit
99

1010
@available(iOS 10.0, *)
1111
class IterableTaskRunner: NSObject {
12-
// TODO: @tqm Move to `DependencyContainer` after we remove iOS 9 support
1312
init(networkSession: NetworkSessionProtocol = URLSession(configuration: .default),
14-
persistenceContextProvider: IterablePersistenceContextProvider = CoreDataPersistenceContextProvider(),
13+
persistenceContextProvider: IterablePersistenceContextProvider,
1514
notificationCenter: NotificationCenterProtocol = NotificationCenter.default,
1615
timeInterval: TimeInterval = 1.0 * 60,
1716
connectivityManager: NetworkConnectivityManager = NetworkConnectivityManager()) {

swift-sdk/Internal/IterableTaskScheduler.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ import Foundation
77

88
@available(iOS 10.0, *)
99
class IterableTaskScheduler {
10-
// TODO: @tqm Move to `DependencyContainer` after we remove iOS 9 support
11-
init(persistenceContextProvider: IterablePersistenceContextProvider = CoreDataPersistenceContextProvider(),
10+
init(persistenceContextProvider: IterablePersistenceContextProvider,
1211
notificationCenter: NotificationCenterProtocol = NotificationCenter.default,
1312
dateProvider: DateProviderProtocol = SystemDateProvider()) {
1413
self.persistenceContextProvider = persistenceContextProvider

swift-sdk/Internal/OfflineRequestProcessor.swift

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,16 @@ struct OfflineRequestProcessor: RequestProcessorProtocol {
1212
authManager: IterableInternalAuthManagerProtocol?,
1313
endPoint: String,
1414
deviceMetadata: DeviceMetadata,
15-
taskRunner: IterableTaskRunner = IterableTaskRunner(),
15+
taskScheduler: IterableTaskScheduler,
16+
taskRunner: IterableTaskRunner,
1617
notificationCenter: NotificationCenterProtocol
1718
) {
1819
self.apiKey = apiKey
1920
self.authProvider = authProvider
2021
self.authManager = authManager
2122
self.endPoint = endPoint
2223
self.deviceMetadata = deviceMetadata
24+
self.taskScheduler = taskScheduler
2325
self.taskRunner = taskRunner
2426
notificationListener = NotificationListener(notificationCenter: notificationCenter)
2527
}
@@ -340,6 +342,7 @@ struct OfflineRequestProcessor: RequestProcessorProtocol {
340342
private let endPoint: String
341343
private let deviceMetadata: DeviceMetadata
342344
private let notificationListener: NotificationListener
345+
private let taskScheduler: IterableTaskScheduler
343346
private let taskRunner: IterableTaskRunner
344347

345348
private func createRequestCreator(authProvider: AuthProvider) -> RequestCreator {
@@ -366,14 +369,14 @@ struct OfflineRequestProcessor: RequestProcessorProtocol {
366369
iterableRequest: iterableRequest)
367370

368371
do {
369-
let taskId = try IterableTaskScheduler().schedule(apiCallRequest: apiCallRequest,
370-
context: IterableTaskContext(blocking: true))
372+
let taskId = try taskScheduler.schedule(apiCallRequest: apiCallRequest,
373+
context: IterableTaskContext(blocking: true))
371374
let result = notificationListener.futureFromTask(withTaskId: taskId)
372375
return RequestProcessorUtil.apply(successHandler: onSuccess,
373-
andFailureHandler: onFailure,
374-
andAuthManager: authManager,
375-
toResult: result,
376-
withIdentifier: identifier)
376+
andFailureHandler: onFailure,
377+
andAuthManager: authManager,
378+
toResult: result,
379+
withIdentifier: identifier)
377380
} catch let error {
378381
ITBError(error.localizedDescription)
379382
return SendRequestError.createErroredFuture(reason: error.localizedDescription)

swift-sdk/Internal/RequestProcessor.swift

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,29 +18,12 @@ struct DefaultRequestProcessorStrategy: RequestProcessorStrategy {
1818
}
1919

2020
@available(iOS 10.0, *)
21-
struct RequestProcessor: RequestProcessorProtocol {
22-
init(apiKey: String,
23-
authProvider: AuthProvider,
24-
authManager: IterableInternalAuthManagerProtocol?,
25-
endPoint: String,
26-
deviceMetadata: DeviceMetadata,
27-
networkSession: NetworkSessionProtocol,
28-
notificationCenter: NotificationCenterProtocol,
29-
strategy: RequestProcessorStrategy = DefaultRequestProcessorStrategy(selectOffline: false),
30-
taskRunner: IterableTaskRunner = IterableTaskRunner()) {
31-
offlineProcessor = OfflineRequestProcessor(apiKey: apiKey,
32-
authProvider: authProvider,
33-
authManager: authManager,
34-
endPoint: endPoint,
35-
deviceMetadata: deviceMetadata,
36-
taskRunner: taskRunner,
37-
notificationCenter: notificationCenter)
38-
onlineProcessor = OnlineRequestProcessor(apiKey: apiKey,
39-
authProvider: authProvider,
40-
authManager: authManager,
41-
endPoint: endPoint,
42-
networkSession: networkSession,
43-
deviceMetadata: deviceMetadata)
21+
class RequestProcessor: RequestProcessorProtocol {
22+
init(onlineCreator: @escaping () -> OnlineRequestProcessor,
23+
offlineCreator: @escaping () -> OfflineRequestProcessor?,
24+
strategy: RequestProcessorStrategy = DefaultRequestProcessorStrategy(selectOffline: false)) {
25+
self.onlineCreator = onlineCreator
26+
self.offlineCreator = offlineCreator
4427
self.strategy = strategy
4528
}
4629

@@ -260,11 +243,27 @@ struct RequestProcessor: RequestProcessorProtocol {
260243
onFailure: onFailure)
261244
}
262245

246+
private let onlineCreator: () -> OnlineRequestProcessor
247+
private let offlineCreator: () -> OfflineRequestProcessor?
248+
263249
private let strategy: RequestProcessorStrategy
264-
private let offlineProcessor: OfflineRequestProcessor
265-
private let onlineProcessor: OnlineRequestProcessor
250+
251+
private lazy var offlineProcessor: OfflineRequestProcessor? = {
252+
offlineCreator()
253+
}()
254+
255+
private lazy var onlineProcessor: OnlineRequestProcessor = {
256+
onlineCreator()
257+
}()
266258

267259
private func chooseRequestProcessor() -> RequestProcessorProtocol {
268-
strategy.chooseOfflineProcessor ? offlineProcessor: onlineProcessor
260+
if strategy.chooseOfflineProcessor {
261+
if let offlineProcessor = self.offlineProcessor {
262+
return offlineProcessor
263+
}
264+
return onlineProcessor
265+
} else {
266+
return onlineProcessor
267+
}
269268
}
270269
}

0 commit comments

Comments
 (0)