objC / C-组合:让C函数等到objC-Delegate完成

时间:2009-10-07 16:30:18

标签: iphone c objective-c

我在这里遇到问题:

我有一个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方法(在它自己的类中)设置waitingForResponse == 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 个答案:

答案 0 :(得分:3)

你不应该在主线程上做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];

您可以明确指定一些常量而不是01,并且有一个非常好的解决方案。

答案 1 :(得分:2)

此代码

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

看起来很奇怪。特别是,在alertViewDelegate上永远不会调用init。如果实例未正确初始化,您可能会发现事情不正常。你也泄漏了alertViewDelegate,因为你有两个所有权引用(来自allocretain,但没有平衡版本。至少,这些行应该是

alertViewDelegate = [[FireallRest alloc] init];

...

[alertViewDelegate release]; //balancing release at end of scope

答案 2 :(得分:0)

这看起来有点奇怪.. alertViewDelegate = [FirewallRest alloc]; [alertViewDelegate保留];这里发生了什么?

'waitingForResponse'在哪里宣布?您使用'extern'关键字。如果你不知道它在做什么,你就不应该这样做。

您可能需要发布更多代码,包括头文件。

但是,假设waitingForResponse是alertViewDelegate的属性,则使用self。 waitingForResponse在设置waitingForResponse的值并使用alertViewDelegate时。 waitingForResponse在测试时。

答案 3 :(得分:0)

我最终使用了一个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()

用户界面仍然非常敏感,我没有注意到应用程序的任何减速。