passing blocks as parameters and calling them

Discussion in 'iOS Programming' started by johnmerlino, May 24, 2012.

  1. johnmerlino macrumors member

    Joined:
    Oct 22, 2011
    #1
    I declared a block in .h: void (^block)(BOOL);
    I initialize it:

    I initialize it in .m:

    Code:
    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
    {
        self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
        if (self) {
            block = ^(BOOL noshow)
            {
                if(noshow){
                    AutoTracView.hidden = YES;
                    MarineTracView.hidden = YES;
                    
                }
            };
        }
        return self;
    }
    
    I pass it as a parameter:

    Code:
    [self renderView:[current_unit.unit_type intValue] onCollection:(NSDictionary *)collection withBlock:block];
    
    And then try to call it, passing it the boolean:

    Code:
    -(void)renderView:(int)value onCollection:(NSDictionary *)collection withBlock:block
    {
        block(TRUE);
        NSString *index = [NSString stringWithFormat:@"%d", value];
        UIView *view = [collection objectForKey:index];
        view.hidden = NO;    
    }
    

    but it fails with above saying with the call to block(TRUE) with compile error: "expected identifier"

    thanks for response
     
  2. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #2
    Now, it's possible that you know something that I don't, but I wasn't aware of any feature allowing one to store blocks in variables that could then be used later...

    alright, I just read something here that tells me that I'm wrong and you're right:
    http://pragmaticstudio.com/blog/2010/7/28/ios4-blocks-1

    I don't have any experience with this, but based on skimming through that article, I think the proper way of declaring a block variable with the name block would be like this:

    Code:
    void (^[b]block[/b])(BOOL) = ^ (BOOL noshow) {
        if(noshow){
            AutoTracView.hidden = YES;
            MarineTracView.hidden = YES;        
        }
    };
    I've bolded block to clarify that I'm using that to say what the name of the block is, not that it is a block (the ^ symbol already conveys the fact that it's a block.)

    I hope I've helped! (And if I haven't... I am curious... I've never tried storing a block as a variable before, and I'd like to see how it's done.)
     
  3. PhoneyDeveloper macrumors 68030

    PhoneyDeveloper

    Joined:
    Sep 2, 2008
    #3
  4. Guiyon, May 25, 2012
    Last edited: May 25, 2012

    Guiyon macrumors 6502a

    Joined:
    Mar 19, 2008
    Location:
    North Shore, MA
    #4
    This is possible but, one thing to remember is that the block lives on the stack. What this means is that the moment this method returns, your block is invalid and should not be called. What you'll need to to do is either:
    • Assign the block to a property with the 'copy' attribute
    • Copy the block manually using the -copy method
      Code:
      block = [^(BOOL noshow)
              {
                  if(noshow){
                      AutoTracView.hidden = YES;
                      MarineTracView.hidden = YES;
                      
                  }
              } copy];

    If you are using the first method with ARC, your memory management should be handled by the compiler (if ARC is not enabled, be sure to free the block in your -dealloc method/when you are done with it). If you are manually copying it, make sure you call -release on the block (and nil out the variable) once you are done with it!

    Edit: One more thing, don't do direct variable accesses inside the block! It looks like the two views you are accessing will most likely not be initialized at that point and will become static values inside the block. In this case, you'll be effectively calling nil. I would suggest moving those values over to either public properties or private properties in a class extension and the use something like 'self.autoTracView.hidden' instead of 'AutoTracView.hidden' (same with MarineTracView).
     
  5. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #5
    I'd suggest never using block as the name of the block for the same reason you should never use variable as the name of a variable. Use a name that provides an idea of the purpose of the block and help keep your code self-documenting; in this case, perhaps something like blockToHideAutoAndMarineTracViews.
     
  6. Sykte macrumors regular

    Joined:
    Aug 26, 2010
    #6
    I typed this a while ago while the question was different I think it will give you a ok overview.
    http://forums.macrumors.com/showthread.php?t=1225712
     

Share This Page