Challenge - Anonymous Block


#1

Okay,

Finally made it here, seems like a pretty straightforward replacement and only had one syntactic thing that surprised me.

[oldStrings enumerateObjectsUsingBlock:^(id string, NSUInteger i, BOOL *stop)
        
            {
            
            NSMutableString *newString = [NSMutableString stringWithString:string];
            
            // Iterate over the array of vowels, replacing occurences of each
            // with an empty string.
            for (NSString *s in vowels) {
                NSRange fullRange = NSMakeRange(0, [newString length]);
                [newString replaceOccurrencesOfString:s withString:@"" options:NSCaseInsensitiveSearch range:fullRange];
            }
            
            [newStrings addObject:newString];
            
            
            }]; // End of Block Assignment

I expected the closing syntax to be };]; , but it complained that it was still expecting ] with that. So I tried what i have above }]; and it worked. That surprised me as the other examples had the blocks being closed out as a statement }; , putting it inline anonymous seems to remove that requirement. Executed exactly the same otherwise, fairly straightforward substitution.

I read a bit of Apple’s documentation on blocks and can see that the scope is actually bigger allowing that newStrings (not newString which is defined inside the block) usage inside the block. That’s what really confused me.

Definitely will need to revisit this a few times or see other examples of when it’s appropriate.
Actually a few more exercises/challenges might be good for your next revision. Hell I’d buy an accompanying workbook that had more exercises and other usages.

Myrhillion


#2

I got exactly the same results as you. I imagine the ; gets left out as it signifies the end of a line.

[code] // Iterate over the oldStrings using our block
[oldStrings enumerateObjectsUsingBlock:^(id string, NSUInteger i, BOOL *stop) {

        // Did we find a 'y'?
        NSRange yRange = [string rangeOfString:@"y"options:NSCaseInsensitiveSearch];
        
        if (yRange.location != NSNotFound) {
            *stop = YES; // Prevent further iterations
            return; // Kick out of this one
        }
        
        NSMutableString *newString = [NSMutableString stringWithString:string];
        
        // Iterate over the array of vowels, replace each with an empty string
        for (NSString *s in vowels) {
            NSRange fullRange = NSMakeRange(0, [newString length]);
            [newString replaceOccurrencesOfString:s
                                       withString:@""
                                          options:NSCaseInsensitiveSearch
                                            range:fullRange];
        }
        
        [newStrings addObject:newString];
    }];

[/code]

Using a block anonymously like this seems to defeat a lot of the point to me!


#3

I agree, I think it’s it bit easier to read when the block is assigned to a variable.


#4

I’m just a total beginner in Objective-C but this looks exactly the same as anonymous functions in javascript and with experience you’ll see that you’ll probably never assign a block to a variable. Actually it’s a bit in the definition of those functions: you don’t declare it because you’ll use it only once, so you write its body right away.


#5

BTW, in the examples of the book the semicolon is here for the assignment, like a:

int i = 0;

but when it’s used as an argument you don’t put a semicolon, like in:

function(a, b, {my block code});

or

[object sendMessage:{my block code}];

Does make sense.


#6

I’ve got to say, this was hands down the best intro to blocks have read, and while I’m certainly still no expert, at least now I understand the gist of blocks…

My solution looks very similar to myrhillion.

I love the writing style of this book, I happened to be doing some business while I was reading ahead on this chapter, I found paragraph stating I should name the project VowelMovement, with reference to @autoreleasepool’s curly brackets, to be quite amusing at the time. Then for the challenge to be passing an anonymous block… :laughing:


#7

With the help of those who have posted earlier, I was able to get this to run.

Are you supposed to be able to reuse blocks? Or have more than one block? I assume the answer is “yes” to both, but the notion of an anonymous block would seem to make that impossible. How would the program know which block is which?

//  main.m
//  Challenge Anonymous Block

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    
    @autoreleasepool {
        
        // Create the array of strings to devowelize and a container for the new ones
        NSArray *oldStrings = [NSArray arrayWithObjects:@"Sauerkraut", @"Raygun", @"Big Nerd Ranch", @"Mississippi", nil];
        NSLog(@"old strings: %@", oldStrings);
        NSMutableArray *newStrings = [NSMutableArray array];
        
        // Create a list of characters that we'll remove from the string
        NSArray *vowels = [NSArray arrayWithObjects:@"a", @"e", @"i", @"o", @"u", nil];       
     
        //Iterate over the array with our block
        [oldStrings enumerateObjectsUsingBlock: ^(id string, NSUInteger i, BOOL *stop)   {
             NSMutableString *newString = [NSMutableString stringWithString:string];
             // Iterate over the array of vowels, replacing occurrences of each with an empty string.
             for (NSString *s in vowels) {
                 NSRange fullRange = NSMakeRange(0, [newString length]);
                 [newString replaceOccurrencesOfString:s 
                                            withString:@"" 
                                               options:NSCaseInsensitiveSearch 
                                                 range:fullRange];
             }

             [newStrings addObject:newString];
         }]; // End of block assignment

        NSLog(@"new strings: %@", newStrings);
        
    }
    return 0;
}

#8

I’m glad to see you guys had some of the same misgivings that I had. And, imbedding that whole block inside that enumerateObjectsUsingBlock: message just somehow offends my sense of organization, or clarity, or something! Maybe I’ll get used to it. I can see how that would be useful if you only needed to use the block once for some Apple framework/library call, but I’m not sure that I wouldn’t separate it out anyway just so that I could more easily see where the end of that object message pair ended…