StoreKit SKProductsRequest Crash
Я использую следующий код, чтобы запросить список продуктов в соответствии с руководством по программированию при покупке приложений. Он отлично работал в моем приложении 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, может быть уже освобожден.
Вполне возможно, что для выполнения запроса потребуется несколько секунд, и это может закончиться целым временем вашего объекта-делегата, поэтому вы можете захотеть убедиться, что оно достаточно длительное время.
Ответ 2
Ответ выше технически корректен, но он не является полным. Как сказал Мегастеп, "объект, который вы установили в качестве делегата для 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, потому что он уже выпущен в методе обратного вызова делегата. Снова вам не нужно вызывать выпуск продуктовRequest или устанавливать его в метод viewDidUnload/dealloc, потому что это может привести к сбою, если вы отклоните представление до вызова метода обратного вызова.
Ответ 3
Я использую объект как делегат. Таким образом, в методе deinit этого объекта я удаляю делегат a и crash был исправлен.
private var currentProductRequest: SKProductsRequest?
deinit {
if let r = currentProductRequest {
r.delegate = nil
r.cancel()
currentProductRequest = nil
}
}