xcode 方法 BOOL 从块内部返回

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11632780/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 01:00:41  来源:igfitidea点击:

Method BOOL return from inside block

objective-ciosxcodecocoa-touchobjective-c-blocks

提问by Darren

I'm trying to add Beeblex's new In App Purchase verification to my app, however i'm struggling passing a return value from within a block.

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

Here's the code I have now, and as you can see I set a BOOL value, then within the verification block I set the BOOL and return it at the end. However the return at the end is called before the block finishes, so what I need is to return the BOOL from within the block?

这是我现在拥有的代码,正如您所看到的,我设置了一个 BOOL 值,然后在验证块中设置了 BOOL 并在最后返回它。但是在块完成之前调用最后的返回,所以我需要从块内返回 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;
}

If I simply put return = NO;inside the block, I get compiler warnings of Incompatible block pointer types, and control may reach end of non-void block.

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

回答by Count Chocula

Beeblex developer here. The code inside -validateWithCompletionBlock: execute asynchronously (in the background, it needs to talk to our servers, so there's no point blocking your app completely while we wait for the Internet to do its thing).

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

Therefore, you need to rethink your approach to validating your receipts. Right now you, general workflow is:

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

  1. Complete purchase
  2. Call Beeblex
  3. Wait for response
  4. Check boolean value
  1. 完成购买
  2. 呼叫 Beeblex
  3. 等待回应
  4. 检查布尔值

But #3 returns right away, so this will never work. You should consider doing something like this:

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

  1. Complete purchase
  2. Show a “Please wait…” view, or something similar that advises the user that you're unlocking whatever they've purchased.
  3. Call Beeblex
  4. Inside the block, determine whether the validation succeeded or not, and thenact to unlock the content from there.
  5. Sit idle until called by the block
  1. 完成购买
  2. 显示“请稍候……”视图,或类似的东西,告知用户您正在解锁他们购买的任何东西。
  3. 呼叫 Beeblex
  4. 在块内部,确定验证是否成功,然后从那里解锁内容。
  5. 闲置直到被块调用

Here's a quick-and-dirty example. I didn't compile it, so it probably has a few bugs, but it should give you the idea behind the intended usage pattern.

这是一个快速而肮脏的例子。我没有编译它,所以它可能有一些错误,但它应该为您提供预期使用模式背后的想法。

- (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];
            }
        }
    }];
}

回答by user500

<3 blocks

<3块

- (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);
            }
        }
    }];
}

Then use

然后使用

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

instead of

代替

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