iOS passing blocks as parameters and calling them

johnmerlino

macrumors member
Original poster
Oct 22, 2011
81
0
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
 

ArtOfWarfare

macrumors G3
Nov 26, 2007
8,609
4,087
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.)
 

Guiyon

macrumors 6502a
Mar 19, 2008
767
1
North Shore, MA
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;
}
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).
 
Last edited:

dejo

Moderator
Staff member
Sep 2, 2004
15,981
450
The Centennial State
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'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.
 

Sykte

macrumors regular
Aug 26, 2010
223
0
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
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
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.