Bad Access Parent is Null - 这是怎么回事?

时间:2014-08-23 17:33:48

标签: objective-c xcode ios7

我理解错误是什么,但在这种情况下不是导致它的原因。在一般情况下,它可能发生在1%的时间(可能更少),但我发现了一种极端的方式来引起它,我将在下面描述。首先,我使用的是Ray Wenderlich网站上的应用内购买流程。以下是具体的问题:

·H:

typedef void (^RequestProductsCompletionHandler)(BOOL success, NSArray * products);
@interface IAPHelper : NSObject

- (void)requestProductsWithCompletionHandler:RequestProductsCompletionHandler)completionHandler;

@end

的.m

@implementation IAPHelper
{
    SKProductsRequest * _productsRequest;
    RequestProductsCompletionHandler _completionHandler;
}

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {

    NSLog(@"Loaded list of products...");
    _productsRequest = nil;

    NSArray * skProducts = response.products;
    for (SKProduct * skProduct in skProducts) {
        NSLog(@"Found product: %@ %@ %0.2f",
              skProduct.productIdentifier,
              skProduct.localizedTitle,
              skProduct.price.floatValue);
    }

    _completionHandler(YES, skProducts); // here is where bad access occurs 
    _completionHandler = nil;
}

再次,99%以上的时间这个工作正常。鉴于常规使用中不良访问的频率很低,并且难以诊断。但是,我找到了导致这个问题的极端方法。设置为“Tab 1”是表视图控制器,“Tab 2”是使用上面代码的表视图控制器。如果我在两个标签之间快速来回切换,我通常会导致问题发生在从几秒到20-30秒的任何地方。在这种情况下,每次都不会发生但绝大多数情况都会发生。如上所示,以下行获取了错误的访问错误,其中Parent为Null。

  

_completionHandler(YES,skProducts);

要解决此问题,我可以执行以下操作:

if (_completionHandler)
{
    _completionHandler(YES, skProducts);
    _completionHandler = nil;
}

虽然该修复工作确实有效并且确实解决了问题,但我仍然为此感到困扰。有关于这个原因的任何想法吗?

更新

向所有人道歉,因为我忘记在上面粘贴的内容中包含以下内容。

- (void)requestProductsWithCompletionHandler:(RequestProductsCompletionHandler)completionHandler {


    // 1
    _completionHandler = [completionHandler copy];

    // 2
    _productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:_productIdentifiers];
    _productsRequest.delegate = self;
    [_productsRequest start];

}

2 个答案:

答案 0 :(得分:0)

存储时,您需要将完成块视为任何其他对象。因此,如果要将块存储为变量,然后在与分配块的范围不同的范围内使用它,则需要通过复制或保留它来增加引用计数。简单的解决方案是创建一个strong属性来存储块。

答案 1 :(得分:0)

根据看不见的代码位,可能无法正确分配完成处理程序块。如果您打算在创建它的范围之外使用它,则需要复制块。

在您的界面中,将完成处理程序的存储属性声明为“copy”。

@property (nonatomic, readwrite, copy) void (^completionHandler)(BOOL, NSArray *);

如果要控制局部变量,可以在实现中手动合成属性:

@synthesize completionHandler = _completionHandler;