I'm having a problem here:
I have a C function:
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);
...
It should wait till the UIAlertViewDelegate method (in it's own class) sets 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 = N开发者_运维技巧O;
}
if (buttonIndex == 2){
NSLog(@"2");
waitingForResponse = NO;
}
if (buttonIndex == 3){
NSLog(@"3");
waitingForResponse = NO;
}
}
but somehow that doesn't work :/
does anyone have an idea? or a better way to do this? (I'm not very used to C and objC in one app ;))
Thanks in advance for any help
You should not do IO on the main thread, your need to try to handle a run-loop is evident. Run-loops are tricky, especially since many events do not make the runloop call exit as expected (Anything run on a timer for one, performing selectors just happens to be run on a timer). You could probably solve your problem by not waiting for distantFuture
, but just for a few hundred milliseconds at a time.
What you really want to to do is top run my_connect()
in a background thread, and just wait for a condition. This code will be much easier to handle, look like less of a hack, and actually perform better.
You can use an instance of NSConditionLock
to implement the wait. It is not super obvious how to do this. But you can create a shared instance on NSConditionLock
in the variable condLock
like this:
condLock = [[NSConditionLock alloc] initWithCondition:0];
And this is then how you would implement the waiting in my_connect()
:
[condLock lockWhenCondition:1];
// Add code that needs to be thread safe here if you like.
[condLock unlockWithCondition:0];
And this is how you would signal the NSConditionLock
that it is time to continue from you delegate method.
[condLock lock];
// More thread safe code here if you like
[condLock unlockWithCondition:1];
You could assign some constants to use instead of 0
and 1
explicitly, and have a quite nice solution.
This code
alertViewDelegate = [FirewallRest alloc];
[alertViewDelegate retain];
looks very weird. In particular, init
is never called on alertViewDelegate. You might expect things to not behave appropriately if the instance isn't properly initialized. You also leak alertViewDelegate, as you have two owership references to it (from alloc
and retain
, but no balancing releases. At the very least, these lines should be
alertViewDelegate = [[FireallRest alloc] init];
...
[alertViewDelegate release]; //balancing release at end of scope
This looks a bit weird.. alertViewDelegate = [FirewallRest alloc]; [alertViewDelegate retain]; What is happening here?
Where is 'waitingForResponse' declared? You use the 'extern' keyword. You shouldn't if you don't know what it is doing.
You may need to post a bit more code, including header file.
But, assuming waitingForResponse is a property of alertViewDelegate use self. waitingForResponse when setting waitingForResponse's value and use alertViewDelegate. waitingForResponse when testing it.
I ended up using a different system with an UIActionSheet
:
in my_connect()
I do:
[alertViewDelegate performSelectorOnMainThread:@selector(createActionSheet) withObject:nil waitUntilDone:YES];
then in the alertViewDelegate I create the action sheet:
- (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];
}
so this method is waiting until the delegate's methods are finished and then my_connect()
continues.
The UI is still very responsive and I didn't notice any slowdown of the apps.
精彩评论