我一直在用kivy / python制作应用程序,我需要用obj-c调用一些ios框架。因此,我使用python-> cython-> c-> obj-c-> framework进行了几层包装。到目前为止,我已经完成所有工作,直到回调功能一直返回到python。现在,回叫在cython-> C-> obj-c层之间的某个地方失败(从来没有在cython中命中我的打印)。我感觉像是因为我试图将user_func作为C函数而不是像obj-c函数来调用。我应该如何在obj-c内部运行C回调函数?我已经在代码中添加了打印内容(无法逐步完成我的设置方式),它会打印生成的令牌,然后立即在user_func上崩溃。它也永远不会到达我的cython文件中的回调函数。因此,两者之间的某个地方是崩溃的根源。
- (void) retrieveTokenObjC:(char*)myKey andcardNumber:(char*)cardNumber andexpMonth:(int)expMonth andexpYear:(int)expYear andcvc:(char*)cvc anduser_func:(tokenfunc)user_func anduser_data:(void*)user_data {
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 *apiClient = [[STPAPIClient alloc] initWithPublishableKey:myPublishableKey];
[apiClient createTokenWithCard:cardParams completion:^(STPToken *token,NSError *error) {
if (token == nil || error != nil) {
const char* errorChar = [error.localizedDescription UTF8String];
user_func(errorChar,user_data);
} else {
const char* tokenChar = [token.tokenId UTF8String];
user_func(tokenChar,user_data);
}
}];
}
之后,它进入obj-c标头
#import <Foundation/Foundation.h>
typedef void (*tokenfunc) (const char *name, void *user_data);
@interface retToken : NSObject
- (void) retrieveTokenObjC:(char*)myKey andcardNumber:(char*)cardNumber andexpMonth:(int)expMonth andexpYear:(int)expYear andcvc:(char*)cvc anduser_func:(tokenfunc)user_func anduser_data:(void*)user_data;
@end
然后将其放入cython的C包装器中。
#include "stripe_ios_c.h"
#include "stripe_ios_imp.h"
void retrieveToken(char* myKey, char* cardNumber, int expMonth, int expYear, char* cvc,tokenfunc user_func, void *user_data){
retToken* retrieveToken = [[retToken alloc] init];
[retrieveToken retrieveTokenObjC:myKey andcardNumber:cardNumber andexpMonth:expMonth andexpYear:expYear andcvc:cvc anduser_func:user_func anduser_data:user_data];
}
然后是c包装的头文件
typedef void (*tokenfunc)(const char *name, void *user_data);
void retrieveToken(char* myKey, char* cardNumber, int expMonth, int expYear, char* cvc,tokenfunc user_func, void *user_data);
最后是cython代码
__all__ = ['StripeWrapper']
cdef extern from "stripe_ios_c.h":
ctypedef void (*tokenfunc)(const char *name, void *user_data)
void retrieveToken(char* myKey, char* cardNumber, int expMonth, int expYear, char* cvc,tokenfunc user_func, void *user_data)
class StripeWrapper():
def __init__(self,**kwargs):
foo = 'bar'
pass
def getToken(self,tokenCallback,myKey,cardNumber,expMonth,expYear,cvc):
cdef bytes myKey_bytes = myKey.encode('utf-8')
cdef char* myKey_string = myKey_bytes
cdef bytes cardNumber_bytes = cardNumber.encode('utf-8')
cdef char* cardNumber_string = cardNumber_bytes
cdef bytes cvc_bytes = cvc.encode('utf-8')
cdef char* cvc_string = cvc_bytes
print myKey_bytes
print cardNumber_bytes
print cvc_bytes
print myKey_string
print cardNumber_string
print cvc_string
retrieveToken(myKey_bytes, cardNumber_bytes, expMonth, expYear, cvc_bytes, callback, <void*>tokenCallback)
print 'Debug 1'
cdef void callback(const char *name, void *tokenCallback):
print 'callback debug'
(<object>tokenCallback)(name.decode('utf-8'))
更新:我已经跟踪了问题,我的回调函数执行了该问题,因为python回调在此途中被释放了。
最佳答案
我解决了这个问题。如果您离开主文件/当前文件,则此处的https://github.com/cython/cython/blob/master/Demos/callback/run_cheese.py cython回调示例将不起作用。这是因为在您离开该文件的那一刻,内存已被释放。推送python对象并使用后
cdef void callback(const char *name, void *tokenCallback):
(<object> tokenCallback).token = (name.decode('utf-8'))
我觉得cython是example是一个不好的例子,应该使用一个对象来发送回调,这样可以避免很多挫败感,但最终成功!
关于objective-c - 在Objective-C完成块中运行C回调函数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51097133/