I use the following code to request a list of products as per the In-App Purchase Programming Guide. It used to work fine in my iPhone application, however now it crashes every time the product list is requested. The delegate method (void)productsRequest:(SKProductsRequest **)request didReceiveResponse:(SKProductsResponse **)response
is never called.
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:@"my.product.identifier"]];
[request setDelegate:self];
[request start];
As I said, it worked perfectly fine, then just stopped working. This is the crash which occurs when the above code is called.
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
I don't know what is causing the objc_msgSend crash, or how it is related to StoreKit. I also have no idea what I added or changed which caused this simple code to stop working.
A very likely explanation is whether the object you set as a delegate for the SKProductRequest object might have been deallocated already.
It is quite possible for the request to take a few seconds to complete, and this might be past the lifetime of your delegate object, so you may want to make sure it sticks around for long enough.
The answer above is technically correct but it is not complete. As Megastep said "the object you set as the delegate for the SKProductsRequest may have already been deallocated." Therefore you are sending a message to an object that has already been deallocated. Now onto the actual answer:
- (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];
}
So basically as you can see above you do not need to release productsRequest because it is already being released in the delegate callback method. Again you do not need to call productsRequest release or set it Nil in viewDidUnload/dealloc method because that could cause a crash if you dismiss the view before the callback method gets called.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With