IOS of the block, little experience

IOS development as a programmer, never used block is impossible. This time I explore is block principle, but some deeper stuff, I was not very clear, the future with a better understanding of block will slowly improve.

  The first question, what is the block?

  We will use the block, but what block is it, this is first of all to clarify the concept. Although, what does not affect us use it, but figuring out the principles that we can better to use it, I think as a programmer, you need to keep things the principle of accountability of mind?

  block is essentially an object. But you can also say it is a code block, closure, inline functions, function pointers ... there are many called, it may, it is called here, is wrong or inaccurate, but I personally feel that from Functionally, so to understand. However, in order to respect oc, or call block it, block is the block. Other languages ​​have similar block syntax closure as javascript function inside a function, java code block, the C function pointers. Like, put a piece of code in advance here, and then come back when you need to call. We know that the code execution is called in sequence, that is, we often say that the process-oriented. But the reverse can block calls. But the block can be written in function inside, you can also say that it is a function of the function, which is a special function. Here we look at an example.

 
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        int i = 0; void (^block)() = ^(){ NSLog(@"%i", i); }; block(); } return 0; }
 

  first on the block i = 0; later, but it is not performed immediately, using the block (); which was performed after this is the block. As for the block nature, to'll come back.

  The second question, Why block?

  Although it is known what a block, but why do we use it? Under what circumstances do with? This issue is also very important to master his application scenarios, we can make good use of it.

  The most common case, the network request. When calling network API requests data server, we do not know when it will be completed, the program at this time it is impossible to stop and wait for the request to complete before continuing to run, this is certainly not acceptable. When the request is successful, to perform some operations, this time we need to do a thing, is to perform a piece of code has been prepared in advance. This situation is not exactly coincide with the block yet, block is not to do this thing right? Some would say that with the agent can do ah, yes, the agent can also achieve operational needs of this scenario. But it has the advantage of simplicity block, after the agent talk.

  As another example, you write a page, you can click the button on the page, but the Click event is only after the user point of conflict with the law, and you want to put the controller in response to an event processing (it follows the MVC design pattern). This time, you can also use block.

  In general, when you need to use callback procedures, you will use block clear thinking, concise code.

  The third question, How to block?

  The definition of 1.block: void (^ a) () = ^ () {};

 
= Foregoing:
     void : return type; 
    () (): syntax structure, a first block inside the brackets is the name, which is the second bracket parameter list, the parameter list, and c java or written as; for example: int I, char c ... ^ : caret, block identifies a: block name, like the name of the function, the name of the object is instantiated, it means a name; = behind the numbers: ^ is the block identification; () parameter list, when no parameters when, it may be omitted, but the "= " in front of () parameter list can not be omitted; {} to be executed on the inside, and finally add ";"
 

  The last call, a (); with calling methods to repeat itself. But it and the method has a very clear distinction, in the current class methods (or in the main function) can be called, but a different block, it is out of the scope in which it can not be called. Like variables, at this point, you are not thought to block the global award. Yes, let's look at the use of the global block.

  2. Global block

 
void(^globeBlock)(int, int);
void max(int, int); int main(int argc, const char * argv[]) { @autoreleasepool { globeBlock = ^(int i, int j){ printf("%d\n", i>j?i:j); }; max(1, 2); } return 0; } void max(int i, int j){ globeBlock(i,j); }
 

  The above code, we can see that declares a global block, to achieve the main function, called max method. This allows block can call in the big picture, but we must realize block, otherwise it will error. Global block principles and variables, not much to say here. There is a global block, then there is no static block it (do not hit me, I also guess), tried it, does not seem, I may not written.

  3. The block is used as a property of the object.

  Creating a class Block, .h file:

typedef void (^block)();
@interface Block : NSObject
@property (nonatomic, assign) block myBlock;
- (void)start;

  .m file

- (void)start{
    if (self.myBlock) {
        self.myBlock();
    }
}

  In the main function:

__block int i = 0;
Block *block = [Block new];
block.myBlock = ^{ i++; }; [block start];

  The wording is more commonly used, but can also cause some problems, such as: retain cycle, said this on the back.

  4. The block passed as variables.

  Examples or by the above classes. .h file:

- (void)show:(void (^)(NSInteger index))paramBlock;

  .m file

- (void)show:(void (^)(NSInteger index))paramBlock{
    paramBlock(1);
}

  the main function call:

[block show:^(NSInteger index) {
  NSLog(@"%li", index);
}];

  Such variables will be passed as a block, some network libraries which will often request this way.

  The concept of block mentioned above are some of the more basic things, the following will speak deeper theoretical block.

  1.retain cycle, circular references has been a commonplace problem, I believe 99.9 oc programmers have encountered, and can be a good solution, so I do not repeat them here, simply say something.

  retain cycle in the block is how generated. IOS since the introduction of the ARC, memory management becomes easy, but in some cases a headache. When the object A held object B, A released, B will be released with the release of A. So the question is, if B is also holding the object A, then A will be released as the B and release. Well, now A, B are waiting for the release of each other, hurt each other, ah, we do not release the results, this will result in a circular reference. With weak keyword modification, or by other methods, can be resolved, not much to say here, not much meaning.

  2. not form the block retain cycle. Like in UIKit UIView animation it will not block the formation retain cycle, as well as network library AF callback does not form retain cycle. Not formed retain cycle instructions no strong references to each other, UIView class method is invoked, the current controller can not be a strong reference class, and there is no cause retain cycle; as for AF inside how to do, to be honest I was not very clear, Haha, but also to look at. That being the case, then we will not cause block to write about circular references.

  2.1block there is no reference to the current controller

  View controller is TestViewController, has a property testView, TestView class code is as follows:

 
.h
@interface TestView : UIView
{
    NSString *str;
}
@property (nonatomic, copy) void(^block)(); @end .m #import "TestView.h" @implementation TestView - (void)dealloc{ NSLog(@"TestView 被释放"); } - (instancetype)initWithFrame:(CGRect)frame{ if (self = [super initWithFrame:frame]) { self.backgroundColor = [UIColor blackColor]; UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(click)]; [self addGestureRecognizer:tap]; } return self; } - (void)click{ if (self.block) { self.block(); } } @end
 

  TestViewController code is as follows:

 
- (void)dealloc{
    NSLog(@"TestViewController 被释放"); } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.view.backgroundColor = [UIColor whiteColor]; self.testView = [[TestView alloc] initWithFrame:CGRectMake(100, 200, 50, 50)]; self.testView.block = ^{ NSLog(@"没有引用self"); }; [self.view addSubview:self.testView]; }
 

  In the block, there is no reference to self, so after the current controller didDisAppear is destroyed.

2017- 07- 07 . 11: 16: 33.556 noRetainBlock [ 1319: 39876 ] TestViewController released 2017- 07- 07 . 11: 16: 33.557 noRetainBlock [ 1319: 39876] is released the TestView

  It will result in the case of circular references:

  Then TestViewController and TestView have not been released, resulting in the successful retain cycle. With weak self modified look on it, do not say here.

  2.2 method invocation, block as a variable, TestView code is as follows:

 
.h
@interface TestView : UIView
@property (nonatomic, copy) void(^block)();
+ (void)show:(void(^)())myBlock; @end .m #import "TestView.h" @implementation TestView - (void)dealloc{ NSLog(@"TestView 被释放"); } - (instancetype)initWithFrame:(CGRect)frame{ if (self = [super initWithFrame:frame]) { self.backgroundColor = [UIColor blackColor]; UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(click)]; [self addGestureRecognizer:tap]; } return self; } - (void)click{ if (self.block) { self.block(); } } + (void)show:(void (^)())myBlock{ myBlock(); } @end
 

  Controller call:

 
- (void)dealloc{
    NSLog(@"TestViewController 被释放"); } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. self.view.backgroundColor = [UIColor whiteColor]; [TestView show:^{ [self show]; }]; } - (void)show{ NSLog(@"show"); }
 

  Finally, the controller is released after disappearance

2017- 07- 07 11: 40: 15.482 noRetainBlock [ 1608: 52010 ] Show 2017- 07- 07 11: 40: 17.784 noRetainBlock [ 1608: 52010] TestViewController is released

  Do not ask me why testView not been released, because simply do not create the object, ha ha, was show it. There is also a writing I tried, can also cause retain cycle, will testView not to attribute controller, so that there will be no warning, but will eventually result in a circular reference, because the destructor is not called.

  Two or more circular references can be avoided, but looks like the first futile. Because not there some way self operation of this block looks like lacks significance, in the final analysis only write a. As there are no other writing, I have not studied. If found later on I will make. Next, we will look at the block in the end what it is.

  Before looking at the source code block, let's return to the code below, a closer look will find that, i was __block modified with.

__block int i = 0;
Block *block = [Block new];
block.myBlock = ^{ i++; }; [block start];

  So do not __block modifications look like? The answer is: If you change the value of the local variable i in the block, then the compiler will complain, do not compile, but you want to print or to other variable assignment or can. In this case, we look at two source code written above and below the wording of the main terminal cd to the folder where the file functions, use the command clang file -rewrite-objc main.m will get the main.cpp. You can view the source code.

  First, do not __block modify, print variable i:

 
int I = 0 ;
 void (^ Block) () = ^ {  NSLog ( @ " % I " , I);}; Block (); CPP file, at the end, because there are about 95,000 lines of code, take only the last part of the code struct __main_block_impl_0 { struct __block_impl impl; struct __main_block_desc_0 * Asc; int I; __main_block_impl_0 ( void * FP, struct __main_block_desc_0 desc *, int _i, int the flags = 0 ): I (_i) = {impl.isa & _NSConcreteStackBlock; impl.Flags = the flags; impl.FuncPtr = FP; Asc = desc;}}; static void __main_block_func_0 ( struct __main_block_impl_0 *__cself) {   int i = __cself->i; // bound by copy     NSLog((NSString *)&__NSConstantStringImpl__var_folders_s1_pqp17thd18bdxjswsty3xkmh0000gn_T_main_e26a0c_mi_0, i); } static struct __main_block_desc_0 { size_t reserved; size_t Block_size; } __main_block_desc_0_DATA = { 0, sizeof(struct __main_block_impl_0)}; int main(int argc, const char * argv[]) { /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; int i = 0; void(*block)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, i)); ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block); } return 0; }
 

  __Main_block_impl_0 source code and information in __main_block_desc_0 tell us the nature of the block, it has an isa pointer, block can be seen as an object, but you can not say that it is a object. In the source code can be seen, block a copy of the variable i, that is, outside and inside the Block i i is a two variables. Just like the relationship between arguments and parameters of the line. The reference line a copy argument, on the memory. oc optimized, changing the value of the local variable i directly. But after using __block modified variable i can be changed. This is why it, look at the following source code (look in the main):

 
__block int i = 0;
void(^block)() = ^{
    i++; NSLog(@"%i", i); }; block(); int main(int argc, const char * argv[]) { /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; __attribute__((__blocks__(byref))) __Block_byref_i_0 i = {(void*)0,(__Block_byref_i_0 *)&i, 0, sizeof(__Block_byref_i_0), 0}; void(*block)() = ((void (*)())&__main_block_impl_0((void *)__main_block_func_0, &__main_block_desc_0_DATA, (__Block_byref_i_0 *)&i, 570425344)); ((void (*)(__block_impl *))((__block_impl *)block)->FuncPtr)((__block_impl *)block); } return 0; }
 

  We can see __attribute __ ((__ blocks __ (byref))) __Block_byref_i_0 i = {(void *) 0, (__ Block_byref_i_0 *) & i, 0, sizeof (__ Block_byref_i_0), 0}; modified __block through the variable i becomes so, then in block i is (__Block_byref_i_0 *) & i, an address. Originally, when modified with __block of i incoming block which is an address, so you can change the value of i.

  In fact, there is the value of a variable can be modified in the block, the global variables, static variables. Note, however, changing the value of the variable of time to pay attention to the problem of circular references.

  Summary: block is a very interesting thing, master it, to figure out the principle, in order to better use it.

Guess you like

Origin www.cnblogs.com/Free-Thinker/p/11249951.html