我正在尝试在阻塞调用中发送实例并等待其完成,因此稍后我可以在程序中使用该值,但完成功能永远不会完成。我对Objective-C极为陌生,我只使用Objective-c作为包装器,所以我不知道为什么我的完成调用永远不会结束。
[sharedClient createTokenWithCard:cardParams completion:^(STPToken *token,NSError *error) {
if (token == nil || error != nil) {
tokenChar = [error.localizedDescription UTF8String];
}
else{
tokenChar = [token.tokenId UTF8String];
}
}];
while(tokenChar == nil){
}
return tokenChar;
所以现在我将方法更改为此
void StripeWrapper::retrieveToken:(id)(char* myKey, char* cardNumber, int expMonth, int expYear, char* cvc) completion:(void (^)(NSString *))completion {
NSString* NScardNumber = [NSString stringWithUTF8String:cardNumber];
NSString* NScvc = [NSString stringWithUTF8String:cvc];
STPCardParams *cardParams = [[STPCardParams alloc] init];
cardParams.number = NScardNumber;
cardParams.expMonth = expMonth;
cardParams.expYear = expYear;
cardParams.cvc = NScvc;
NSString *myPublishableKey = [NSString stringWithUTF8String:myKey];
STPAPIClient *sharedClient = [[STPAPIClient alloc] initWithPublishableKey:myPublishableKey];
[sharedClient createTokenWithCard:cardParams completion:^(STPToken *token,NSError *error) {
NSString *tokenChar;
if (token == nil || error != nil) {
tokenChar = [error.localizedDescription UTF8String];
} else {
tokenChar = [token.tokenId UTF8String];
}
if (completion) completion(tokenChar);
}];
}
答案 0 :(得分:0)
自从我处理了Objective-c以来已经有一段时间了,所以请谅解我在语法上的错误。
// This just uses completion block and will call the completion once the createTokenWithCard function finishes its execution
- (void) someFunctionName: (void (^)(NSString * theThingIWant, NSError *error)) completion {
[sharedClient createTokenWithCard:cardParams completion:^(STPToken *token,NSError *error) {
if (token == nil || error != nil) {
tokenChar = [error.localizedDescription UTF8String];
} else{
tokenChar = [token.tokenId UTF8String];
}
completion(tokenChar, error)
}];
}
// And in your caller its like
[self someFunctionName:^(NSString *some, NSError *error) {
// do the thing you want here
}];
// Second approach will be dispatches. This will wait for createTokenWithCard before it returns
- (void) someFunctionName: (id) cardParams {
__block NSString * theThingYouNeed;
dispatch_group_t someGroupName = dispatch_group_create();
[sharedClient createTokenWithCard:cardParams completion:^(STPToken *token,NSError *error) {
if (token == nil || error != nil) {
theThingYouNeed = [error.localizedDescription UTF8String];
} else{
theThingYouNeed = [token.tokenId UTF8String];
}
dispatch_group_leave(someGroupName);
}];
// this will wait forever so try to have a timeout I guess.
dispatch_group_wait(someGroupName,DISPATCH_TIME_FOREVER);
return theThingYouNeed
}
答案 1 :(得分:0)
异步方法有一种激增的方式,通常也迫使其调用者异步。换句话说,如果methodA的结果取决于methodB,并且methodB是异步的,那么methodA也必须是异步的。
因此包含OP代码的方法可能应该这样声明:
- (void)getMyTokenChar:(id)someParams completion:(void (^)(NSString *))completion {
// form cardParams with someParams (or maybe they are the same
[sharedClient createTokenWithCard:cardParams completion:^(STPToken *token,NSError *error) {
NSString *tokenChar;
if (token == nil || error != nil) {
tokenChar = [error.localizedDescription UTF8String];
} else {
tokenChar = [token.tokenId UTF8String];
}
if (completion) completion(tokenChar);
}];
}
呼叫者会这样做...
[theTokenCharObject getMyTokenChar:@"someParams" completion:^(NSString *tokenChar) {
// tokenChar will be a string or an error description here
}];
这是个坏消息,包含调用代码的方法可能也需要异步。它永远不会结束吗?
是的,它通常在用户界面上结束...
// do something to the UI to say the app is busy, like an activity indicator view
[theTokenCharObject getMyTokenChar:@"someParams" completion:^(NSString *tokenChar) {
// remove the activity indicator view
// show something new to the user: "we got the thing that depends on tokenChar!!"
}];
有两种选择,最简单的描述是使用NSNotificationCenter。您原始的方法将变得(似乎)同步...
- (void)getMyTokenChar:(id)someParams {
// form cardParams with someParams (or maybe they are the same
[sharedClient createTokenWithCard:cardParams completion:^(STPToken *token,NSError *error) {
NSString *tokenChar;
if (token == nil || error != nil) {
tokenChar = [error.localizedDescription UTF8String];
} else {
tokenChar = [token.tokenId UTF8String];
}
[[NSNotificationCenter defaultCenter] postNotificationName:@"TokenGetterDidGetToken" object:tokenChar];
}];
}
您应用的其他任何部分都这样订阅...
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didGetToken:) name:@"TokenGetterDidGetToken" object:nil];
并且必须实现选择器...
- (void)didGetToken:(NSNotification *)notification {
// notification.object will be the tokenChar
}
不过,通常情况下,最好不要传递块。以我给的UI示例为例。代码的一部分将UI更改为繁忙,另一部分未连接的部分将更改为UI。