Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective-C: typedef'd a block, used it in a method declaration. How do I implement this?

Just trying to get a handle on blocks. I get the concept. They're like function pointers, but they're actually objects; you can declare a block variable and assign it a block value; call it like a function; they get "frozen in time," for lack of a term, when they get executed, etc. I've created a few blocks and run them successfully, in a few different formats, but when it comes to using them in a method--either with a typedef or without--I'm having a lot of trouble. For example, here's an object interface I created, just to get a handle on the syntax. I have almost no idea how to implement it.

// AnObject.h

#import <Foundation/Foundation.h>

// The idea with the block and the method below is for the block to take
// an int, multiply it by 3, and return a "tripled" int.  The method
// will then repeat: this process however many times the user wants via
// the howManyTimes parameter and return that value in the form of an int.

typedef int (^triple)(int);

@interface AnObject : NSObject
{
    int num;
}

-(int)repeat:(int)howManyTimes withBlock:(triple)someBlock;

@end

Here's what I have for an implementation, so far:

#import "AnObject.h"

@implementation AnObject

@synthesize num;

-(int)repeat:(int)howManyTimes withBlock:(triple)someBlock {
    for (int i = 0; i <= howManyTimes; i++) {
        // What the heck am I supposed to put here?  I'm baffled by the
        // syntax over and over again.
    }
}

@end

I know I'm not addressing the instance variable yet. Again, this is a rough draft, just trying to get a handle on how blocks work. Am I even declaring this method right? I'm reading Big Nerd Ranch's Objective-C Programming, Mike Clark's article on blocks from Pragmatic Studio, and several SO threads. Can't find anything relevant. Thanks.

EDIT: XCode 4.3.2, if it matters.

FURTHER EDIT: Ok. Using BJ's (slightly modified) example, I think I've come up with a really complicated way of multiplying 5 by 3. :)

// BJ's implementation:

-(int)repeat:(int)howManyTimes withBlock:(Triple)someBlock {

    int blockReturnValue;

    for (int i = 0; i <= howManyTimes; i++) {
        blockReturnValue = someBlock(i);
    }
    return blockReturnValue;
}

Main:

...
    @autoreleasepool
    {
        AnObject *obj = [[AnObject alloc] init];

        NSLog(@"%d", [obj repeat: 5 withBlock: ^ (int number) {
            return number * 3;
        }]);

    }
    return 0;
...

And the output is:

15

Now, it's kicking back 15, because the block I defined as an argument is run only once, right? It multiplies "number," which is 5 in this case, by 3 and freezes that answer, right? I'm sure I just created a completely useless method, and I don't yet understand how to utilize the benefits/features of a block. Am I correct?

/********************* UPDATE *********************/

UPDATE: I understand what you're saying, CRD. Just a correction though, for any new programmers who might be reading this, getting a different output and going, "Que?" Your for loop should be either:

for (int i = 0; i < howManyTimes; i++)
            value = someBlock(value);

...or...

(i = 1; i <= howManyTimes; i++)

...to get the answer 243.

And, yes, this is exactly what I was initially trying to do with this code. At least that's what I thought was supposed to be happening. Turns out the author's intent wasn't to triple a number, store that value, triple the stored value, store that...etc., but rather just to print x * 3 for numbers 1-5 (3, 6, 9, 12, 15).

Here is the finished product. I just typedef'd a block that takes an int and returns an int, called Tripler. I also changed the name of the argument from "someBlock" to "triple" to more clearly indicate the intended use of the block. I think those are the only changes to the code.

/********************  interface  ********************/


#import <Foundation/Foundation.h>

typedef int (^Tripler)(int);

@interface AnObject : NSObject

-(void)iterateFromOneTo:(int)number withBlock:(Tripler)triple;

@end

/********************  implementation  ********************/


#import "AnObject.h"

@implementation AnObject

-(void)iterateFromOneTo:(int)number withBlock:(Tripler)triple {
    for (int i = 1; i <= number; i++) {
        NSLog(@"%d", triple(i));
    }
}

@end

/********************  main.m  ********************/


#import "AnObject.h"
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        AnObject *obj = [[AnObject alloc] init];

        [obj iterateFromOneTo:5 withBlock:^(int number) {
            return number * 3;
        }];
    }
    return 0;
}

As you can probably imagine, the resulting output is:

2012-05-05 17:10:13.418 Untitled 2[71735:707] 3
2012-05-05 17:10:13.445 Untitled 2[71735:707] 6
2012-05-05 17:10:13.446 Untitled 2[71735:707] 9
2012-05-05 17:10:13.446 Untitled 2[71735:707] 12
2012-05-05 17:10:13.447 Untitled 2[71735:707] 15

I was making it a lot more complicated than it needed to be. Sorry for explaining it so poorly in the OP. Thanks for your help! /thread? :)

like image 380
baptzmoffire Avatar asked May 03 '12 21:05

baptzmoffire


People also ask

How do you declare a block in Objective C?

Declaring Block VariablesStart with a return type followed by the variable name and a parameter list. You'll need a caret (^) before the variable name and two sets of parentheses. With that in mind, the following example declares a completion block, identical to the one you just saw, but without using custom typedefs.

What is the purpose of block in objective C?

Blocks are a language-level feature added to C, Objective-C and C++, which allow you to create distinct segments of code that can be passed around to methods or functions as if they were values. Blocks are Objective-C objects, which means they can be added to collections like NSArray or NSDictionary .

What is Typedef Objective C?

We can use Objective C to rename a datatype using the typedef fucnction. The typedef function is used to assign the new name to the datatype. So that you can use a custom name for predefined long names of the datatypes. This will not only save time but also aids in having more understandable and easy-to-read code.

What does __ block do?

The __block Storage Type __block variables live in storage that is shared between the lexical scope of the variable and all blocks and block copies declared or created within the variable's lexical scope.


2 Answers

From reading your question I understood, or maybe misunderstood, that your intention was to produce the result of applying your block n times; e.g. if you applied a tripling function twice you'd get the original value multiplied by nine.

Just in case it helps, here is the code to do that:

@interface AnObject

typedef int (^monadic)(int); // an function which takes an int and return an int

- (int) repeat:(int)howManyTimes for:(int)value withBlock:(monadic)someBlock;

@end

@implementation AnObject

- (int) repeat:(int)howManyTimes for:(int)value withBlock:(monadic)someBlock
{
   for (int i = 0; i < howManyTimes; i++)
      value = someBlock(value);

   return value;
}

@end

Now call this with:

AnObject *myObject = [AnObject new];

int z = [myObject repeat:5  
                     for:1 
               withBlock: ^(int number)
                          {
                             return number * 3;
                          }
        ];

and z will have the value 243.

like image 94
CRD Avatar answered Oct 24 '22 13:10

CRD


Just call the block like a regular C function.

-(int)repeat:(int)howManyTimes withBlock:(triple)someBlock {
    for (int i = 0; i <= howManyTimes; i++) {
        int blockReturnValue = someBlock(i);
        // do something with blockReturnValue
    }
}

Update after your "further edit"

No, the block you passed in as an argument is run five times, each pass through the for loop.

  • The first time, it invokes the block with 1 as the argument, and gets back 3. It stores that in blockReturnValue, then goes on to the next iteration of the loop.
  • The second time, it invokes the block with 2 as the argument, and gets back 6. It stores that in blockReturnValue, completely overwriting the value we stored there in the previous pass.
  • The third time, it inbokes the block with 3 as the argument, and gets back 9. Again, it overwrites the value in blockReturnValue.
  • The fourth time, we store 12 in blockReturnValue.
  • The fifth time, we store 15 in blockReturnValue.

Then we exit the for loop, and return 15. So yes, you're correct that you've made a pointless method to multiply by 3. But you're doing it in a way that also does a bunch of useless calculations.

like image 42
BJ Homer Avatar answered Oct 24 '22 12:10

BJ Homer