Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 43 additions & 13 deletions Sources/BranchSDK/BNCNetworkService.m
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,36 @@ - (instancetype) init {
return self;
}

// Avoid locking in dealloc; just tear down with ivars
- (void)dealloc {
NSURLSession *session = _session;
if (session) {
[session invalidateAndCancel];
_session = nil;
}
NSOperationQueue *queue = _sessionQueue;
if (queue) {
[queue cancelAllOperations];
_sessionQueue = nil;
}
}

// IMPORTANT: do not touch properties here; use ivars so you don’t create a session while tearing down
- (void)cancelAllOperations {
@synchronized (self) {
NSURLSession *session = _session;
if (session) {
[session invalidateAndCancel];
_session = nil;
}
NSOperationQueue *queue = _sessionQueue;
if (queue) {
[queue cancelAllOperations];
_sessionQueue = nil;
}
}
}

#pragma mark - Getters & Setters

- (void) setDefaultTimeoutInterval:(NSTimeInterval)defaultTimeoutInterval {
Expand Down Expand Up @@ -183,25 +213,25 @@ - (void)startOperation:(BNCNetworkOperation *)operation {
} else {
[[BranchLogger shared] logError:[NSString stringWithFormat:@"Expected NSMutableURLRequest, got %@", [operation.request class]] error:nil];
}
operation.sessionTask = [self.session dataTaskWithRequest:operation.request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

operation.sessionTask = [self.session dataTaskWithRequest:operation.request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
operation.responseData = data;
operation.response = (NSHTTPURLResponse*) response;
operation.response = (NSHTTPURLResponse*)response;
operation.error = error;

if (operation.completionBlock) {
operation.completionBlock(operation);

// Capture, clear, then invoke to avoid unexpected long-lived captures
void (^completion)(BNCNetworkOperation *) = operation.completionBlock;
operation.completionBlock = nil;

if (completion) {
completion(operation);
}

// Break back-reference to the service
operation.networkService = nil;
}];

[operation.sessionTask resume];
}

- (void) cancelAllOperations {
@synchronized (self) {
[self.session invalidateAndCancel];
_session = nil;
}
}

@end
34 changes: 22 additions & 12 deletions Sources/BranchSDK/BNCPreferenceHelper.m
Original file line number Diff line number Diff line change
Expand Up @@ -1038,23 +1038,33 @@ - (void)writeObjectToDefaults:(NSString *)key value:(NSObject *)value {
}

- (void)persistPrefsToDisk {
if (self.useStorage) {
@synchronized (self) {
if (!self.persistenceDict) return;

NSData *data = [self serializePrefDict:self.persistenceDict];
if (!data) return;

NSURL *prefsURL = [self.class.URLForPrefsFile copy];
NSBlockOperation *newPersistOp = [NSBlockOperation blockOperationWithBlock:^ {
if (!self.useStorage) return;

@synchronized (self) {
if (!self.persistenceDict) return;

NSData *data = [self serializePrefDict:self.persistenceDict];
if (!data) return;

NSURL *prefsURL = [self.class.URLForPrefsFile copy];

// Coalesce: drop older pending writes to avoid retaining many large NSData snapshots
[_persistPrefsQueue cancelAllOperations];

NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
@autoreleasepool {
NSError *error = nil;
[data writeToURL:prefsURL options:NSDataWritingAtomic error:&error];
if (error) {
[[BranchLogger shared] logWarning:@"Failed to persist preferences" error:error];
}
}];
[_persistPrefsQueue addOperation:newPersistOp];
}
}
}];

// Optional: lower priority; it’s background I/O
op.queuePriority = NSOperationQueuePriorityLow;

[_persistPrefsQueue addOperation:op];
}
}

Expand Down
25 changes: 21 additions & 4 deletions Sources/BranchSDK/BNCURLFilter.m
Original file line number Diff line number Diff line change
Expand Up @@ -106,19 +106,36 @@ - (void)updatePatternListFromServerWithCompletion:(void (^_Nullable) (void))comp
return;
}

NSString *urlString = [NSString stringWithFormat:@"%@/sdk/uriskiplist_v%ld.json", [BNCPreferenceHelper sharedInstance].patternListURL, (long) self.listVersion+1];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:30.0];
NSString *urlString = [NSString stringWithFormat:@"%@/sdk/uriskiplist_v%ld.json",
[BNCPreferenceHelper sharedInstance].patternListURL,
(long)self.listVersion + 1];
NSMutableURLRequest *request =
[NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
timeoutInterval:30.0];

__block id<BNCNetworkServiceProtocol> networkService = [[Branch networkServiceClass] new];
id<BNCNetworkOperationProtocol> operation = [networkService networkOperationWithURLRequest:request completion: ^(id<BNCNetworkOperationProtocol> operation) {
[self processServerOperation:operation];

__weak typeof(self) weakSelf = self;
id<BNCNetworkOperationProtocol> operation =
[networkService networkOperationWithURLRequest:request
completion:^(id<BNCNetworkOperationProtocol> op) {
// Process result
[weakSelf processServerOperation:op];

if (completion) {
completion();
}

// IMPORTANT: break the NSURLSession delegate retain cycle
[networkService cancelAllOperations]; // invalidates and cancels the session
networkService = nil; // drop our last reference ASAP
}];

[operation start];
}


- (BOOL)foundUpdatedURLList:(id<BNCNetworkOperationProtocol>)operation {
NSInteger statusCode = operation.response.statusCode;
NSError *error = operation.error;
Expand Down