я новичок в Objective-C, пожалуйста, потерпите меня, если я буду задавать глупые вопросы :) Ниже приведена часть кода, который я должен запустить туннелем vpn, но продолжает получать ошибку EXC_BAD_ACCESS.
- (void)startTunnelWithOptions:(NSDictionary *)options completionHandler:(void (^)(BOOL * error))completionHandler {
vpnAdapter = [[OpenAdapter alloc] init];
vpnAdapter.delegate = self;
// get config
config = [[NSDictionary alloc] init];
NETunnelProviderProtocol *protocol = (NETunnelProviderProtocol *)self.protocolConfiguration;
config = protocol.providerConfiguration;
host = config[@"server"];
// Load config data
username = config[@"username"];
password = config[@"password"];
if (option != nil){
[vpnAdapter connect:host user:username pass:password add:YES completionHandler:^(BOOL success){
// return success;
completionHandler(&success); // Thread 2: EXC_BAD_ACCESS (code=1, address=0xbcc68f020)
}];
}else{
[vpnAdapter connect:host user:username pass:password add:NO completionHandler:^(BOOL success){
completionHandler(&success);
}];
}
}
вот способ подключения
- (void)connect: (NSString *) host user:(NSString *)username pass:(NSString *) password add:(Boolean) isAdd completionHandler:(void (^)(BOOL success)) completionHandler{
dispatch_queue_attr_t attributes = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, 0);
dispatch_queue_t connectQueue = dispatch_queue_create("me.ss-abramchuk.open-adapter.connection", attributes);
dispatch_async(connectQueue, ^{
// Call connect
//int ret=1;
NSArray* options = [NSArray arrayWithObjects:
@"--user", username,
host,
nil];
if (isAdd){
options = [NSArray arrayWithObjects:
@"--user", username,
@"--protocol", @"ad",
host,
nil];
}
//NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDocumentDirectory, NSUserDomainMask, YES);
//NSString *documentsDirectory = [paths objectAtIndex:0];
NSMutableArray *arguments = [NSMutableArray arrayWithCapacity:1+[options count]];
[arguments addObject:@"connect"];
[arguments addObjectsFromArray:options];
int argc = [arguments count];
char **argv = (char **)malloc(sizeof(char*) * (argc + 1));
[arguments enumerateObjectsUsingBlock:^(NSString *option, NSUInteger i, BOOL *stop) {
const char * c_string = [option UTF8String];
int length = (int)strlen(c_string);
char *c_string_copy = (char *) malloc(sizeof(char) * (length + 1));
strcpy(c_string_copy, c_string);
argv[i] = c_string_copy;
}];
argv[argc] = NULL;
const char *cfPass=[password UTF8String];
int ret = self.vpnClient->start2connect(argc, argv, cfPass);
BOOL result;
if (ret!=0){
result=false;
}
else {result = true;}
completionHandler(result);
});
}
все это из networkextension и во время отладки я нашел int ret = self.vpnClient->start2connect(argc, argv, cfPass);
кажется, не возвращает никакого значения.
однако я подтвердил, что метод start2connect возвращает значение int так что на данный момент кто-нибудь может помочь объяснить, что не так?
Спасибо
Вы можете быть более конкретным? Спасибо
Кстати, когда вы запустите это, я бы посоветовал вам запустить это через инструмент «Утечки» в «Инструментах», потому что все эти malloc
вызовы без соответствующих free
вызовов должны вызывать утечки.
BOOL *
— это указатель на BOOL
. Мы не используем этот шаблон очень часто. Мы используем его, когда блоку нужно где-то обновить свойство BOOL
, например. в enumerateMatchesinString
, где вы можете обновить логическое значение, на которое указывает stop
, чтобы остановить перечисление.
Но это обработчик завершения, поэтому нет смысла передавать указатель на логическое значение (тот, который предположительно был в стеке, вызывая проблемы). Просто передайте само логическое значение, а не указатель на него.
Я бы предложил вместо:
- (void)startTunnelWithOptions:(NSDictionary *)options completionHandler:(void (^)(BOOL * error))completionHandler {
...
[vpnAdapter connect:host user:username pass:password add:YES completionHandler:^(BOOL success){
completionHandler(&success);
}];
...
}
Что ты хочешь:
- (void)startTunnelWithOptions:(NSDictionary *)options completionHandler:(void (^)(BOOL success))completionHandler {
...
[vpnAdapter connect:host user:username pass:password add:YES completionHandler:^(BOOL success){
completionHandler(success);
}];
...
}
Обратите внимание, что параметр блока не BOOL * error
, а скорее BOOL success
, и когда он вызывает completionHandler
, перед &
нет success
.
Если по какой-то причине вам нужно было обновить BOOL
, то это другое дело, но в контексте обработчика завершения это не имеет смысла.
Почему параметр блока для
startTunnelWithOptions
используетBOOL *
? Почему бы просто не сделать его параметрBOOL
тоже? Тогда вы просто делаетеcompletionHandler(success);
и все готово. Я не понимаю, что вы пытаетесь сделать...