方法 BOOL 从内部块返回

Posted

技术标签:

【中文标题】方法 BOOL 从内部块返回【英文标题】:Method BOOL return from inside block 【发布时间】:2012-07-24 14:14:14 【问题描述】:

我正在尝试将 Beeblex 的新应用内购买验证添加到我的应用中,但是我正在努力从块内传递返回值。

这是我现在拥有的代码,如您所见,我设置了一个 BOOL 值,然后在验证块中设置了 BOOL 并在最后返回它。但是最后的 return 是在块完成之前调用的,所以我需要从块内返回 BOOL?

- (BOOL)verifyTransaction:(SKPaymentTransaction *)transaction

    if (![BBXIAPTransaction canValidateTransactions]) 
        return YES; // There is no connectivity to reach the server
    

    BOOL __block toReturn = YES;
    BBXIAPTransaction *bbxTransaction = [[BBXIAPTransaction alloc] initWithTransaction:transaction];
    bbxTransaction.useSandbox = YES;
    [bbxTransaction validateWithCompletionBlock:^(NSError *error) 
        if (bbxTransaction.transactionVerified) 
            if (bbxTransaction.transactionIsDuplicate) 
                // The transaction is valid, but duplicate - it has already been sent to Beeblex in the past.
                NSLog(@"Transaction is a duplicate!");
                [FlurryAnalytics logEvent:@"Transaction duplicate!"];
                toReturn = NO;
             else 
                // The transaction has been successfully validated and is unique
                NSLog(@"Transaction valid data:%@",bbxTransaction.validatedTransactionData);
                [FlurryAnalytics logEvent:@"Transaction verified"];
                toReturn = YES;
            
         else 
            // Check whether this is a validation error, or if something went wrong with Beeblex
            if (bbxTransaction.hasConfigurationError || bbxTransaction.hasServerError || bbxTransaction.hasClientError) 
                // The error was not caused by a problem with the data, but is most likely due to some transient networking issues
                NSLog(@"Transaction error caused by network, not data");
                [FlurryAnalytics logEvent:@"Transaction network error"];
                toReturn = YES;
             else 
                // The transaction supplied to the validation service was not valid according to Apple
                NSLog(@"Transaction not valid according to Apple");
                [FlurryAnalytics logEvent:@"Transaction invalid!!"];
                toReturn = NO;
            
        
    ];

    NSLog(@"toReturn: %@",toReturn ? @"Yes" : @"No");
    return toReturn;

如果我只是将return = NO; 放在块内,我会收到不兼容块指针类型的编译器警告,并且控制可能会到达非空块的末尾。

【问题讨论】:

这是一个奇怪的事情,因为块与方法不同步,因此无论你想为块内的toReturn变量设置什么值,方法都不会处理它,当线程池运行return toReturn; 行时,它会发回当前的toReturn 值。 您正在尝试将异步 API 转换为同步 API,这是错误的做法。而不是返回BOOL,您的代码应该采用完成块或它自己的委托,在事务完成时回调调用者。使 API 同步会降低您的应用程序的响应速度。 是的,我想这是有道理的,我正在尝试将异步变为同步,这并不好。在这种情况下,我可以在块内使用 [self successMethod] 和 [self failMethod] 来调用单独的方法。谢谢 【参考方案1】:

Beeblex 开发人员在这里。 -validateWithCompletionBlock 中的代码:异步执行(在后台,它需要与我们的服务器通信,因此在我们等待互联网执行它的操作时完全阻止您的应用程序是没有意义的)。

因此,您需要重新考虑验证收据的方法。现在你,一般的工作流程是:

    完成购买 致电 Beeblex 等待回复 检查布尔值

但是 #3 会立即返回,所以这永远不会奏效。你应该考虑做这样的事情:

    完成购买 显示“请稍候...”视图或类似内容,以告知用户您正在解锁他们购买的任何商品。 致电 Beeblex 在块内,确定验证是否成功,然后然后从那里解锁内容。 闲置直到被块调用

这是一个简单粗暴的例子。我没有编译它,所以它可能有一些错误,但它应该让您了解预期使用模式背后的想法。

- (void) showWaitView 
    // Display a wait view



- (void) hideWaitView 
    // Hide the wait view



- (void) completeValidationWithValidateReceiptData:(NSDictionary *) receipt isRecoverableError(BOOL) isRecoverableError 
    [self hideWaitView];

    if (receipt) 
        // Unlock the content, tell the user
     else 
        if (isRecoverableError) 
            // Probably a network error of some kind. Tell user they need to be connected,
            // and ask them to do it again.
         else 
            // Keep the content locked, tell the user something went wrong
        
    


- (void) validateReceipt:(SKPaymentTransaction *) transaction 
    if (![BBXIAPTransaction canValidateTransactions]) 
        [self completeValidationWithValidateReceiptData:Nil isRecoverableError:YES];
        return;
    

    BBXIAPTransaction *bbxTransaction = [[BBXIAPTransaction alloc] initWithTransaction:transaction];
    bbxTransaction.useSandbox = YES;

    [bbxTransaction validateWithCompletionBlock:^(NSError *error) 
        if (bbxTransaction.transactionVerified) 
            if (bbxTransaction.transactionIsDuplicate) 
                // The transaction is valid, but duplicate - it has already been sent to Beeblex in the past.
                [FlurryAnalytics logEvent:@"Transaction duplicate!"];
                [self completeValidationWithValidateReceiptData:Nil isRecoverableError:NO];
             else 
                // The transaction has been successfully validated and is unique
                [FlurryAnalytics logEvent:@"Transaction verified"];
                [self completeValidationWithValidateReceiptData:bbxTransaction.validatedTransactionData isRecoverableError:NO];
            
         else 
            // Check whether this is a validation error, or if something went wrong with Beeblex
            if (bbxTransaction.hasConfigurationError || bbxTransaction.hasServerError || bbxTransaction.hasClientError) 
                // The error was not caused by a problem with the data, but is most likely due to some transient networking issues
                [FlurryAnalytics logEvent:@"Transaction network error"];
                [self completeValidationWithValidateReceiptData:Nil isRecoverableError:YES];
             else 
                // The transaction supplied to the validation service was not valid according to Apple
                [FlurryAnalytics logEvent:@"Transaction invalid!!"];
                [self completeValidationWithValidateReceiptData:Nil isRecoverableError:NO];
            
        
    ];

【讨论】:

谢谢,我做了很多。无论如何,我在购买期间有一个 HUD,现在等待 Beeblex 响应,然后再继续。感谢这项优质的服务。当你在这里的时候,我在打电话给 Beeblex 核实之前购买是对的吗?因此,如果它是消耗品,如果 Beeblex 不可用,您不能要求用户再试一次,因为它会向他们收费两次? 正确。这种情况下的模式应该是应用一些启发式方法并找出失败的可能原因是什么。导致暂时错误的交易只能重新发送到 Beeblex,而不是 App Store。但是,有人可能会阻止我们的服务器以阻止您访问它们,因此您需要注意这一点(这也是我们建议您先调用 +canValidateTransactions 的部分原因)。【参考方案2】:

- (void)verifyTransaction:(SKPaymentTransaction *)transaction completionHandler:(void (^)(BOOL flag))completionHandler

    if (![BBXIAPTransaction canValidateTransactions]) 
        completionHandler(YES); // There is no connectivity to reach the server
    

    BBXIAPTransaction *bbxTransaction = [[BBXIAPTransaction alloc] initWithTransaction:transaction];
    bbxTransaction.useSandbox = YES;
    [bbxTransaction validateWithCompletionBlock:^(NSError *error) 
        if (bbxTransaction.transactionVerified) 
            if (bbxTransaction.transactionIsDuplicate) 
                // The transaction is valid, but duplicate - it has already been sent to Beeblex in the past.
                NSLog(@"Transaction is a duplicate!");
                [FlurryAnalytics logEvent:@"Transaction duplicate!"];
                completionHandler(NO);
             else 
                // The transaction has been successfully validated and is unique
                NSLog(@"Transaction valid data:%@",bbxTransaction.validatedTransactionData);
                [FlurryAnalytics logEvent:@"Transaction verified"];
                completionHandler(YES);
            
         else 
            // Check whether this is a validation error, or if something went wrong with Beeblex
            if (bbxTransaction.hasConfigurationError || bbxTransaction.hasServerError || bbxTransaction.hasClientError) 
                // The error was not caused by a problem with the data, but is most likely due to some transient networking issues
                NSLog(@"Transaction error caused by network, not data");
                [FlurryAnalytics logEvent:@"Transaction network error"];
                completionHandler(YES);
             else 
                // The transaction supplied to the validation service was not valid according to Apple
                NSLog(@"Transaction not valid according to Apple");
                [FlurryAnalytics logEvent:@"Transaction invalid!!"];
                completionHandler(NO);
            
        
    ];

然后使用

[instance verifyTransaction:transaction completionHandler:^(BOOL flag) 
    if (flag) 
        // YOUR CODE HERE
    
];

而不是

if ([instance verifyTransaction:transaction]) 
    // YOUR CODE HERE

【讨论】:

以上是关于方法 BOOL 从内部块返回的主要内容,如果未能解决你的问题,请参考以下文章

使用 != 了解返回 BOOL 的方法

从 Objective-C 中的 ColdFusion 布尔返回类型获取 BOOL 的更好方法?

从可枚举块内部返回 erb

从 Bool 数组返回索引值数组,其中 true

FileStream 常用的属性和方法

FileStream常用的属性和方法: