Skip to content

Commit

Permalink
Fixed concurrency issue on iOS. (#413)
Browse files Browse the repository at this point in the history
The `productsRequest` method as per Apple docs can be called on any
thread (source:
https://developer.apple.com/documentation/storekit/skproductsrequestdelegate
(please check text in read)).
Working with `validProducts` on such thread can cause concurrency
issues, such as this one:
**"Terminating app due to uncaught exception 'NSGenericException',
reason: '*** Collection <__NSArrayM: 0x283ca4090> was mutated while
being enumerated.'"**

Moreover, flutter results must be called on platform main thread only
(source:
https://docs.flutter.dev/development/platform-integration/platform-channels)
_"Even though Flutter sends messages to and from Dart asynchronously,
whenever you invoke a channel method, you must invoke that method on the
platform’s main thread."_

To fix these issues I simply wrapped all the code in
`dispatch_async(dispatch_get_main_queue, ^{ ... })`.
Please pull this fix.

Co-authored-by: Alfred Lapkovsky <[email protected]>
  • Loading branch information
AlfredsLapkovskis and Alfred Lapkovsky authored Mar 22, 2023
1 parent 7a0289c commit 1237aa2
Showing 1 changed file with 15 additions and 13 deletions.
28 changes: 15 additions & 13 deletions ios/Classes/FlutterInappPurchasePlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -286,21 +286,23 @@ - (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
}

- (void)productsRequest:(nonnull SKProductsRequest *)request didReceiveResponse:(nonnull SKProductsResponse *)response {
NSValue* key = [NSValue valueWithNonretainedObject:request];
FlutterResult result = [fetchProducts objectForKey:key];
if (result == nil) return;
[fetchProducts removeObjectForKey:key];
dispatch_async(dispatch_get_main_queue(), ^{
NSValue* key = [NSValue valueWithNonretainedObject:request];
FlutterResult result = [self.fetchProducts objectForKey:key];
if (result == nil) return;
[self.fetchProducts removeObjectForKey:key];

for (SKProduct* prod in response.products) {
[self addProduct:prod];
}
NSMutableArray* items = [NSMutableArray array];

for (SKProduct* prod in response.products) {
[self addProduct:prod];
}
NSMutableArray* items = [NSMutableArray array];

for (SKProduct* product in validProducts) {
[items addObject:[self getProductObject:product]];
}
for (SKProduct* product in self->validProducts) {
[items addObject:[self getProductObject:product]];
}

result(items);
result(items);
});
}

-(void)addProduct:(SKProduct *)aProd {
Expand Down

0 comments on commit 1237aa2

Please sign in to comment.