一. 现象
我们某个App出现上述crash报告,目前只发现一例,内存访问异常引起
闪退位置:
闪退位置代码是在给一个数组进行复制,value是请求到的SKProduct对象。
二. Crash分析
XYStoreProductService类用于请求商品生成SKProduct对象,具体过程是使用SKProductsRequest,根据identifier发起一个请求,在回调里面获取SKProduct
1 | - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response |
但是这个回调是异步的,在子线程中返回,返回时间依赖于当前手机的网络环境,可能会比较慢。
在回调中会往XYStore中的数组products添加SKProduct对象
1 | - (void)addProduct:(SKProduct*)product |
添加动作是在子线程的,所以就可能出现同步问题,具体例子如下:
用户进入购买页会请求所有商品项,还没有返回成功的情况下,用户点击购买按钮,因为此时商品还没有返回,所以又会出发请求商品项的动作
1 | SKProduct *product = [self productForIdentifier:identifier]; |
此时会同时出现两次商品请求,两次返回,两个线程,同时对products进行设置操作,就有几率导致内存访问异常而crash。
这个crash的概率极低,需要满足以下条件:
- 第一次的request返回很慢
- 用户购买的商品的时候,商品项不存在
- 两次请求几乎同时返回
三. 如何解决
对products数组的访问添加同步方法即可,示例代码如下
1 | - (SKProduct*)productForIdentifier:(NSString*)productIdentifier |