Skip to content

Commit d9d9abc

Browse files
Merge pull request #398 from Iterable/bug/mob-2153-memory-leak
[MOB-2153] - Fix memory leak
2 parents c4a3fc5 + 44f99b4 commit d9d9abc

13 files changed

+191
-128
lines changed

swift-sdk/Internal/ApiClient.swift

Lines changed: 60 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ struct DeviceMetadata: Codable {
1515

1616
class ApiClient {
1717
init(apiKey: String,
18-
authProvider: AuthProvider,
18+
authProvider: AuthProvider?,
1919
endPoint: String,
2020
networkSession: NetworkSessionProtocol,
2121
deviceMetadata: DeviceMetadata) {
@@ -54,13 +54,14 @@ class ApiClient {
5454

5555
// MARK: - Private
5656

57-
private func createRequestCreator() -> RequestCreator {
57+
private func createRequestCreator() -> Result<RequestCreator, IterableError> {
5858
guard let authProvider = authProvider else {
59-
fatalError("authProvider is missing")
59+
return .failure(IterableError.general(description: "authProvider is missing"))
6060
}
6161

62-
return RequestCreator(apiKey: apiKey, auth: authProvider.auth, deviceMetadata: deviceMetadata)
62+
return .success(RequestCreator(apiKey: apiKey, auth: authProvider.auth, deviceMetadata: deviceMetadata))
6363
}
64+
6465

6566
private func createIterableHeaders() -> [String: String] {
6667
var headers = [JsonKey.contentType.jsonKey: JsonValue.applicationJson.jsonStringValue,
@@ -86,40 +87,52 @@ class ApiClient {
8687

8788
extension ApiClient: ApiClientProtocol {
8889
func register(registerTokenInfo: RegisterTokenInfo, notificationsEnabled: Bool) -> Future<SendRequestValue, SendRequestError> {
89-
send(iterableRequestResult: createRequestCreator().createRegisterTokenRequest(registerTokenInfo: registerTokenInfo,
90-
notificationsEnabled: notificationsEnabled))
90+
let result = createRequestCreator().flatMap { $0.createRegisterTokenRequest(registerTokenInfo: registerTokenInfo,
91+
notificationsEnabled: notificationsEnabled) }
92+
return send(iterableRequestResult: result)
9193
}
9294

9395
func updateUser(_ dataFields: [AnyHashable: Any], mergeNestedObjects: Bool) -> Future<SendRequestValue, SendRequestError> {
94-
send(iterableRequestResult: createRequestCreator().createUpdateUserRequest(dataFields: dataFields, mergeNestedObjects: mergeNestedObjects))
96+
let result = createRequestCreator().flatMap { $0.createUpdateUserRequest(dataFields: dataFields,
97+
mergeNestedObjects: mergeNestedObjects) }
98+
return send(iterableRequestResult: result)
9599
}
96100

97101
func updateEmail(newEmail: String) -> Future<SendRequestValue, SendRequestError> {
98-
send(iterableRequestResult: createRequestCreator().createUpdateEmailRequest(newEmail: newEmail))
102+
let result = createRequestCreator().flatMap { $0.createUpdateEmailRequest(newEmail: newEmail) }
103+
return send(iterableRequestResult: result)
99104
}
100105

101106
func getInAppMessages(_ count: NSNumber) -> Future<SendRequestValue, SendRequestError> {
102-
send(iterableRequestResult: createRequestCreator().createGetInAppMessagesRequest(count))
107+
let result = createRequestCreator().flatMap { $0.createGetInAppMessagesRequest(count) }
108+
return send(iterableRequestResult: result)
103109
}
104110

105111
func disableDevice(forAllUsers allUsers: Bool, hexToken: String) -> Future<SendRequestValue, SendRequestError> {
106-
send(iterableRequestResult: createRequestCreator().createDisableDeviceRequest(forAllUsers: allUsers, hexToken: hexToken))
112+
let result = createRequestCreator().flatMap { $0.createDisableDeviceRequest(forAllUsers: allUsers,
113+
hexToken: hexToken) }
114+
return send(iterableRequestResult: result)
107115
}
108116

109117
func track(purchase total: NSNumber, items: [CommerceItem], dataFields: [AnyHashable: Any]?) -> Future<SendRequestValue, SendRequestError> {
110-
send(iterableRequestResult: createRequestCreator().createTrackPurchaseRequest(total, items: items, dataFields: dataFields))
118+
let result = createRequestCreator().flatMap { $0.createTrackPurchaseRequest(total, items: items,
119+
dataFields: dataFields) }
120+
return send(iterableRequestResult: result)
111121
}
112122

113123
func track(pushOpen campaignId: NSNumber, templateId: NSNumber?, messageId: String, appAlreadyRunning: Bool, dataFields: [AnyHashable: Any]?) -> Future<SendRequestValue, SendRequestError> {
114-
send(iterableRequestResult: createRequestCreator().createTrackPushOpenRequest(campaignId,
115-
templateId: templateId,
116-
messageId: messageId,
117-
appAlreadyRunning: appAlreadyRunning,
118-
dataFields: dataFields))
124+
let result = createRequestCreator().flatMap { $0.createTrackPushOpenRequest(campaignId,
125+
templateId: templateId,
126+
messageId: messageId,
127+
appAlreadyRunning: appAlreadyRunning,
128+
dataFields: dataFields) }
129+
return send(iterableRequestResult: result)
119130
}
120131

121132
func track(event eventName: String, dataFields: [AnyHashable: Any]?) -> Future<SendRequestValue, SendRequestError> {
122-
send(iterableRequestResult: createRequestCreator().createTrackEventRequest(eventName, dataFields: dataFields))
133+
let result = createRequestCreator().flatMap { $0.createTrackEventRequest(eventName,
134+
dataFields: dataFields) }
135+
return send(iterableRequestResult: result)
123136
}
124137

125138
func updateSubscriptions(_ emailListIds: [NSNumber]? = nil,
@@ -128,40 +141,52 @@ extension ApiClient: ApiClientProtocol {
128141
subscribedMessageTypeIds: [NSNumber]? = nil,
129142
campaignId: NSNumber? = nil,
130143
templateId: NSNumber? = nil) -> Future<SendRequestValue, SendRequestError> {
131-
send(iterableRequestResult: createRequestCreator().createUpdateSubscriptionsRequest(emailListIds,
132-
unsubscribedChannelIds: unsubscribedChannelIds,
133-
unsubscribedMessageTypeIds: unsubscribedMessageTypeIds,
134-
subscribedMessageTypeIds: subscribedMessageTypeIds,
135-
campaignId: campaignId,
136-
templateId: templateId))
144+
let result = createRequestCreator().flatMap { $0.createUpdateSubscriptionsRequest(emailListIds,
145+
unsubscribedChannelIds: unsubscribedChannelIds,
146+
unsubscribedMessageTypeIds: unsubscribedMessageTypeIds,
147+
subscribedMessageTypeIds: subscribedMessageTypeIds,
148+
campaignId: campaignId,
149+
templateId: templateId) }
150+
return send(iterableRequestResult: result)
137151
}
138152

139153
func track(inAppOpen inAppMessageContext: InAppMessageContext) -> Future<SendRequestValue, SendRequestError> {
140-
send(iterableRequestResult: createRequestCreator().createTrackInAppOpenRequest(inAppMessageContext: inAppMessageContext))
154+
let result = createRequestCreator().flatMap { $0.createTrackInAppOpenRequest(inAppMessageContext: inAppMessageContext) }
155+
return send(iterableRequestResult: result)
141156
}
142157

143158
func track(inAppClick inAppMessageContext: InAppMessageContext, clickedUrl: String) -> Future<SendRequestValue, SendRequestError> {
144-
send(iterableRequestResult: createRequestCreator().createTrackInAppClickRequest(inAppMessageContext: inAppMessageContext, clickedUrl: clickedUrl))
159+
let result = createRequestCreator().flatMap { $0.createTrackInAppClickRequest(inAppMessageContext: inAppMessageContext,
160+
clickedUrl: clickedUrl) }
161+
return send(iterableRequestResult: result)
145162
}
146163

147164
func track(inAppClose inAppMessageContext: InAppMessageContext, source: InAppCloseSource?, clickedUrl: String?) -> Future<SendRequestValue, SendRequestError> {
148-
send(iterableRequestResult: createRequestCreator().createTrackInAppCloseRequest(inAppMessageContext: inAppMessageContext, source: source, clickedUrl: clickedUrl))
165+
let result = createRequestCreator().flatMap { $0.createTrackInAppCloseRequest(inAppMessageContext: inAppMessageContext,
166+
source: source,
167+
clickedUrl: clickedUrl) }
168+
return send(iterableRequestResult: result)
149169
}
150170

151171
func track(inAppDelivery inAppMessageContext: InAppMessageContext) -> Future<SendRequestValue, SendRequestError> {
152-
send(iterableRequestResult: createRequestCreator().createTrackInAppDeliveryRequest(inAppMessageContext: inAppMessageContext))
172+
let result = createRequestCreator().flatMap { $0.createTrackInAppDeliveryRequest(inAppMessageContext: inAppMessageContext) }
173+
return send(iterableRequestResult: result)
153174
}
154175

155176
func track(inboxSession: IterableInboxSession) -> Future<SendRequestValue, SendRequestError> {
156-
send(iterableRequestResult: createRequestCreator().createTrackInboxSessionRequest(inboxSession: inboxSession))
177+
let result = createRequestCreator().flatMap { $0.createTrackInboxSessionRequest(inboxSession: inboxSession) }
178+
return send(iterableRequestResult: result)
157179
}
158180

159181
func inAppConsume(messageId: String) -> Future<SendRequestValue, SendRequestError> {
160-
send(iterableRequestResult: createRequestCreator().createInAppConsumeRequest(messageId))
182+
let result = createRequestCreator().flatMap { $0.createInAppConsumeRequest(messageId) }
183+
return send(iterableRequestResult: result)
161184
}
162185

163186
func inAppConsume(inAppMessageContext: InAppMessageContext, source: InAppDeleteSource?) -> Future<SendRequestValue, SendRequestError> {
164-
send(iterableRequestResult: createRequestCreator().createTrackInAppConsumeRequest(inAppMessageContext: inAppMessageContext, source: source))
187+
let result = createRequestCreator().flatMap { $0.createTrackInAppConsumeRequest(inAppMessageContext: inAppMessageContext,
188+
source: source) }
189+
return send(iterableRequestResult: result)
165190
}
166191
}
167192

@@ -170,11 +195,14 @@ extension ApiClient: ApiClientProtocol {
170195
extension ApiClient {
171196
// deprecated - will be removed in version 6.3.x or above
172197
func track(inAppOpen messageId: String) -> Future<SendRequestValue, SendRequestError> {
173-
send(iterableRequestResult: createRequestCreator().createTrackInAppOpenRequest(messageId))
198+
let value = createRequestCreator().flatMap { $0.createTrackInAppOpenRequest(messageId) }
199+
return send(iterableRequestResult: value)
174200
}
175201

176202
// deprecated - will be removed in version 6.3.x or above
177203
func track(inAppClick messageId: String, clickedUrl: String) -> Future<SendRequestValue, SendRequestError> {
178-
send(iterableRequestResult: createRequestCreator().createTrackInAppClickRequest(messageId, clickedUrl: clickedUrl))
204+
let result = createRequestCreator().flatMap { $0.createTrackInAppClickRequest(messageId,
205+
clickedUrl: clickedUrl) }
206+
return send(iterableRequestResult: result)
179207
}
180208
}

swift-sdk/Internal/DependencyContainer.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,18 @@ extension DependencyContainerProtocol {
5151

5252
func createRequestProcessor(apiKey: String,
5353
config: IterableConfig,
54-
authProvider: AuthProvider,
54+
authProvider: AuthProvider?,
5555
authManager: IterableInternalAuthManagerProtocol,
5656
deviceMetadata: DeviceMetadata) -> RequestProcessorProtocol {
5757
if #available(iOS 10.0, *) {
58-
return RequestProcessor(onlineCreator: {
58+
return RequestProcessor(onlineCreator: { [weak authProvider] in
5959
OnlineRequestProcessor(apiKey: apiKey,
6060
authProvider: authProvider,
6161
authManager: authManager,
6262
endPoint: config.apiEndpoint,
6363
networkSession: networkSession,
6464
deviceMetadata: deviceMetadata) },
65-
offlineCreator: {
65+
offlineCreator: { [weak authProvider] in
6666
guard let persistenceContextProvider = createPersistenceContextProvider() else {
6767
return nil
6868
}

swift-sdk/Internal/InAppInternal.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ protocol InAppFetcherProtocol {
1010
}
1111

1212
/// For callbacks when silent push notifications arrive
13-
protocol InAppNotifiable {
13+
protocol InAppNotifiable: AnyObject {
1414
func scheduleSync() -> Future<Bool, Error>
1515
func onInAppRemoved(messageId: String)
1616
func reset() -> Future<Bool, Error>

swift-sdk/Internal/IterableAPIInternal.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,7 @@ final class IterableAPIInternal: NSObject, PushTrackerProtocol, AuthProvider {
606606

607607
deinit {
608608
ITBInfo()
609+
requestProcessor.stop()
609610
}
610611
}
611612

swift-sdk/Internal/IterableAppIntegrationInternal.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,11 @@ extension PushTrackerProtocol {
129129
extension UIApplication: ApplicationStateProviderProtocol {}
130130

131131
struct IterableAppIntegrationInternal {
132-
private let tracker: PushTrackerProtocol
132+
private weak var tracker: PushTrackerProtocol?
133133
private let urlDelegate: IterableURLDelegate?
134134
private let customActionDelegate: IterableCustomActionDelegate?
135135
private let urlOpener: UrlOpenerProtocol?
136-
private let inAppNotifiable: InAppNotifiable
136+
private weak var inAppNotifiable: InAppNotifiable?
137137

138138
init(tracker: PushTrackerProtocol,
139139
urlDelegate: IterableURLDelegate? = nil,
@@ -162,10 +162,10 @@ struct IterableAppIntegrationInternal {
162162
if case let NotificationInfo.silentPush(silentPush) = NotificationHelper.inspect(notification: userInfo) {
163163
switch silentPush.notificationType {
164164
case .update:
165-
_ = inAppNotifiable.scheduleSync()
165+
_ = inAppNotifiable?.scheduleSync()
166166
case .remove:
167167
if let messageId = silentPush.messageId {
168-
inAppNotifiable.onInAppRemoved(messageId: messageId)
168+
inAppNotifiable?.onInAppRemoved(messageId: messageId)
169169
} else {
170170
ITBError("messageId not found in 'remove' silent push")
171171
}
@@ -222,7 +222,7 @@ struct IterableAppIntegrationInternal {
222222

223223
// Track push open
224224
if let _ = dataFields[JsonKey.actionIdentifier.jsonKey] { // i.e., if action is not dismiss
225-
tracker.trackPushOpen(userInfo, dataFields: dataFields)
225+
tracker?.trackPushOpen(userInfo, dataFields: dataFields)
226226
}
227227

228228
// Execute the action
@@ -314,7 +314,7 @@ struct IterableAppIntegrationInternal {
314314

315315
// Track push open
316316
let dataFields = [JsonKey.actionIdentifier.jsonKey: JsonValue.ActionIdentifier.pushOpenDefault]
317-
tracker.trackPushOpen(userInfo, dataFields: dataFields)
317+
tracker?.trackPushOpen(userInfo, dataFields: dataFields)
318318

319319
guard let itbl = IterableAppIntegrationInternal.itblValue(fromUserInfo: userInfo) else {
320320
return
@@ -333,7 +333,7 @@ struct IterableAppIntegrationInternal {
333333
}
334334

335335
private func alreadyTracked(userInfo: [AnyHashable: Any]) -> Bool {
336-
guard let lastPushPayload = tracker.lastPushPayload else {
336+
guard let lastPushPayload = tracker?.lastPushPayload else {
337337
return false
338338
}
339339

swift-sdk/Internal/IterableTaskRunner.swift

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,17 @@ class IterableTaskRunner: NSObject {
121121
ITBInfo("Paused")
122122
return
123123
}
124-
125-
DispatchQueue.global().async {
124+
125+
DispatchQueue.global().async { [weak self] in
126126
ITBInfo("Scheduling timer")
127-
let timer = Timer.scheduledTimer(withTimeInterval: self.timeInterval, repeats: false) { _ in
128-
self.run()
127+
guard let timeInterval = self?.timeInterval else {
128+
return
129129
}
130-
self.timer = timer
130+
131+
let timer = Timer.scheduledTimer(withTimeInterval: timeInterval, repeats: false) { [weak self] _ in
132+
self?.run()
133+
}
134+
self?.timer = timer
131135
RunLoop.current.add(timer, forMode: .default)
132136
RunLoop.current.run()
133137
}
@@ -224,6 +228,7 @@ class IterableTaskRunner: NSObject {
224228

225229
deinit {
226230
ITBInfo()
231+
stop()
227232
notificationCenter.removeObserver(self)
228233
}
229234

@@ -250,7 +255,7 @@ class IterableTaskRunner: NSObject {
250255
private let notificationCenter: NotificationCenterProtocol
251256
private let timeInterval: TimeInterval
252257
private let connectivityManager: NetworkConnectivityManager
253-
private var timer: Timer?
258+
private weak var timer: Timer?
254259
private var running = false
255260

256261
private lazy var persistenceContext: IterablePersistenceContext = {

swift-sdk/Internal/NetworkConnectivityManager.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class NetworkConnectivityManager: NSObject {
3131
deinit {
3232
ITBInfo()
3333
notificationCenter.removeObserver(self)
34-
stopTimer()
34+
stop()
3535
}
3636

3737
var isOnline: Bool {

swift-sdk/Internal/NetworkMonitor.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class NetworkMonitor: NetworkMonitorProtocol {
2626

2727
deinit {
2828
ITBInfo()
29+
stop()
2930
}
3031

3132
var statusUpdatedCallback: (() -> Void)?
@@ -45,9 +46,10 @@ class NetworkMonitor: NetworkMonitorProtocol {
4546
func stop() {
4647
ITBInfo()
4748
networkMonitor?.cancel()
49+
networkMonitor = nil
4850
}
4951

50-
private var networkMonitor: NWPathMonitor?
52+
private weak var networkMonitor: NWPathMonitor?
5153
private let queue = DispatchQueue(label: "NetworkMonitor")
5254
}
5355

0 commit comments

Comments
 (0)