本文主要是介绍函数参数是block,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一、函数参数是block定义
在 Objective-C 中,编写两个函数,一个导致循环引用,另一个避免循环引用是一个很好的练习来理解循环引用和如何避免它们。
造成循环引用的例子:
// MyClass.h
@interface MyClass : NSObject
@property (nonatomic, strong) void (^myRetainedBlock)(void);
- (void)setBlockThatRetainsSelf:(void (^)(void))block;
@end// MyClass.m
@implementation MyClass
- (void)setBlockThatRetainsSelf:(void (^)(void))block {// 这里 self 持有 myRetainedBlock,而 myRetainedBlock 又捕获了 selfself.myRetainedBlock = block;block(); // 执行 block
}// MyClass 中的其他方法
- (void)doSomething {NSLog(@"Doing something...");
}@end// 使用 MyClass 和设置 block 的例子
MyClass *myObject = [[MyClass alloc] init];
[myObject setBlockThatRetainsSelf:^{[myObject doSomething]; // 这里 block 捕获了 myObject
}];
在这个例子中,MyClass
的一个实例 myObject
设置了一个 block,这个 block 内部引用了 myObject
。由于 MyClass
对这个 block 有一个强引用属性 myRetainedBlock
,这造成了一个循环引用,因为 myObject
强引用了 block,而 block 也强引用了 myObject
。
不造成循环引用的例子:
// MyClass.h
@interface MyClass : NSObject
@property (nonatomic, copy) void (^myBlock)(void);
- (void)setBlockThatDoesNotRetainSelf:(void (^)(void))block;
@end// MyClass.m
@implementation MyClass
- (void)setBlockThatDoesNotRetainSelf:(void (^)(void))block {// 使用弱引用来避免循环引用__weak typeof(self) weakSelf = self;self.myBlock = ^{// 在 block 内部将弱引用升级为强引用__strong typeof(weakSelf) strongSelf = weakSelf;[strongSelf doSomething]; // 使用升级后的强引用};block(); // 执行 block
}// MyClass 中的其他方法
- (void)doSomething {NSLog(@"Doing something...");
}@end// 使用 MyClass 和设置 block 的例子
MyClass *myObject = [[MyClass alloc] init];
[myObject setBlockThatDoesNotRetainSelf:^{[myObject doSomething]; // 这里 block 不捕获 myObject
}];
在这个例子中,为了避免循环引用,我们使用 __weak
来创建 self
的弱引用 weakSelf
然后在 block 内部使用这个弱引用。通过这种方式,block 不会强引用 myObject
,避免了循环引用。
请注意,在第二个例子中,即使我们的目的是避免循环引用,传递给 setBlockThatDoesNotRetainSelf:
方法的 block 仍然不应该捕获 myObject
。这是因为我们已经在方法内部定义了一个适当的 block,它只捕获 weakSelf
。如果我们的 block 参数捕获了 myObject
,我们将不得不确保它是以正确的方式(例如使用 weakSelf
)来捕获 myObject
。
二、应用:
在实际的 iOS 开发中,使用带有 block 参数的函数或方法很常见,特别是在处理异步操作、回调、动画、网络请求等场景时。以下是一些具体的情况,说明何时需要正确处理 block 以避免或造成循环引用:
1. 网络请求和回调
当你执行一个网络请求并希望在请求完成时执行某些操作,你通常会提供一个完成回调的 block。如果这个 block 捕获了发起请求的对象,并且这个对象又保留了这个 block(例如,作为一个属性),那么就有可能产生循环引用。
避免循环引用的例子:
// 假设你有一个网络请求管理器
@implementation NetworkManager- (void)fetchDataWithCompletion:(void (^)(NSData *, NSError *))completion {NSURLSession *session = [NSURLSession sharedSession];NSURL *url = [NSURL URLWithString:@"https://example.com/data"];__weak typeof(self) weakSelf = self;NSURLSessionDataTask *task = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {__strong typeof(weakSelf) strongSelf = weakSelf;if (!strongSelf) {return;}// 处理返回的数据if (completion) {completion(data, error);}// 可能还需要更新一些 strongSelf 的属性或状态}];[task resume];
}@end
在这个例子中,网络请求完成时的 block 没有捕获 self
,因此不会造成循环引用。
2. 动画
在 UIKit 中,执行动画时通常会使用 block 来定义动画结束后执行的操作。如果你在动画 block 中捕获了一个视图控制器或视图,并且这个对象又保存了这个 block,那么就可能产生循环引用。
避免循环引用的例子:
@implementation MyViewController- (void)animateView:(UIView *)view {__weak typeof(self) weakSelf = self;[UIView animateWithDuration:1.0 animations:^{// 执行一些动画view.alpha = 0.0;} completion:^(BOOL finished) {__strong typeof(weakSelf) strongSelf = weakSelf;// 动画完成后的操作if (finished) {[strongSelf animationDidComplete];}}];
}- (void)animationDidComplete {// 动画完成后的一些操作
}@end
在这个例子中,animateView:
方法中的 block 使用了 weakSelf
来避免捕获 self
,从而避免循环引用。
3. 委托和数据源
如果你的对象是另一个对象的委托或数据源,并且这个关系通过 block 定义,如果不小心,这也可能导致循环引用。
避免循环引用的例子:
@implementation DataSourceManager- (void)setupDataSourceWithConfigBlock:(void (^)(id config))configBlock {__weak typeof(self) weakSelf = self;self.dataSourceConfigBlock = ^{__strong typeof(weakSelf) strongSelf = weakSelf;id config = [strongSelf createDefaultConfig];if (configBlock) {configBlock(config);}};
}- (id)createDefaultConfig {// 创建和返回默认的数据源配置
}@end
在这个例子中,DataSourceManager
类设置了一个数据源配置 block,该 block 使用了 weakSelf
来避免捕获 self
,防止循环引用。
结论
总的来说,当你在一个对象的 block 属性或 block 参数中使用 self
时,你应该注意是否会造成循环引用。在大多数情况下,你应该希望避免循环引用,因为它会阻止对象被正确释放,导致内存泄露。使用 __weak
和 __strong
转换是管理循环引用的常用方法。不过,在特定情况下,如果你希望对象在 block 执行期间保持活跃状态,并且你有清晰的机制来打破这个循环,那么循环引用可能是可接受的。
这篇关于函数参数是block的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!