iOS in-depth learning (Block comprehensive analysis)

Keywords: github xcode git

This article is translated from Apple Documents There are deletions and additions.

If you don't understand Block syntax, you can refer to fucking block syntax, which is for Block.

For comparison purposes, I assume that the following code is written in the ViewController subclass

1. Part I

Define and use Block,

- (void)viewDidLoad
{
    [super viewDidLoad];
    //(1) Define a Block with no parameters and no return value
    void (^printBlock)() = ^(){
        printf("no number");
    };
    printBlock();
    

    printBlock(9);
    
    int mutiplier = 7;
    //(3) Define a code block named myBlock with return value type int
    int (^myBlock)(int) = ^(int num){
        return num*mutiplier;
    }
    //Use the defined myBlock
    int newMutiplier = myBlock(3);
    printf("newMutiplier is %d",myBlock(3));
}
//Defined outside the - viewDidLoad method
//(2) Define a Block with parameters and no return value
void (^printNumBlock)(int) = ^(int num){
    printf("int number is %d",num);
};

Defining a Block variable is equivalent to defining a function. But the difference is also obvious, because the function must be defined outside the - viewDidLoad method, while the Block variable is defined inside the viewDidLoad method. Of course, we can also define a block outside the - viewDidLoad method, such as the definition of the block printNumBlock above, just outside the - viewDidLoad method.

Let's look at the sequence of the above code. In terms of the (3) myBlock distance, the code inside the Block {} is not executed at the defined place, but only after the call of myBlock(3), which is similar to the understanding of the function, that is, the code inside the Block (function body) is executed only when the Block (function) is called. So for the simple code example above, I can draw the following conclusions.

(1) Defining a Block variable in a class is like defining a function;

(2) Block can be defined either inside or outside the method.

(3) Only when a Block is called will the code in its {} body be executed;

PS: With respect to Article (2), a Block defined outside a method is actually a global variable at the file level.

So what's the point of defining a Block in a class, especially in the body of the - viewDidLoad method? I mean, at this point, just treat it as a private function. As I said before, a Block is actually an agent, so how can I compare it to an agent at this time? At this point, I can say that the Block in this class is equivalent to the class itself obeying a certain agreement and then letting itself do something on behalf of itself. It's awkward, isn't it? Look at the code below.

//Define a protocol
@protocol ViewControllerDelegate<NSObject>
- (void)selfDelegateMethod;
@end

//This class implements the protocol ViewController Delegate
@interface ViewController ()<ViewControllerDelegate>
@property (nonatomic, assign) id<ViewControllerDelegate> delegate;

@end

Then the code in - viewDidLoad is as follows.

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    self.delegate = self;
    if (self.delegate && [self.delegate respondsToSelector:@selector(selfDelegateMethod)]) {
        [self.delegate selfDelegateMethod];
    }
}

#pragma mark - ViewControllerDelegate method
//The Method of Implementing Protocol
- (void)selfDelegateMethod
{
    NSLog(@"Ways to Delegate Self-Realization");
}

Do you see the wonderful place of this writing? You delegate yourself to implement a method, not another class to implement a method. In fact, a Block defined in this class is a pain in idle eggs, delegating oneself to do something, which has little practical significance. So you seldom see other people's code define a Block directly in the class and then use it. Many uses of a Block are used across two classes, such as as as property attributes or as parameters of a method, so that it can span two classes.

2. Part Two

_ The Use of block Keyword

In Block's {} body, external variables can not be changed, such as the following statement,

- (void)viewDidLoad
{
    //Define a Block within a method
    int x = 100;
    void (^sumXAndYBlock)(int) = ^(int y){
    x = x+y;
    printf("new x value is %d",x);
    };
    sumXAndYBlock(50);
}

What's wrong with this code? Xcode will prompt the error message of X variable: Variable is not assigning (missing block type), then give int x = 100; add the block keyword before the statement, as follows.

__block int x = 100;

In Block's {} body, you can modify external variables.

3. Part 3: Block as property property property to transfer values between pages

Requirement: In ViewController, click Button, push to NextViewController on the next page, enter a string of characters in TextField of NextViewController's input box, and display text content on Label of ViewController when returned.

(1) The first method: First, see how to transfer value between two pages through "protocol/proxy".

//NextViewController is the second page push enters
//NextViewController.h file
//Define a protocol that ViewController on the previous page will obey and implement the methods in the protocol
@protocol NextViewControllerDelegate <NSObject>
- (void)passTextValue:(NSString *)tfText;
@end

@interface NextViewController : UIViewController
@property (nonatomic, assign) id<NextViewControllerDelegate> delegate;

@end

//NextViewController.m file
//Click Button to return to the previous ViewController page
- (IBAction)popBtnClicked:(id)sender {
    if (self.delegate && [self.delegate respondsToSelector:@selector(passTextValue:)]) {
        //self.inputTF is the TextField input box on this page
        [self.delegate passTextValue:self.inputTF.text];
    }
    [self.navigationController popViewControllerAnimated:YES];
}

Next, let's look at the contents of the ViewController file.

//ViewController.m file
@interface ViewController ()<NextViewControllerDelegate>
@property (strongnonatomicIBOutlet UILabel *nextVCInfoLabel;

@end
//Click Button to go to the next NextViewController page
- (IBAction)btnClicked:(id)sender
{
    NextViewController *nextVC = [[NextViewController alloc] initWithNibName:@"NextViewController" bundle:nil];
    nextVC.delegate = self;//Setting agent
    [self.navigationController pushViewController:nextVC animated:YES];
}

//Implementation of NextViewController Delegate
#pragma mark - NextViewControllerDelegate method
- (void)passTextValue:(NSString *)tfText
{
    //self.nextVCInfoLabel is a string Label object that displays the NextViewController passed in
    self.nextVCInfoLabel.text = tfText;
}

This is a way of passing values between two pages through "protocol/proxy".

(2) The second method is to use Block as property to transfer values between two pages.

First, look at the contents of the NextViewController file.

//NextViewController.h file
@interface NextViewController : UIViewController
@property (nonatomic, copy) void (^NextViewControllerBlock)(NSString *tfText);

@end
//NextViewContorller.m file
- (IBAction)popBtnClicked:(id)sender {
    if (self.NextViewControllerBlock) {
        self.NextViewControllerBlock(self.inputTF.text);
    }
    [self.navigationController popViewControllerAnimated:YES];
}

Let's look at the contents of the ViewController file.

- (IBAction)btnClicked:(id)sender
{
    NextViewController *nextVC = [[NextViewController alloc] initWithNibName:@"NextViewController" bundle:nil];
    nextVC.NextViewControllerBlock = ^(NSString *tfText){
        [self resetLabel:tfText];
    };
    [self.navigationController pushViewController:nextVC animated:YES];
}
#pragma mark - NextViewControllerBlock method
- (void)resetLabel:(NSString *)textStr
{
    self.nextVCInfoLabel.text = textStr;
}

Well, with so much code, you can use Block to achieve the purpose of passing values between two pages, which is actually replacing the function of Delegate.

In addition, the code Sample Code in the blog can be used again Github Download, if Github is walled, you can use git clone + full link at the terminal to clone the project locally.

The code in Github can open two debugging modes. You need to annotate or annotate the following code in the project configuration file BlockSamp-Prefix.pch.

#define Debug_BlcokPassValueEnable

You can open two debugging methods, if you annotate the above statement, you use Delegate to debug; otherwise, you use Block to debug.

Posted by smartsley on Sat, 30 Mar 2019 08:27:28 -0700