Previous iOS – Circular references

We know that circular references occur when two objects, A and B, strongly refer to each other. When A is released, B must be released, and WHEN B is released, A must be released. The way to break a circular reference that no one can release is for one party to weakly reference the other

As we know from the previous article, the key to circular references is: strong references to each other. If this requirement is not met, blocks will not cause circular references

Two simple examples:

@interface BlockViewController () @property (nonatomic, copy) NSString *nickname; @property (nonatomic, copy) void(^ testBlock1)(void); @property (nonatomic, copy) void(^ testBlock2)(void); @end @implementation BlockViewController - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor orangeColor]; Self ->Block, Block -> self self.testBlock1 = ^{NSLog(@"== self = %p",self); }; Self ->block self.testBlock2 = ^{}; } - (void)dealloc { NSLog(@"dealloc = %@", self); } @endCopy the code

CPP source code:

testBlock0

struct __BlockViewController__viewDidLoad_block_impl_0 { struct __block_impl impl; struct __BlockViewController__viewDidLoad_block_desc_0* Desc; BlockViewController *self; __BlockViewController__viewDidLoad_block_impl_0(void *fp, struct __BlockViewController__viewDidLoad_block_desc_0 *desc, BlockViewController *_self, int flags=0) : self(_self) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; }}; static void __BlockViewController__viewDidLoad_block_func_0(struct __BlockViewController__viewDidLoad_block_impl_0 *__cself) { BlockViewController *self = __cself->self; // bound by copy NSLog((NSString *)&__NSConstantStringImpl__var_folders_44_1ht3l6g55dv59_5s62wsv_bm0000gn_T_BlockViewController_439f5f_mi_0,self); } ((void (*)(id, SEL, void (*)()))(void *)objc_msgSend)((id)self, sel_registerName("setTestBlock1:"), ((void (*)())&__BlockViewController__viewDidLoad_block_impl_0((void *)__BlockViewController__viewDidLoad_block_func_0, &__BlockViewController__viewDidLoad_block_desc_0_DATA, self, 570425344)));Copy the code

testBlock1:

struct __BlockViewController__viewDidLoad_block_impl_1 { struct __block_impl impl; struct __BlockViewController__viewDidLoad_block_desc_1* Desc; __BlockViewController__viewDidLoad_block_impl_1(void *fp, struct __BlockViewController__viewDidLoad_block_desc_1 *desc, int flags=0) { impl.isa = &_NSConcreteStackBlock; impl.Flags = flags; impl.FuncPtr = fp; Desc = desc; }}; static void __BlockViewController__viewDidLoad_block_func_1(struct __BlockViewController__viewDidLoad_block_impl_1 *__cself) { } ((void (*)(id, SEL, void (*)()))(void *)objc_msgSend)((id)self, sel_registerName("setTestBlock2:"), ((void (*)())&__BlockViewController__viewDidLoad_block_impl_1((void *)__BlockViewController__viewDidLoad_block_func_1, &__BlockViewController__viewDidLoad_block_desc_1_DATA)));Copy the code

Or as follows: there is no circular reference, although the block holds self, self does not hold the block

    BlockViewController2 *vc = [[BlockViewController2 alloc] init];
    [self.navigationController pushViewController:vc animated:true];
    vc.testBlock10 = ^{
        NSLog(@"-----vc.testBlock10 = %p", self);
    };
Copy the code

2. Does UIView animation cause circular references

+ (void)animateWithDuration:(NSTimeInterval) Duration animations: Is a class method. The current controller cannot forcibly reference a class, so a circular reference cannot be formed

3. Whether it will cause circular references

Self. block = block(constrainMaker) self.block = block(constrainMaker) self.block = block(constrainMaker) self.block = block(constrainMaker) That’s why the view is holding the block, that’s why it’s circular

self.testButton = [UIButton buttonWithType:UIButtonTypeCustom]; [self.view addSubview:self.testButton]; [self.view mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self.view); make.centerY.equalTo(self.view); make.size.mas_equalTo(CGSizeMake(100, 50)); }]; Masonry source code: - (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block { self.translatesAutoresizingMaskIntoConstraints =  NO; MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self]; block(constraintMaker); return [constraintMaker install]; }Copy the code

4. Whether AFN will cause circular reference

AFN code is used in the project

    AFHTTPSessionManager * manager = [AFHTTPSessionManager manager];
    [manager POST:completeURL parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        if (success) {
            success(responseObject);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        if (failure) {
            failure(error);
        }
    }];
Copy the code

AFN source

- (NSURLSessionDataTask *)POST:(NSString *)URLString
                    parameters:(id)parameters
                      progress:(void (^)(NSProgress * _Nonnull))uploadProgress
                       success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
                       failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
    NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"POST" URLString:URLString parameters:parameters uploadProgress:uploadProgress downloadProgress:nil success:success failure:failure];

    [dataTask resume];

    return dataTask;
}

- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
                                       URLString:(NSString *)URLString
                                      parameters:(id)parameters
                                  uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
                                downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
                                         success:(void (^)(NSURLSessionDataTask *, id))success
                                         failure:(void (^)(NSURLSessionDataTask *, NSError *))failure
{
    NSError *serializationError = nil;
    NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
    if (serializationError) {
        if (failure) {
            dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
                failure(nil, serializationError);
            });
        }

        return nil;
    }

    __block NSURLSessionDataTask *dataTask = nil;
    dataTask = [self dataTaskWithRequest:request
                          uploadProgress:uploadProgress
                        downloadProgress:downloadProgress
                       completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
        if (error) {
            if (failure) {
                failure(dataTask, error);
            }
        } else {
            if (success) {
                success(dataTask, responseObject);
            }
        }
    }];

    return dataTask;
}
Copy the code

You can see that self does not hold the Manager, and the dataTask does not hold the Success and failure blocks, even though self is held in the block. Nor does it constitute a circular reference