Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to understand blocks on iOS

I am trying to understand how to use blocks on iOS. I have read Apple's docs but, as usual, they are vague and incomplete and several essential bits of information are not mentioned. I have also googled around without success. This is what I am trying to do as an exercise to understand that.

I have created a block to read a string and compare the string to the previous read. If the strings are not the same, return YES, if they are the same, return NO.

This is how I did:

I declared this on .h

BOOL (^differentStrings)(void);

I declared this on .m, inside viewDidLoad in a viewController

__block NSString * previousString;
__block NSString * currentString;
differentStrings = ^(void){

    currentString = [self getString];
    NSLog(@"%@", currentString); // not printing anything on console

    if (![currentString isEqualToString:previousString]) {
        previousString = currentString;
        return YES;
    } else {
        return NO;
    }
};

This is how I use: I have a thread that does this:

if (differentStrings)
  NSLog (@"strings are different);

These are the problems I have:

  1. the block always return YES (strings are different)
  2. I am not comfortable declaring this inside videDidLoad. How should I declare this, so I can use it globally as a method? Should I put this like I would with a method?
  3. I am calling a method "getString" inside the block. Is it OK?
  4. I find strange to declare the block variables on .m. As I see, I should declare the block variables on .h and then just use them on .m. I have tried to do that, but received an error.
  5. I have setup a debugging point on the first line of the block but it is not stopping there;
  6. NSlog line inside the block do not prints anything. Isn't the block being called?

Can you guys help me with this?

like image 981
Duck Avatar asked Jan 06 '11 12:01

Duck


People also ask

What is block in iOS?

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.

How do I view blocked calls on my iPhone?

Go to Settings > Phone and tap Blocked Contacts to see the list.

How do you block a contact on iPhone 11?

The easiest way to block an individual is through their contact card. Open the contact info of someone you want to block and scroll to the bottom of the screen. There, you'll find a button to block them. Tapping this button will prevent the person from being able to call you, send you text messages, or FaceTime you.


2 Answers

You're misunderstanding how blocks work. (Okay, so that's kinda obvious.) In the same way that previousString is a variable pointing to an NSString, differentStrings is a variable pointing to a block. Not the result of running the block, but rather, the block itself. That is, after you do this:

__block NSString * previousString;
__block NSString * currentString;
differentStrings = ^(void){

    currentString = [self getString];
    NSLog(@"%@", currentString); // not printing anything on console

    if (![currentString isEqualToString:previousString]) {
        previousString = currentString;
        return YES;
    } else {
        return NO;
    }
};

differentStrings is a variable pointing to the block.Thus, when you do this:

if (differentStrings)

…you're simply checking whether differentStrings contains something other than 0 or NULL. Since it contains a block, it is not empty, so it evaluates to true.

Remember: differentStrings is a block variable, not a BOOL variable. It contains a block (a function, if you will), which when called will return a bool. Thus, in order to actually run the block, you need to call it. Like this:

differentStrings();

or, in your case:

if (differentStrings()) {
    NSLog (@"strings are different");
}

Edit: As pointed out in the comments, since differentStrings is an instance variable, you need to copy it, just like you'd call retain on any other object assigned to an instance variable. (For technical reasons I won't go into now, you should always use copy with blocks instead of retain.) Likewise, you'll need to call release on it at some point later, perhaps in your dealloc method.

like image 114
BJ Homer Avatar answered Oct 17 '22 16:10

BJ Homer


I don't believe you're actually executing the block. I think your code should be

if (differentStrings())
{
    NSLog (@"strings are different);
}

Treat a block like a function. I think you were just checking to see whether the block had been defined, not executing it.

Also, if you don't need to access an NSString outside of the block, you could get rid of the __block qualifier and move the currentString declaration inside of the block.

If you need another resource on blocks, I cover them in the fall session of my advanced iOS development course on iTunes U. I describe block syntax in the Understanding Cocoa session, and their use in Grand Central Dispatch within the multithreading session. The course notes also have links to some sample applications that use blocks in different ways.

I also can't recommend highly enough that you watch the WWDC 2010 video sessions 206 - Introducing Blocks and Grand Central Dispatch on iPhone and 211 - Simplifying iPhone App Development with Grand Central Dispatch.

like image 4
Brad Larson Avatar answered Oct 17 '22 18:10

Brad Larson