performSelector:withObject:afterDelay: not making call

13,020

Solution 1

Try using:

-(void) select {   
    [self changeButtonNames];
    [self drawMap];
    [self performSelectorOnMainThread:@selector(showActionSheet) withObject:nil waitUntilDone:YES];
}

-performSelector:withObject:afterDelay: schedules a timer on the same thread to call the selector after the passed delay.

Maybe this will work for you:

-(void) select {   
    [self changeButtonNames];
    [self drawMap];
    [self performSelectorOnMainThread:@selector(someA) withObject:nil waitUntilDone:YES];
}

-(void)someA {
    [self performSelector:@selector(showActionSheet) withObject:nil afterDelay:2];
}

Solution 2

I ran into this same issue, and by necessity I solve it slightly different from the accepted answer. Notice I wanted my delay and selectors to be variables? Using a block allows me to stay within my current method.

dispatch_async(dispatch_get_main_queue(), ^{
       [self performSelector:loopSelector withObject:nil afterDelay:cycleTime];
});  

By the way, this is definitely a threading issue. The documentation for performSelector:withObject:afterDelay: states that this will be performed on the current thread after the delay, but sometimes that thread's run loop is no longer active.

A more detailed discussion on the subject can be found here

Solution 3

Does your class still exist in memory?

If your class goes away before the performSelector fires, do you wind up sending the message to nil (which would cause nothing to occur). You could test this by dropping an NSLog into your dealloc()

You mentioned threads. If your performSelector isn't called from the MainThread it could cause issues (UI things should be done on the main thread).

Share:
13,020

Related videos on Youtube

Padin215
Author by

Padin215

Updated on June 04, 2022

Comments

  • Padin215
    Padin215 almost 2 years

    in a method, i want to call a method after n seconds:

        self.toolBarState = [NSNumber numberWithInt:1];
        [self changeButtonNames];
        [self drawMap];
        [self performSelector:@selector(showActionSheet) withObject:nil afterDelay:2];
    

    i want to show the action sheet 2 seconds after drawMap is complete. when i use this performSelector, it never makes the call.

    if i just put [self showActionSheet];, it works just fine. is there reason why the performSelector is not making the call?

    EDIT: in another part of my code, i make the same call and it works:

    HUD = [[MBProgressHUD alloc] initWithView:self.view];
    [self.view addSubview:HUD];
    HUD.delegate = (id) self;
    [HUD showWhileExecuting:@selector(drawMap) onTarget:self withObject:nil animated:YES];
    
    [self performSelector:@selector(showActionSheet) withObject:nil afterDelay:6];
    

    here, the showActionSheet gets called 6 seconds after drawMap has completed. i'm guessing there is something going on with the threads that i don't understand yet...

    EDIT2:

    -(void)showActionSheet
    {
        InspectAppDelegate *dataCenter = (InspectAppDelegate *) [[UIApplication sharedApplication] delegate];
    
        if (dataCenter.fieldIDToPass == nil)
        {
            UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"Selected Boundary Options" delegate:(id) self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Analyze a Field",@"Retrieve Saved Analysi", @"Geotag Photos", @"Refresh the map",nil];
            actionSheet.tag = 0;
            [actionSheet showInView:self.view];
        }
        else
        {
            UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"Selected Boundary Options" delegate:(id) self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:@"Analyze a Field",@"Retrieve Saved Analysi", @"Geotag Photos", @"Attribute the Field", @"Refresh the map",nil];
            actionSheet.tag = 0;
            [actionSheet showInView:self.view];
    
        }
    }
    

    EDIT3:

    ok, so the progress of method calls is:

    -(void) foundDoubleTap:(UITapGestureRecognizer *) recognizer
    {        
        [HUD showWhileExecuting:@selector(select) onTarget:self withObject:nil animated:YES];
    }
    
    -(void) select
    {   
            [self changeButtonNames];
            [self drawMap];
            [self performSelector:@selector(showActionSheet) withObject:nil afterDelay:2];
    }
    

    showActionSheet never gets called. like i said, i'm pretty sure its a threading issue. if call it with [self showActionSheet], it will run. =/

  • Padin215
    Padin215 over 12 years
    this does work, the method gets called but there is no delay which is what i'm trying to do. i want showActionSheet to wait n seconds after drawMap is complete (i'm making a change to the view and want the user to see the change before the action sheet is brought up).
  • rishi
    rishi over 12 years
    Yes.there is no delay on main thread methods, you can try with edited part above
  • Padin215
    Padin215 over 12 years
    ha, that works perfectly! think you could explain why this works? i'm guessing it has something to do with the threads, where this is getting process back onto the main thread which does get killed?
  • rishi
    rishi over 12 years
    showWhileExecuting works on a new thread, so from there before calling any other selector you need to move to main thread. That is main logic. For more information you can check - developer.apple.com/library/mac/#documentation/Cocoa/Referen‌​ce/…
  • Padin215
    Padin215 over 12 years
    awesome, thanks for the info. i added in some NSLog(@"%@", [NSThread currentThread]) and ya, as soon as it goes to -(void)select its a new thread. with the fix, when it gets to -(void)showActionSheet its back on the main thread.
  • Padin215
    Padin215 about 11 years
    Yep, I recently updated the MBProgressHUD library and in their how-to, they suggest getting the main thread and running the methods just like this. I've switch to doing it this way as well.
  • jab
    jab about 10 years
    The OP needs the main thread to show an action sheet. My problem was a little different, but this was still basically a good solution. I used dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ), ^{ rather than run on the main queue.