- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
一个客户给我带来了一个现有的应用程序,我们刚刚发布了一个新版本,其中包括用于崩溃报告的 Crittercism。
自发布以来,我们收到了大量崩溃报告,如下所示。我相信崩溃是由于 SKProductRequest 的委托(delegate)发布得太早造成的,所以我不是在寻找崩溃发生原因的答案 - 这已经在 StackOverflow 的其他地方得到了回答。
我的问题是我无法复制错误。我试过很多设备和不同版本的 iOS。从 Crittercism 来看,崩溃主要发生在最新的设备上,包括一系列 iPhone、iPod 和 iPad——所以它不是一种特定类型的设备,但我仍然无法让它发生。我已经下载了精简版,并从那里购买了完整版 - 一切都完美无缺。
因此,我的问题是,有没有人知道如何在我的设备上实现它,以便我可以修复它?!
libobjc.A.dylib 0x37393f78 objc_msgSend + 15
StoreKit 0x37bc3a4f -[SKProductsRequest handleFinishResponse:returningError:] + 142
StoreKit 0x37bc4dc7 -[SKRequest _requestFinishedNotification:] + 210
Foundation 0x319624ff __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 + 18
CoreFoundation 0x31027547 ___CFXNotificationPost_block_invoke_0 + 70
CoreFoundation 0x30fb3097 _CFXNotificationPost + 1406
Foundation 0x318d63eb -[NSNotificationCenter postNotificationName:object:userInfo:] + 66
AppSupport 0x314eeba3 -[CPDistributedNotificationCenter deliverNotification:userInfo:] + 62
AppSupport 0x314f010b _CPDNDeliverNotification + 290
AppSupport 0x314ee99b _XDeliverNotification + 170
AppSupport 0x314e3b11 migHelperRecievePortCallout + 172
CoreFoundation 0x3102f523 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 38
CoreFoundation 0x3102f4c5 __CFRunLoopDoSource1 + 140
CoreFoundation 0x3102e313 __CFRunLoopRun + 1370
CoreFoundation 0x30fb14a5 CFRunLoopRunSpecific + 300
CoreFoundation 0x30fb136d CFRunLoopRunInMode + 104
GraphicsServices 0x3302b439 GSEventRunModal + 136
UIKit 0x30714cd5 UIApplicationMain + 1080
MyAppLite 0x000fc7c3 main (main.m:13)
罪魁祸首肯定就在这里的某个地方,但我仍然不能让它在我的设备上或模拟器中崩溃:
#import "InAppPurchaseViewController.h"
#define INDICATOR_Y 150.0f
#define INDICATOR_MOVE_Y 300.0f
#define PRODUCT_LABEL_Y 150.0f
#define PURCHASE_BUTTON_Y 190.0f
#define RESTORE_BUTTON_Y 240.0f
@interface InAppPurchaseViewController (Private)
- (void)updateUIToDefaultState;
@end
@implementation InAppPurchaseViewController
- (void) dealloc {
[productLabel release];
[purchaseButton release];
[indicatorView release];
[super dealloc];
}
#pragma mark -
#pragma mark UIViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"...";
self.view.backgroundColor = [UIColor blackColor];
self.tableView.backgroundColor = [UIColor blackColor];
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
self.tableView.scrollEnabled = NO;
self.tableView.indicatorStyle = UIScrollViewIndicatorStyleWhite;
UIImageView *headerImageView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"upgrade-header.png"]] autorelease];
UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.view.bounds.size.width, headerImageView.image.size.height + 200.0)] autorelease];
[headerView addSubview:headerImageView];
indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
indicatorView.hidesWhenStopped = YES;
[indicatorView startAnimating];
[headerView addSubview:indicatorView];
productLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 300.0f, 0.0f)];
productLabel.text = @"...";
productLabel.hidden = YES;
productLabel.font = [UIFont systemFontOfSize:18.0f];
productLabel.textColor = [UIColor whiteColor];
productLabel.backgroundColor = [UIColor blackColor];
[productLabel sizeToFit];
[headerView addSubview:productLabel];
purchaseButton = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
purchaseButton.titleLabel.font = [UIFont boldSystemFontOfSize:20.0f];
UIImage *bgImage = [UIImage imageNamed:@"btn_purchase.png"];
UIImage *buttonImage = [bgImage stretchableImageWithLeftCapWidth:(bgImage.size.width / 2.0f) - 1 topCapHeight:0.0f];
[purchaseButton setBackgroundImage:buttonImage forState:UIControlStateNormal];
[purchaseButton setTitle:@"Purchase" forState:UIControlStateNormal];
[purchaseButton addTarget:self action:@selector(purchaseClicked:) forControlEvents:UIControlEventTouchUpInside];
purchaseButton.frame = CGRectMake(0.0f, 0.0f, 300.0f, buttonImage.size.height);
purchaseButton.hidden = YES;
[self.view addSubview:purchaseButton];
restoreButton = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
restoreButton.enabled = NO;
restoreButton.titleLabel.font = [UIFont boldSystemFontOfSize:18.0f];
[restoreButton setBackgroundImage:buttonImage forState:UIControlStateNormal];
[restoreButton setTitle:@"Restore Purchases" forState:UIControlStateNormal];
[restoreButton addTarget:self action:@selector(restoreClicked:) forControlEvents:UIControlEventTouchUpInside];
restoreButton.frame = CGRectMake(0.0f, 0.0f, 300.0f, buttonImage.size.height);
[self.view addSubview:restoreButton];
headerImageView.center = headerView.center;
headerImageView.frame = CGRectMake(headerImageView.frame.origin.x, 0.0f, headerImageView.frame.size.width, headerImageView.frame.size.height);
indicatorView.center = headerView.center;
indicatorView.frame = CGRectMake(indicatorView.frame.origin.x, INDICATOR_Y, indicatorView.frame.size.width, indicatorView.frame.size.height);
productLabel.center = headerView.center;
productLabel.frame = CGRectMake(productLabel.frame.origin.x, PRODUCT_LABEL_Y, productLabel.frame.size.width, productLabel.frame.size.height);
purchaseButton.center = headerView.center;
purchaseButton.frame = CGRectMake(purchaseButton.frame.origin.x, PURCHASE_BUTTON_Y, purchaseButton.frame.size.width, purchaseButton.frame.size.height);
restoreButton.center = headerView.center;
restoreButton.frame = CGRectMake(restoreButton.frame.origin.x, RESTORE_BUTTON_Y, restoreButton.frame.size.width, restoreButton.frame.size.height);
self.tableView.tableHeaderView = headerView;
[self performSelectorInBackground:@selector(retrieveProductDetails:) withObject:nil];
}
#pragma mark -
#pragma mark AppStoreServiceDelegate
- (void)productDetailsRequestSucceededWithResponse:(SKProductsResponse *)response {
if (response.products.count == 1) {
[self performSelectorOnMainThread:@selector(productDetailsRetrieved:) withObject:[response.products objectAtIndex:0] waitUntilDone:NO];
} else {
NSString *message = @"Unable to retrieve product details: No valid product to purchase. Please contact support.";
[self performSelectorOnMainThread:@selector(appStoreRequestFailed:) withObject:message waitUntilDone:NO];
}
}
- (void)productDetailsRequestFailedWithError:(NSError *)error {
NSString *message = [NSString stringWithFormat:@"Unable to retrieve product details: %@", [error localizedDescription]];
[self performSelectorOnMainThread:@selector(appStoreRequestFailed:) withObject:message waitUntilDone:NO];
}
- (void)transactionSucceededForProductId:(NSString *)productId {
[self performSelectorOnMainThread:@selector(purchaseCompleted:) withObject:productId waitUntilDone:NO];
}
- (void)transactionFailedWithReason:(NSString *)reason {
NSString *message = [NSString stringWithFormat:@"Sorry, your purchase could not be completed: %@", reason];
[self performSelectorOnMainThread:@selector(appStoreRequestFailed:) withObject:message waitUntilDone:NO];
}
- (void)transactionCancelled {
[self performSelectorOnMainThread:@selector(updateUIToDefaultState) withObject:nil waitUntilDone:NO];
}
#pragma mark -
#pragma mark UIAlertViewDelegate (purchase failed)
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
[self.navigationController popViewControllerAnimated:YES];
}
#pragma mark -
#pragma mark Private button callbacks
- (void)purchaseClicked:(UIButton *)clicked {
clicked.enabled = NO;
[indicatorView startAnimating];
indicatorView.frame = CGRectMake(indicatorView.frame.origin.x, INDICATOR_MOVE_Y, indicatorView.frame.size.width, indicatorView.frame.size.height);
[self performSelectorInBackground:@selector(purchaseProduct:) withObject:nil];
}
- (void)restoreClicked:(UIButton *)clicked {
clicked.enabled = NO;
[indicatorView startAnimating];
indicatorView.frame = CGRectMake(indicatorView.frame.origin.x, INDICATOR_MOVE_Y, indicatorView.frame.size.width, indicatorView.frame.size.height);
[self performSelectorInBackground:@selector(restoreProducts:) withObject:nil];
}
#pragma mark -
#pragma mark Private
- (void)showPurchaseDetailsWithName:(NSString *)productName price:(NSString *)price {
self.title = productName;
productLabel.text = [NSString stringWithFormat:@"%@, %@", productName, price];
[productLabel sizeToFit];
productLabel.center = self.tableView.tableHeaderView.center;
[self updateUIToDefaultState];
}
- (void)productDetailsRetrieved:(SKProduct *)productDetails {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[indicatorView stopAnimating];
[self showPurchaseDetailsWithName:productDetails.localizedTitle price:[[AppStoreService sharedAppStoreService] formatPrice:productDetails]];
[pool drain];
}
- (void)purchaseCompleted:(NSString *)productId {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[indicatorView stopAnimating];
[[AppStoreService sharedAppStoreService] setPurchasedFullEdition:YES];
[self.navigationController popViewControllerAnimated:YES];
[pool drain];
}
- (void)purchaseProduct:(id)ignored {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[[AppStoreService sharedAppStoreService] purchaseProducts:[NSSet setWithObject:[[AppStoreService sharedAppStoreService] inAppProductIdentifierForEdition]] notifyingDelegate:self];
[pool drain];
}
- (void)restoreProducts:(id)ignored {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[[AppStoreService sharedAppStoreService] retoreCompletedTransactionsNotifyingDelegate:self];
[pool drain];
}
- (void)appStoreRequestFailed:(NSString *)reason {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[[[[UIAlertView alloc] initWithTitle:@"Purchase Error" message:reason delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil] autorelease] show];
[self updateUIToDefaultState];
[pool drain];
}
- (void)retrieveProductDetails:(id)ignored {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[[AppStoreService sharedAppStoreService] requestDetailsOfProducts:[NSSet setWithObject:[[AppStoreService sharedAppStoreService] inAppProductIdentifierForEdition]] notifyingDelegate:self];
[pool drain];
}
- (void)updateUIToDefaultState {
[indicatorView stopAnimating];
productLabel.hidden = NO;
purchaseButton.hidden = NO;
restoreButton.enabled = YES;
purchaseButton.enabled = YES;
}
@end
这是 AppStoreService.m
// AppStoreService.m
#import "AppStoreService.h"
#import "SynthesizeSingleton.h"
#import "DataService.h"
#import "ConfigService.h"
#pragma mark -
#pragma mark Private internal app store delegates
@implementation AppStoreProductRequestDelegate
@synthesize delegate = _delegate;
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
//NSLog(@"Got response... %@", response);
[request release];
if (self.delegate) {
[self.delegate productDetailsRequestSucceededWithResponse:response];
}
}
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
//NSLog(@"Got error... %@", error);
[request release];
if (self.delegate) {
[self.delegate productDetailsRequestFailedWithError:error];
}
}
@end
@implementation AppStoreTransactionObserver
@synthesize delegate = _delegate;
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased: { [self completeTransaction:transaction]; break; }
case SKPaymentTransactionStateFailed: { [self failedTransaction:transaction]; break; }
case SKPaymentTransactionStateRestored: {[self restoreTransaction:transaction]; break; }
default: break;
}
}
}
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error {
if (self.delegate) {
[self.delegate transactionFailedWithReason:[NSString stringWithFormat:@"Purchase failed: %@", [error localizedDescription]]];
}
}
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue {
//NSLog(@"paymentQueueRestoreCompletedTransactionsFinished:");
}
- (void)failedTransaction:(SKPaymentTransaction *)transaction {
//NSLog(@"failedTransaction: %@", transaction);
if (self.delegate) {
if (transaction.error.code == SKErrorPaymentCancelled) {
[self.delegate transactionCancelled];
} else {
[self.delegate transactionFailedWithReason:[NSString stringWithFormat:@"Purchase failed: %@", [transaction.error localizedDescription]]];
}
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
//NSLog(@"restoreTransaction: %@", transaction);
if (self.delegate) {
[self.delegate transactionSucceededForProductId:transaction.originalTransaction.payment.productIdentifier];
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (void)completeTransaction:(SKPaymentTransaction *)transaction {
//NSLog(@"completeTransaction: %@", transaction);
if (self.delegate) {
[self.delegate transactionSucceededForProductId:transaction.payment.productIdentifier];
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
@end
#pragma mark -
#pragma mark AppStoreService
@implementation AppStoreService
SYNTHESIZE_SINGLETON_FOR_CLASS(AppStoreService);
static NSString *kLPHasPurchasedFullEdition = @"kLPHasPurchasedFullEdition";
- (AppStoreService *)init {
if (self = [super init]) {
productDetailsDelegate = [[AppStoreProductRequestDelegate alloc] init];
appStoreObserver = [[AppStoreTransactionObserver alloc] init];
[[SKPaymentQueue defaultQueue] addTransactionObserver:appStoreObserver];
}
return self;
}
- (void) dealloc {
[[SKPaymentQueue defaultQueue] removeTransactionObserver:appStoreObserver];
[productDetailsDelegate release];
[appStoreObserver release];
[super dealloc];
}
- (BOOL)hasPurchasedFullEdition {
return [[NSUserDefaults standardUserDefaults] boolForKey:kLPHasPurchasedFullEdition];
}
- (void)setPurchasedFullEdition:(BOOL)purchased {
//NSLog(@"Purchased? %d", purchased);
[[NSUserDefaults standardUserDefaults] setBool:purchased forKey:kLPHasPurchasedFullEdition];
[[ConfigService sharedConfigService] synchronizeConfig];
}
- (NSString *)inAppProductIdentifierForEdition {
if ([[DataService sharedDataService] isLiteEdition]) {
if ([DataService sharedDataService].isLanguageEdition) {
// Note. Remove the "-" from language codes, e.g. Brazillian Portugese pt-br, as in-app purchase IDs cannot contain a hyphen.
NSString *fixedCode = [[DataService sharedDataService].languageCode stringByReplacingOccurrencesOfString:@"-" withString:@""];
return [NSString stringWithFormat:@"com.myBrokenApp.%@.AllCategories", fixedCode];
} else {
return @"com.myBrokenApp.AllCategories";
}
} else {
@throw [NSException exceptionWithName:@"InvalidOperation" reason:@"An in app purchase product ID was requested for a non-lite version" userInfo:[NSDictionary dictionary]];
}
}
- (NSString *)purchasedCategoryIdsWhereClause {
// flirting & essentials for lite builds
return ([DataService sharedDataService].isLiteEdition && ![self hasPurchasedFullEdition]) ? @"and c.category_id in (1,19)" : @" ";
}
- (NSString *)formatPrice:(SKProduct *)product {
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[numberFormatter setLocale:product.priceLocale];
NSString *currency = [numberFormatter stringFromNumber:product.price];
[numberFormatter release];
return currency;
}
- (void)requestDetailsOfProducts:(NSSet *)products notifyingDelegate:(id<AppStoreServiceDelegate>)delegate {
//NSLog(@"Retrieving details of products: %@", products);
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:products];
productDetailsDelegate.delegate = delegate;
request.delegate = productDetailsDelegate;
//NSLog(@"Starting request...");
[request start];
}
- (void)purchaseProducts:(NSSet *)products notifyingDelegate:(id<AppStoreServiceDelegate>)delegate {
//NSLog(@"Making in app purchase for products: %@", products);
if ([SKPaymentQueue canMakePayments]) {
appStoreObserver.delegate = delegate;
for (NSString *productId in products) {
[[SKPaymentQueue defaultQueue] addPayment:[SKPayment paymentWithProductIdentifier:productId]];
}
} else {
[delegate transactionFailedWithReason:@"You are not permitted to make purchases."];
}
}
- (void)retoreCompletedTransactionsNotifyingDelegate:(id<AppStoreServiceDelegate>)delegate {
//NSLog(@"Restoring in-app purchases...");
if ([SKPaymentQueue canMakePayments]) {
appStoreObserver.delegate = delegate;
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
} else {
[delegate transactionFailedWithReason:@"You are not permitted to make purchases."];
}
}
@end
最佳答案
Whisk,您在这里发布了一些非常有问题的代码。一方面,您使用 SYNTHESIZE_SINGLETON_FOR_CLASS() ,这意味着您的 AppStoreService dealloc 方法将永远不会被调用,因此您的应用程序中存在内存泄漏。此外,productsRequest 中对 [request release] 的调用看起来确实很奇怪。但是,您在使用 SKProductsRequest 时遇到的具体问题似乎与一个委托(delegate)有关,该委托(delegate)指向在 SKProductsRequest 调用回调之前释放的对象之一。这表明当作为委托(delegate)的对象调用其 dealloc 方法时,您需要将委托(delegate)设置为 nil。至于如何重现该问题,这听起来非常棘手,因为您在代码中设置了非常奇怪的对象生命周期。我建议您使用自动回归测试工具,但我不确定它是否可以检查应用程序中的对象生命周期,因为您使用的是单例。参见 What is so bad about singletons?
关于ios - 来自 StoreKit 的 SIGSEGV 崩溃 - 无法复制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12127721/
我通过 spring ioc 编写了一些 Rest 应用程序。但我无法解决这个问题。这是我的异常(exception): org.springframework.beans.factory.BeanC
我对 TestNG、Spring 框架等完全陌生,我正在尝试使用注释 @Value通过 @Configuration 访问配置文件注释。 我在这里想要实现的目标是让控制台从配置文件中写出“hi”,通过
为此工作了几个小时。我完全被难住了。 这是 CS113 的实验室。 如果用户在程序(二进制计算器)结束时选择继续,我们需要使用 goto 语句来到达程序的顶部。 但是,我们还需要释放所有分配的内存。
我正在尝试使用 ffmpeg 库构建一个小的 C 程序。但是我什至无法使用 avformat_open_input() 打开音频文件设置检查错误代码的函数后,我得到以下输出: Error code:
使用 Spring Initializer 创建一个简单的 Spring boot。我只在可用选项下选择 DevTools。 创建项目后,无需对其进行任何更改,即可正常运行程序。 现在,当我尝试在项目
所以我只是在 Mac OS X 中通过 brew 安装了 qt。但是它无法链接它。当我尝试运行 brew link qt 或 brew link --overwrite qt 我得到以下信息: ton
我在提交和 pull 时遇到了问题:在提交的 IDE 中,我看到: warning not all local changes may be shown due to an error: unable
我跑 man gcc | grep "-L" 我明白了 Usage: grep [OPTION]... PATTERN [FILE]... Try `grep --help' for more inf
我有一段代码,旨在接收任何 URL 并将其从网络上撕下来。到目前为止,它运行良好,直到有人给了它这个 URL: http://www.aspensurgical.com/static/images/a
在过去的 5 个小时里,我一直在尝试在我的服务器上设置 WireGuard,但在完成所有设置后,我无法 ping IP 或解析域。 下面是服务器配置 [Interface] Address = 10.
我正在尝试在 GitLab 中 fork 我的一个私有(private)项目,但是当我按下 fork 按钮时,我会收到以下信息: No available namespaces to fork the
我这里遇到了一些问题。我是 node.js 和 Rest API 的新手,但我正在尝试自学。我制作了 REST API,使用 MongoDB 与我的数据库进行通信,我使用 Postman 来测试我的路
下面的代码在控制台中给出以下消息: Uncaught DOMException: Failed to execute 'appendChild' on 'Node': The new child el
我正在尝试调用一个新端点来显示数据,我意识到在上一组有效的数据中,它在数据周围用一对额外的“[]”括号进行控制台,我认为这就是问题是,而新端点不会以我使用数据的方式产生它! 这是 NgFor 失败的原
我正在尝试将我的 Symfony2 应用程序部署到我的 Azure Web 应用程序,但遇到了一些麻烦。 推送到远程时,我在终端中收到以下消息 remote: Updating branch 'mas
Minikube已启动并正在运行,没有任何错误,但是我无法 curl IP。我在这里遵循:https://docs.traefik.io/user-guide/kubernetes/,似乎没有提到关闭
每当我尝试docker组成任何项目时,都会出现以下错误。 我尝试过有和没有sudo 我在这台机器上只有这个问题。我可以在Mac和Amazon WorkSpace上运行相同的容器。 (myslabs)
我正在尝试 pip install stanza 并收到此消息: ERROR: No matching distribution found for torch>=1.3.0 (from stanza
DNS 解析看起来不错,但我无法 ping 我的服务。可能是什么原因? 来自集群中的另一个 Pod: $ ping backend PING backend.default.svc.cluster.l
我正在使用Hibernate 4 + Spring MVC 4当我开始 Apache Tomcat Server 8我收到此错误: Error creating bean with name 'wel
我是一名优秀的程序员,十分优秀!