objC / C- комбинированный: позволить функции C ждать, пока objC-Delegate не будет завершен - PullRequest
0 голосов
/ 07 октября 2009

У меня проблема здесь:

У меня есть функция C:

int my_connect(int sockfd, const struct sockaddr *serv_addr,
      socklen_t addrlen) {
 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
 alertViewDelegate = [FirewallRest alloc];
 [alertViewDelegate retain];
 //ALog(@"1");

 int error;
 //ALog(@"2");
 char hostname[NI_MAXHOST] = "";
 //ALog(@"3");

 error = getnameinfo(serv_addr, addrlen, hostname, NI_MAXHOST, NULL, 0, 0);
 //ALog(@"4");
 if (error !=0) {
  ALog(@"coudldn't resolve hostname or internal connect");
  [pool release];
  return orig__connect(sockfd, serv_addr, addrlen);
 }
 if (error == 0) {
  ALog(@"hostname: %s", hostname);
  NSString *hostFirst = [NSString stringWithCString:hostname];
  NSString *host = [hostFirst stringByReplacingOccurrencesOfString:@"www." withString:@""];

  NSString *msg = [@"tries to contact: " stringByAppendingString:host];
  UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"asdf"
              message:msg
                delegate:alertViewDelegate cancelButtonTitle:@"Never allow!"
             otherButtonTitles:@"1", @"2",@"3", nil];
  [alert show];
  [alert release];



  waitingForResponse = YES;

  while (waitingForResponse == YES) {
   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   ALog(@"running Loop1?");
   [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
   ALog(@"running Loop2?");
   [pool drain];
  }


  ALog(@"continues");

  return orig__connect(sockfd, serv_addr, addrlen);
...

Следует подождать, пока метод UIAlertViewDelegate (в своем собственном классе) установит waitForResponse == NO.

extern BOOL waitingForResponse;

@implementation FirewallRest

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
 //NSLog(@"buttonIndex: %@", buttonIndex);

 if (buttonIndex == 0){
  NSLog(@"0");
  waitingForResponse = NO;
 }

 if (buttonIndex == 1){
  NSLog(@"1");
  waitingForResponse = NO;
 }
 if (buttonIndex == 2){
  NSLog(@"2");
  waitingForResponse = NO;
 }
 if (buttonIndex == 3){
  NSLog(@"3");
  waitingForResponse = NO;
 }


}

но почему-то это не работает: /

У кого-нибудь есть идея? или лучший способ сделать это? (Я не очень привык к C и objC в одном приложении;))

Заранее спасибо за любую помощь

Ответы [ 4 ]

3 голосов
/ 07 октября 2009

Вы не должны выполнять IO в главном потоке, ваша потребность в обработке цикла выполнения очевидна. Циклы выполнения сложны, особенно потому, что многие события не приводят к завершению вызова runloop, как ожидалось (все, что выполняется по таймеру для одного, выполнение селекторов просто выполняется по таймеру) . Возможно, вы могли бы решить свою проблему, не ожидая distantFuture, а всего лишь несколько сотен миллисекунд за раз.

Что вы действительно хотите сделать, так это запустить my_connect() в фоновом потоке и просто подождать условия. Этот код будет намного легче обрабатывать, он будет выглядеть как менее взломанный и на самом деле будет работать лучше.

Вы можете использовать экземпляр NSConditionLock для реализации ожидания. Это не супер очевидно, как это сделать. Но вы можете создать общий экземпляр в NSConditionLock в переменной condLock следующим образом:

condLock = [[NSConditionLock alloc] initWithCondition:0];

И тогда вы бы реализовали ожидание в my_connect():

[condLock lockWhenCondition:1];
// Add code that needs to be thread safe here if you like.
[condLock unlockWithCondition:0];

И вот как вы должны сообщить NSConditionLock, что пришло время продолжить с вашего метода делегата.

[condLock lock];
// More thread safe code here if you like
[condLock unlockWithCondition:1];

Вы можете назначить некоторые константы для использования вместо 0 и 1 в явном виде и получить довольно хорошее решение.

2 голосов
/ 07 октября 2009

Этот код

 alertViewDelegate = [FirewallRest alloc];
 [alertViewDelegate retain];

выглядит очень странно. В частности, init никогда не вызывается в alertViewDelegate. Вы можете ожидать, что вещи будут вести себя неправильно, если экземпляр не инициализирован должным образом. Вы также пропускаете alertViewDelegate, поскольку у вас есть две ссылки на него (от alloc и retain, но нет балансировочных релизов. По крайней мере, эти строки должны быть

alertViewDelegate = [[FireallRest alloc] init];

...

[alertViewDelegate release]; //balancing release at end of scope
0 голосов
/ 14 октября 2009

Я использовал другую систему с UIActionSheet:

в my_connect() Я делаю:

[alertViewDelegate performSelectorOnMainThread:@selector(createActionSheet) withObject:nil waitUntilDone:YES];

затем в alertViewDelegate я создаю лист действий:

- (void) createActionSheet {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
whatToDo = 4;

UIActionSheet *actionSheet = [[UIActionSheet alloc]
                              initWithTitle:[@"this app tries to contact: \n " stringByAppendingString:host]
                              delegate:self
                              cancelButtonTitle:nil
                              destructiveButtonTitle:nil
                              otherButtonTitles:@"Always allow!", @"Always Disallow!", @"Allow all for this App",  nil];
actionSheet.actionSheetStyle = UIActionSheetStyleBlackOpaque;

[actionSheet showInView:[[UIApplication sharedApplication] keyWindow]];
[actionSheet release];
waitUntilDone = YES;

while (waitUntilDone == YES) {

    NSAutoreleasePool *pool2 = [[NSAutoreleasePool alloc] init];
    //ALog(@"running Loop1?");
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.05]];
    //ALog(@"running Loop2?");
    [pool2 release];
}
[pool release];

}

поэтому этот метод ожидает завершения методов делегата, а затем my_connect() продолжается.

Пользовательский интерфейс по-прежнему очень отзывчив, и я не заметил замедления работы приложений.

0 голосов
/ 07 октября 2009

Это выглядит немного странно .. alertViewDelegate = [FirewallRest alloc]; [alertViewDelegate retain]; Что здесь происходит?

Где объявлено ожидание ответа? Вы используете ключевое слово extern. Вы не должны, если вы не знаете, что он делает.

Возможно, вам потребуется опубликовать немного больше кода, включая заголовочный файл.

Но, если предположить, что waitForResponse является свойством alertViewDelegate, использует self. waitForResponse при установке значения waitForResponse и использовании alertViewDelegate. waitForResponse при тестировании.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...