From 234b847beaac1f4d6064f55d1b5f166716da5c0d Mon Sep 17 00:00:00 2001 From: Kamo Spertsyan Date: Thu, 17 Oct 2024 12:29:38 +0300 Subject: [PATCH 1/3] Attempt to fix crashes and race conditions in User Properties manager --- .../QNUserPropertiesManager.m | 52 ++++++++++++------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/Sources/Qonversion/Qonversion/Main/QNUserPropertiesManager/QNUserPropertiesManager.m b/Sources/Qonversion/Qonversion/Main/QNUserPropertiesManager/QNUserPropertiesManager.m index 33cb74e8..3df2dc2b 100644 --- a/Sources/Qonversion/Qonversion/Main/QNUserPropertiesManager/QNUserPropertiesManager.m +++ b/Sources/Qonversion/Qonversion/Main/QNUserPropertiesManager/QNUserPropertiesManager.m @@ -26,10 +26,10 @@ @interface QNUserPropertiesManager() @property (nonatomic) QNInMemoryStorage *inMemoryStorage; -@property (nonatomic, strong) NSMutableArray *completionBlocks; +@property (atomic, strong) NSMutableArray *completionBlocks; -@property (nonatomic, assign, readwrite) BOOL sendingScheduled; -@property (nonatomic, assign, readwrite) BOOL updatingCurrently; +@property (atomic, assign, readwrite) BOOL sendingScheduled; +@property (atomic, assign, readwrite) BOOL updatingCurrently; @property (nonatomic, assign, readwrite) NSUInteger retryDelay; @property (nonatomic, assign, readwrite) NSUInteger retriesCounter; @@ -94,25 +94,31 @@ - (void)forceSendProperties:(QONUserPropertiesEmptyCompletionHandler)completion return; } - [self.completionBlocks addObject:completion]; + @synchronized (self) { + [self.completionBlocks addObject:completion]; + } [self sendProperties:YES]; } - (void)sendPropertiesWithDelay:(NSUInteger)delay { - if (!_sendingScheduled) { - _sendingScheduled = YES; - __block __weak QNUserPropertiesManager *weakSelf = self; - [_backgroundQueue addOperationWithBlock:^{ - dispatch_async(dispatch_get_main_queue(), ^{ - [weakSelf performSelector:@selector(sendPropertiesInBackground) withObject:nil afterDelay:delay]; - }); - }]; + @synchronized (self) { + if (!_sendingScheduled) { + _sendingScheduled = YES; + __block __weak QNUserPropertiesManager *weakSelf = self; + [_backgroundQueue addOperationWithBlock:^{ + dispatch_async(dispatch_get_main_queue(), ^{ + [weakSelf performSelector:@selector(sendPropertiesInBackground) withObject:nil afterDelay:delay]; + }); + }]; + } } } - (void)sendPropertiesInBackground { - _sendingScheduled = NO; + @synchronized (self) { + _sendingScheduled = NO; + } [self sendProperties]; } @@ -137,12 +143,16 @@ - (void)sendProperties:(BOOL)force { NSDictionary *properties = [self->_inMemoryStorage.storageDictionary copy]; if (!properties || ![properties respondsToSelector:@selector(valueForKey:)]) { - self->_updatingCurrently = NO; + @synchronized (self) { + self->_updatingCurrently = NO; + } return; } if (properties.count == 0) { - self->_updatingCurrently = NO; + @synchronized (self) { + self->_updatingCurrently = NO; + } return; } @@ -150,15 +160,19 @@ - (void)sendProperties:(BOOL)force { __block __weak QNUserPropertiesManager *weakSelf = self; [self.apiClient sendProperties:properties completion:^(NSDictionary * _Nullable dict, NSError * _Nullable error) { - weakSelf.updatingCurrently = NO; - NSArray *completions = [weakSelf.completionBlocks copy]; + NSArray *completions = @[]; + @synchronized (self) { + weakSelf.updatingCurrently = NO; + + completions = [weakSelf.completionBlocks copy]; + [weakSelf.completionBlocks removeAllObjects]; + } + for (QONUserPropertiesEmptyCompletionHandler storedCompletion in completions) { storedCompletion(); } - [weakSelf.completionBlocks removeAllObjects]; - if (error) { // copy of an existing array to prevent erasing properties set while the current request is in progress NSMutableDictionary *allProperties = [self.inMemoryStorage.storageDictionary mutableCopy]; From f0c0825eb0a83218bab47a44eacf2c35c6d81a10 Mon Sep 17 00:00:00 2001 From: Kamo Spertsyan Date: Thu, 17 Oct 2024 12:33:48 +0300 Subject: [PATCH 2/3] Private members access fixes --- .../QNUserPropertiesManager.m | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Sources/Qonversion/Qonversion/Main/QNUserPropertiesManager/QNUserPropertiesManager.m b/Sources/Qonversion/Qonversion/Main/QNUserPropertiesManager/QNUserPropertiesManager.m index 3df2dc2b..7e55f82b 100644 --- a/Sources/Qonversion/Qonversion/Main/QNUserPropertiesManager/QNUserPropertiesManager.m +++ b/Sources/Qonversion/Qonversion/Main/QNUserPropertiesManager/QNUserPropertiesManager.m @@ -103,10 +103,10 @@ - (void)forceSendProperties:(QONUserPropertiesEmptyCompletionHandler)completion - (void)sendPropertiesWithDelay:(NSUInteger)delay { @synchronized (self) { - if (!_sendingScheduled) { - _sendingScheduled = YES; + if (!self.sendingScheduled) { + self.sendingScheduled = YES; __block __weak QNUserPropertiesManager *weakSelf = self; - [_backgroundQueue addOperationWithBlock:^{ + [self.backgroundQueue addOperationWithBlock:^{ dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf performSelector:@selector(sendPropertiesInBackground) withObject:nil afterDelay:delay]; }); @@ -117,7 +117,7 @@ - (void)sendPropertiesWithDelay:(NSUInteger)delay { - (void)sendPropertiesInBackground { @synchronized (self) { - _sendingScheduled = NO; + self.sendingScheduled = NO; } [self sendProperties]; } @@ -127,31 +127,31 @@ - (void)sendProperties { } - (void)sendProperties:(BOOL)force { - if ([QNUtils isEmptyString:_apiClient.apiKey]) { + if ([QNUtils isEmptyString:self.apiClient.apiKey]) { QONVERSION_ERROR(@"ERROR: apiKey cannot be nil or empty, set apiKey with launchWithKey:"); return; } @synchronized (self) { - if (_updatingCurrently && !force) { + if (self.updatingCurrently && !force) { return; } - _updatingCurrently = YES; + self.updatingCurrently = YES; } [self runOnBackgroundQueue:^{ - NSDictionary *properties = [self->_inMemoryStorage.storageDictionary copy]; + NSDictionary *properties = [self.inMemoryStorage.storageDictionary copy]; if (!properties || ![properties respondsToSelector:@selector(valueForKey:)]) { @synchronized (self) { - self->_updatingCurrently = NO; + self.updatingCurrently = NO; } return; } if (properties.count == 0) { @synchronized (self) { - self->_updatingCurrently = NO; + self.updatingCurrently = NO; } return; } @@ -224,7 +224,7 @@ - (BOOL)runOnBackgroundQueue:(void (^)(void))block { block(); return NO; } else { - [_backgroundQueue addOperationWithBlock:block]; + [self.backgroundQueue addOperationWithBlock:block]; return YES; } } @@ -237,18 +237,18 @@ - (void)collectIntegrationsData { } - (void)collectIntegrationsDataInBackground { - [_device adjustUserIDWithCompletion:^(NSString * _Nullable userId) { + [self.device adjustUserIDWithCompletion:^(NSString * _Nullable userId) { if (![QNUtils isEmptyString:userId]) { [self setUserProperty:@"_q_adjust_adid" value:userId]; } }]; - NSString *fbAnonID = _device.fbAnonID; + NSString *fbAnonID = self.device.fbAnonID; if (![QNUtils isEmptyString:fbAnonID]) { [self setUserProperty:@"_q_fb_anon_id" value:fbAnonID]; } - NSString *afUserID = _device.afUserID; + NSString *afUserID = self.device.afUserID; if (![QNUtils isEmptyString:afUserID]) { [self setUserProperty:@"_q_appsflyer_user_id" value:afUserID]; } From e3379f4c976692bd5993e889f449a8ab5cf26a46 Mon Sep 17 00:00:00 2001 From: SpertsyanKM Date: Thu, 17 Oct 2024 13:19:28 +0000 Subject: [PATCH 3/3] [create-pull-request] automated change --- Framework/Info.plist | 2 +- Qonversion.podspec | 2 +- Sources/Qonversion/Public/QONConfiguration.m | 2 +- fastlane/report.xml | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Framework/Info.plist b/Framework/Info.plist index ab28e747..b6d898c4 100644 --- a/Framework/Info.plist +++ b/Framework/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 5.12.4 + 5.12.5 CFBundleSignature ???? CFBundleVersion diff --git a/Qonversion.podspec b/Qonversion.podspec index 055e0324..83d47d4b 100644 --- a/Qonversion.podspec +++ b/Qonversion.podspec @@ -3,7 +3,7 @@ Pod::Spec.new do |s| idfa_exclude_files = ['Sources/Qonversion/IDFA'] s.name = 'Qonversion' s.swift_version = '5.5' - s.version = '5.12.4' + s.version = '5.12.5' s.summary = 'qonversion.io' s.description = <<-DESC Deep Analytics for iOS Subscriptions diff --git a/Sources/Qonversion/Public/QONConfiguration.m b/Sources/Qonversion/Public/QONConfiguration.m index 22735e63..546aeceb 100644 --- a/Sources/Qonversion/Public/QONConfiguration.m +++ b/Sources/Qonversion/Public/QONConfiguration.m @@ -9,7 +9,7 @@ #import "QONConfiguration.h" #import "QNAPIConstants.h" -static NSString *const kSDKVersion = @"5.12.4"; +static NSString *const kSDKVersion = @"5.12.5"; @interface QONConfiguration () diff --git a/fastlane/report.xml b/fastlane/report.xml index b36a778c..726432fb 100644 --- a/fastlane/report.xml +++ b/fastlane/report.xml @@ -5,12 +5,12 @@ - + - +