iOS Development - When Block, Agent, Notification Meets Girlfriend

Keywords: github

  • What is Block?
  • Why use Block?
  • How to use Block?

This article will start with these three questions to gradually understand Block.
The example portal used in this article: https://github.com/Elbertz/ZDXBlockStudy

What is Block?

First, let's look at the block format.

a (^b)(c,d)=^(c name1,d name2){};
a: Block The return value type of the(void);
b: Block Object name, can be understood as variable name;
^: Grammatical markers for blocks, declarations b For one Block object;
c: First parameter type
d: Second parameter type
name1,name2: Parameter name;
{}: Block Theme section of the code block.

Some people think that Block is a block of code, and a block of code in the form of closure has good independence and interactivity.
Others regard Block as an anonymous function of OC, which can transfer parameters very well.
Others think that Block is a special data type, and the created Block object can be better invoked by the context.
There's also a group of people who think that a Block is a Block. Blind and one-sided definitions conceal its simple and subtle use, so they describe what a Block is in a usage scenario.

Why use Block?

Block as a parameter and return value can be more convenient to transfer between different scenarios.
Block as a callback can be widely used in multi-threaded GCD, animation, sorting situations;

The following is the basic use of Block. The children's shoes with clear ideas of Block can be deeply studied through the following two cases:
Block implements various sorting: https://github.com/JiongXing/JXSort
AFNetworking: https://github.com/AFNetworking/AFNetworking

How to use Block?

Before using Block, we first popularize the basic knowledge points used by Block in ARC and MRC environments:
ARC: The system will help you manage the memory of the objects you create.
MRC: You need to manage the memory of the objects you create yourself
When you create a new project, the default is the ARC environment. You can turn off the automatic reference count and switch to the MRC environment under Build Setting.

Why use copy to decorate a Block?

Using copy, you can move a Block from the stack to the heap
Under MRC, the default is that in order to control the life cycle of a Block on the stack, it is necessary to copy it on the heap, not to replace it with creation. Most of the cases in ARC are on the heap by default, but because of the tradition, copy can be written, but strong can be used instead.

Does ARC require manual copy of Block?

What about not copy ing manually?

1. When Block is strongly referenced.
2. When using Block is included in the API of the system.
3.Block as function return value.

In the case of manually copy ing?

When block is used as a function parameter, our custom block under arc writes copy.

Note: The characteristics of copy
1. If it was originally on the stack, it was copied to the heap through copy.
2. If it was in the global data area, it would not change.
3. If in the heap area: its reference count plus 1

How to avoid circular references in the use of Block s?

ARC case

1. If you modify a Block with copy, the Block will be stored in heap space. The internal object of the block is strongly referenced, resulting in circular references. Memory cannot be freed.
2. If you modify a Block with weak ness, the Block will be stored in the stack space. There will be no circular reference problem.

MRC case

After modification with copy, if you want to use objects inside a block, you need to (_block typeof (Target) block Target = Target) process. Block Target is used to operate in Block.

_ block has two functions under MRC
1. Allow access to and modification of local variables in Block
2. Prohibit Block from implicitly retain ing referenced objects
_ block has only one function under ARC
1. Allow access to and modification of local variables in Block
_ weak avoids circular references caused by blocks under ARC

Use scenarios?

Standard paradigm:

// 1.Use typedef Definition Block type
typedef int(^MyBlock)(int, int);

// 2.Define a formal parameter as Block Of OC function
- (void)useBlockForOC:(MyBlock)aBlock
{
    NSLog(@"result = %d", aBlock(300,200));
}

// 3.Declare and assign values to define a Block variable
MyBlock addBlock = ^(int x, int y){
    return x+y;
};

// 4.with Block As a function parameter,hold Block Delivery as an object
[self useBlockForOC:addBlock];

// Will be the first3Point and No.4Points merge together,Defined inline Block As a function parameter
[self useBlockForOC:^(int x, int y){
    return x+y;
}];

Scenario 1: Passing parameters

viewController 1, testViewController controller 2, controller 1 jumps to controller 2, and then triggers event callback in controller 2 to modify the background color of the corresponding control of controller 1 to red?

testViewController

typedef void (^myBlock)(UIColor* color);
@property (nonatomic,copy)myBlock block1;

UIColor *color = [UIColor redColor];
//Pass in the parameter color to Block
self.block1(color);
[self.navigationController popViewControllerAnimated:YES];

viewController

//plan1
    testViewController *testVC = [[testViewController alloc]init];
    testVC.block1 = ^(UIColor *color){
        label1.backgroundColor = color;
    };
    [self.navigationController pushViewController:testVC animated:YES];

//plan2
    //When self is used in block, it is necessary to add _weak keyword to self to avoid circular calls.

    __weak typeof(self) weakself = self;//Equivalent to the next line of code
    //__weak UIViewController* weakself = self;
    testViewController *testVC = [[testViewController alloc]init];
    testVC.block1 = ^(UIColor *color){
        weakself.label2.backgroundColor = color;
    };
    [self.navigationController pushViewController:testVC animated:YES];

When using self in Block code blocks, be careful to avoid circular applications.

Q: What about a good girlfriend? Look, there's a problem with girlfriends.
One day, when your girlfriend was shopping Taobao, she said to you, "This bag is beautiful. Can you buy it for me?" Kiss you! In the face of sugar bombardment bombardment, you silently login to your Alipay account and confirm the payment button.
Girlfriend wants to buy things entrusted to you to buy, this is a typical case of agency model, also can be achieved by block.
1) Implementation of proxy mode

    girlFriends *gf = [girlFriends shareInstance];
    gf.delegate = self;

    [gf buyALadiesBackpackForMe];

2) Using Block

    __weak typeof(self) weakself = self;

    //block assigns values first, then uses them
    girlFriends *gf = [girlFriends shareInstance];
    //[gf buyAnotherLadiesBackpackForMe]; //wrong write place
    gf.buyBlock = ^(NSString *goods){
        NSString *tempStr = [NSString stringWithFormat:@"%@❤️❤️❤️������",goods];
        [weakself.label4 setText:tempStr];
    };
    [gf buyAnotherLadiesBackpackForMe];

    if (timer.isValid == YES) {
        [timer invalidate];
    }

3. Implementation using notification mode

    //tips: Register observers before sending notifications

    girlFriends *gf = [girlFriends shareInstance];
    //[gf buyAnyoneLadiesBackpackForMe];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(buyLVAction:) name:@"buybag" object:nil];

    [gf buyAnyoneLadiesBackpackForMe];


-(void)dealloc{
    //Observers who remember the release notice
    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"buybag" object:nil];
}

Scenario 2: Block as a parameter

girlFriends *gf = [girlFriends shareInstance];
    [gf buyMoreLadiesBackpackForMe:^float(int loveNumber) {
        //
        NSLog(@"520");
        float result = 520+(float)loveNumber/10000;
        NSLog(@"%.4f",(float)loveNumber/10000);
        NSString *tempStr = [NSString stringWithFormat:@"%.4f❤️❤️❤️������",result];
        [_label6 setText:tempStr];

        return result;

    }];

    if (timer.isValid == YES) {
        [timer invalidate];
    }

girlFriends.m
-(void)buyMoreLadiesBackpackForMe:(myLoveBlock2)ablock{
    float result = ablock(1314);
    NSLog(@"%.4f",result);

}

Scenario 3: Block as a return value

Recursive calls are used to represent the call and implementation of functions with Block as their return value.

call
[self digui:3];
//Realization
- (int)digui:(int)number{
    if (number <= 2 && number > 0) {
        return number;
    } else {
        int tempResult = [self digui:number-1];
        return number*tempResult;
    }
}

call
gf.setupTab5(3);
Realization
- (int(^)(int))setupTab5
{
__weak typeof (self)weakSelf = self;
int(^block)(int) = ^(int a){
_recursiveResult2 *= a;
NSLog(@"%d – %d", _recursiveResult2,a);
if (a>1) {
weakSelf.setupTab5(a-1);
//weakSelf setupTab5;
}
return _recursiveResult2;

};
return block;

}

Posted by twopeak on Tue, 02 Apr 2019 19:45:30 -0700