@@ -692,7 +692,9 @@ + (void)reset
692692 [state.noDownloadsBlocks removeAllObjects ];
693693 [state.onceNoDownloadsBlocks removeAllObjects ];
694694 [state.noDownloadsResponders removeAllObjects ];
695- [state.userAttributeChanges removeAllObjects ];
695+ @synchronized ([LPInternalState sharedState ].userAttributeChanges ) {
696+ [state.userAttributeChanges removeAllObjects ];
697+ }
696698 state.calledHandleNotification = NO ;
697699
698700 [[LPInbox sharedState ] reset ];
@@ -775,7 +777,9 @@ + (void)startWithUserId:(NSString *)userId
775777 [LPMessageTemplatesClass sharedTemplates ];
776778 attributes = [self validateAttributes: attributes named: @" userAttributes" allowLists: YES ];
777779 if (attributes != nil ) {
778- [state.userAttributeChanges addObject: attributes];
780+ @synchronized ([LPInternalState sharedState ].userAttributeChanges ) {
781+ [state.userAttributeChanges addObject: attributes];
782+ }
779783 }
780784 state.calledStart = YES ;
781785 dispatch_async (dispatch_get_main_queue (), ^{
@@ -2017,12 +2021,14 @@ + (void)setUserId:(NSString *)userId withUserAttributes:(NSDictionary *)attribut
20172021 [self throwError: @" You cannot call setUserId before calling start" ];
20182022 return ;
20192023 }
2024+ LP_END_USER_CODE // Catch when setUser is called in start response.
20202025 LP_TRY
20212026 attributes = [self validateAttributes: attributes named: @" userAttributes" allowLists: YES ];
20222027 [self onStartIssued: ^{
20232028 [self setUserIdInternal: userId withAttributes: attributes];
20242029 }];
20252030 LP_END_TRY
2031+ LP_BEGIN_USER_CODE
20262032}
20272033
20282034+ (void )setUserIdInternal : (NSString *)userId withAttributes : (NSDictionary *)attributes
@@ -2052,7 +2058,9 @@ + (void)setUserIdInternal:(NSString *)userId withAttributes:(NSDictionary *)attr
20522058 }
20532059
20542060 if (attributes != nil ) {
2055- [[LPInternalState sharedState ].userAttributeChanges addObject: attributes];
2061+ @synchronized ([LPInternalState sharedState ].userAttributeChanges ) {
2062+ [[LPInternalState sharedState ].userAttributeChanges addObject: attributes];
2063+ }
20562064 }
20572065
20582066 [Leanplum onStartResponse: ^(BOOL success) {
@@ -2066,35 +2074,30 @@ + (void)setUserIdInternal:(NSString *)userId withAttributes:(NSDictionary *)attr
20662074// Returns if attributes have changed.
20672075+ (void )recordAttributeChanges
20682076{
2069- BOOL madeChanges = NO ;
2070- // Making a copy. Other threads can add attributes while iterating.
2071- NSMutableArray *attributeChanges = [[LPInternalState sharedState ].userAttributeChanges copy ];
2072- // Keep track of processed changes to be removed at the end.
2073- NSMutableArray *processedChanges = [NSMutableArray new ];
2074- for (NSDictionary *attributes in attributeChanges) {
2077+ @synchronized ([LPInternalState sharedState ].userAttributeChanges ){
2078+ BOOL __block madeChanges = NO ;
20752079 NSMutableDictionary *existingAttributes = [LPVarCache userAttributes ];
2076- [processedChanges addObject: attributes];
2077- for (NSString *attributeName in [attributes allKeys ]) {
2078- id existingValue = existingAttributes[attributeName];
2079- id value = attributes[attributeName];
2080- if (![value isEqual: existingValue]) {
2081- LPContextualValues *contextualValues = [[LPContextualValues alloc ] init ];
2082- contextualValues.previousAttributeValue = existingValue;
2083- contextualValues.attributeValue = value;
2084- existingAttributes[attributeName] = value;
2085- [Leanplum maybePerformActions: @[@" userAttribute" ]
2086- withEventName: attributeName
2087- withFilter: kLeanplumActionFilterAll
2088- fromMessageId: nil
2089- withContextualValues: contextualValues];
2090- madeChanges = YES ;
2091- }
2080+ for (NSDictionary *attributes in [LPInternalState sharedState ].userAttributeChanges ) {
2081+ [attributes enumerateKeysAndObjectsUsingBlock: ^(id attributeName, id value, BOOL *stop) {
2082+ id existingValue = existingAttributes[attributeName];
2083+ if (![value isEqual: existingValue]) {
2084+ LPContextualValues *contextualValues = [LPContextualValues new ];
2085+ contextualValues.previousAttributeValue = existingValue;
2086+ contextualValues.attributeValue = value;
2087+ existingAttributes[attributeName] = value;
2088+ [Leanplum maybePerformActions: @[@" userAttribute" ]
2089+ withEventName: attributeName
2090+ withFilter: kLeanplumActionFilterAll
2091+ fromMessageId: nil
2092+ withContextualValues: contextualValues];
2093+ madeChanges = YES ;
2094+ }
2095+ }];
2096+ }
2097+ [[LPInternalState sharedState ].userAttributeChanges removeAllObjects ];
2098+ if (madeChanges) {
2099+ [LPVarCache saveUserAttributes ];
20922100 }
2093- }
2094- // Remove only processed changes.
2095- [[LPInternalState sharedState ].userAttributeChanges removeObjectsInArray: processedChanges];
2096- if (madeChanges) {
2097- [LPVarCache saveUserAttributes ];
20982101 }
20992102}
21002103
0 commit comments