StoreKit SKProducts请求崩溃

Posted

技术标签:

【中文标题】StoreKit SKProducts请求崩溃【英文标题】:StoreKit SKProductsRequest Crash 【发布时间】:2011-03-20 11:17:27 【问题描述】:

我使用以下代码根据应用内购买编程指南请求产品列表。它曾经在我的 iPhone 应用程序中运行良好,但现在每次请求产品列表时它都会崩溃。委托方法 (void)productsRequest:(SKProductsRequest **)request didReceiveResponse:(SKProductsResponse **)response 永远不会被调用。

SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:@"my.product.identifier"]];
[request setDelegate:self];
[request start];

正如我所说,它工作得很好,然后就停止工作了。这是调用上述代码时发生的崩溃。

Exception Type:  EXC_BAD_ACCESS (SIGBUS)
Exception Codes: KERN_PROTECTION_FAILURE at 0x00000011
Crashed Thread:  0

Thread 0 Crashed:
0   libobjc.A.dylib                 0x000034f8 objc_msgSend + 24
1   StoreKit                        0x00003e18 -[SKProductsRequest handleFinishResponse:returningError:] + 40
2   StoreKit                        0x000050c4 -[SKRequest _requestFinishedNotification:] + 152
3   Foundation                      0x00019b9a _nsnote_callback + 150
4   CoreFoundation                  0x0006c2de __CFXNotificationPost_old + 390
5   CoreFoundation                  0x0001ab32 _CFXNotificationPostNotification + 122
6   Foundation                      0x000048e4 -[NSNotificationCenter postNotificationName:object:userInfo:] + 64
7   AppSupport                      0x0000bb42 -[CPDistributedNotificationCenter deliverNotification:userInfo:] + 38
8   AppSupport                      0x0000cf66 _CPDNDeliverNotification + 198
9   AppSupport                      0x0000ba4a _XDeliverNotification + 110
10  AppSupport                      0x00002e82 migHelperRecievePortCallout + 122
11  CoreFoundation                  0x000742ac __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 22
12  CoreFoundation                  0x000761d6 __CFRunLoopDoSource1 + 158
13  CoreFoundation                  0x0007718e __CFRunLoopRun + 574
14  CoreFoundation                  0x0001e0bc CFRunLoopRunSpecific + 220
15  CoreFoundation                  0x0001dfca CFRunLoopRunInMode + 54
16  GraphicsServices                0x00003f88 GSEventRunModal + 188
17  UIKit                           0x00007b40 -[UIApplication _run] + 564
18  UIKit                           0x00005fb8 UIApplicationMain + 964
19  myapp                           0x00002fae main (main.m:13)
20  myapp                           0x00002f58 start + 32

Thread 1:
0   libSystem.B.dylib               0x00034e84 kevent + 24
1   libSystem.B.dylib               0x00102a48 _dispatch_mgr_invoke + 88
2   libSystem.B.dylib               0x00102494 _dispatch_queue_invoke + 96
3   libSystem.B.dylib               0x00102634 _dispatch_worker_thread2 + 120
4   libSystem.B.dylib               0x0008b53c _pthread_wqthread + 392
5   libSystem.B.dylib               0x00082b6c start_wqthread + 0

Thread 2:
0   libSystem.B.dylib               0x00000ab0 mach_msg_trap + 20
1   libSystem.B.dylib               0x00002f94 mach_msg + 60
2   CoreFoundation                  0x00074b18 __CFRunLoopServiceMachPort + 88
3   CoreFoundation                  0x000770e0 __CFRunLoopRun + 400
4   CoreFoundation                  0x0001e0bc CFRunLoopRunSpecific + 220
5   CoreFoundation                  0x0001dfca CFRunLoopRunInMode + 54
6   WebCore                         0x0000370c RunWebThread(void*) + 552
7   libSystem.B.dylib               0x0008af80 _pthread_start + 364
8   libSystem.B.dylib               0x0007d014 thread_start + 0

Thread 3:
0   libSystem.B.dylib               0x00000ab0 mach_msg_trap + 20
1   libSystem.B.dylib               0x00002f94 mach_msg + 60
2   CoreFoundation                  0x00074b18 __CFRunLoopServiceMachPort + 88
3   CoreFoundation                  0x000770e0 __CFRunLoopRun + 400
4   CoreFoundation                  0x0001e0bc CFRunLoopRunSpecific + 220
5   CoreFoundation                  0x0001dfca CFRunLoopRunInMode + 54
6   Foundation                      0x0003c316 +[NSURLConnection(NSURLConnectionReallyInternal) _resourceLoadLoop:] + 210
7   Foundation                      0x0000c612 -[NSThread main] + 42
8   Foundation                      0x00092140 __NSThread__main__ + 908
9   libSystem.B.dylib               0x0008af80 _pthread_start + 364
10  libSystem.B.dylib               0x0007d014 thread_start + 0

Thread 4:
0   libSystem.B.dylib               0x00029f24 select$DARWIN_EXTSN + 20
1   CoreFoundation                  0x0007aa54 __CFSocketManager + 340
2   libSystem.B.dylib               0x0008af80 _pthread_start + 364
3   libSystem.B.dylib               0x0007d014 thread_start + 0

我不知道是什么导致了 objc_msgSend 崩溃,或者它与 StoreKit 有什么关系。我也不知道我添加或更改了什么导致这个简单的代码停止工作。

【问题讨论】:

【参考方案1】:

一个很可能的解释是您设置为 SKProductRequest 对象的委托的对象是否可能已经被释放。

请求很可能需要几秒钟才能完成,这可能已经超过了委托对象的生命周期,因此您可能需要确保它存在足够长的时间。

【讨论】:

确实是问题所在。不久前用大致相同的答案解决了这个问题,不知何故似乎已经消失了。 好的,我知道委托可能会被解除分配,但您将如何解决这个问题? 确保对它的强引用保持足够长的时间,并在知道对象消失后将委托设置为 nil(尽管这可能是不必要的)。 花了一个小时调查这个问题。天哪,在使用委托之前进行一次检查,这一切从未发生过。【参考方案2】:

上面的答案在技术上是正确的,但并不完整。正如 Megastep 所说,“您设置为 SKProductsRequest 委托的对象可能已经被释放。”因此,您正在向已被释放的对象发送消息。现在进入实际答案:

- (void)requestProUpgradeProductData 
    NSSet *productIdentifiers = //Your Product IDs go here

    productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
    productsRequest.delegate = self;
    [productsRequest start];

    // we will release the request object in the delegate callback


#pragma mark -
#pragma mark SKProductRequest Delegate Methods

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse(SKProductsResponse *)response 
self.products = response.products;
//NSLog(@"%i",[products count]);
proUpgradeProduct = [products count] == 4 ? [[products objectAtIndex:0] retain] : nil;
if (proUpgradeProduct)

    //Do your stuff here...


for (NSString *invalidProductId in response.invalidProductIdentifiers)

    //NSLog(@"Invalid product id: %@" , invalidProductId);


// finally release the reqest we alloc/init’ed in requestProUpgradeProductData
[productsRequest release];

[[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerProductsFetchedNotification object:self userInfo:nil];

所以基本上正如你在上面看到的,你不需要释放 productsRequest,因为它已经在委托回调方法中被释放了。同样,您不需要在 viewDidUnload/dealloc 方法中调用 productsRequest release 或将其设置为 Nil,因为如果您在调用回调方法之前关闭视图,这可能会导致崩溃。

【讨论】:

【参考方案3】:

我正在使用像委托这样的对象。所以在这个对象的 deinit 方法中,我删除了委托 a 并且崩溃已得到修复。

private var currentProductRequest: SKProductsRequest?

deinit 
    if let r = currentProductRequest 
        r.delegate = nil
        r.cancel()
        currentProductRequest = nil
    

【讨论】:

以上是关于StoreKit SKProducts请求崩溃的主要内容,如果未能解决你的问题,请参考以下文章

Storekit 框架

iOS15之StoreKit 2

StoreKit.framework 从库目录中删除

我在哪里可以下载 StoreKit.framework

StoreKit 框架

StoreKit 错误代码