我在这里遇到问题:
我有一个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;)
提前感谢您提供任何帮助
答案 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];
您可以明确指定一些常量而不是0
和1
,并且有一个非常好的解决方案。
答案 1 :(得分:2)
此代码
alertViewDelegate = [FirewallRest alloc];
[alertViewDelegate retain];
看起来很奇怪。特别是,在alertViewDelegate上永远不会调用init
。如果实例未正确初始化,您可能会发现事情不正常。你也泄漏了alertViewDelegate,因为你有两个所有权引用(来自alloc
和retain
,但没有平衡版本。至少,这些行应该是
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()
。
用户界面仍然非常敏感,我没有注意到应用程序的任何减速。