我写了一个从相机中获取图像的课程。它的标题如下:
typedef void(^ImageTakenCallback)(UIImage *image);
@interface ImageGetter : NSObject <UIImagePickerControllerDelegate, UIPopoverControllerDelegate>
{
UIImagePickerController *picker;
ImageTakenCallback completionBlock
}
-(void) requestImageInView:(UIView*)view withCompletionBlock:(void(^)(UIImage*))completion;
@end
正如您所看到的,我正在尝试在客户端代码中制作类似的内容:
[[[ImageGetter alloc] init] requestImageInView:_viewController.view withCompletionBlock:^(UIImage *image) {
// do stuff with taken image
}];
以下是我实现ImageGetter的方法:
-(void) requestImageInView:(UIView*)view withCompletionBlock:(ImageTakenCallback)completion
{
completionBlock = [completion copy];
picker = [[UIImagePickerController alloc] init];
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.delegate = self;
[view addSubview:picker.view];
}
- (void)imagePickerController:(UIImagePickerController *)picker_
didFinishPickingImage:(UIImage *)image
editingInfo:(NSDictionary *)editingInfo
{
[picker.view removeFromSuperview];
picker = nil;
completionBlock(image);
}
问题是因为我正在使用ARC,所以在调用-requestImage...
后会立即取消分配ImageGetter的实例,因此picker
的弱代表变为nil
。
解决此类问题的常用方法有哪些?
我可以看到一些方法,但是,它们似乎都不是正确的:
requestImage...
,它将创建ImageGetter实例,保留它们,重定向requestImage...
调用,从它们获取回调并释放。这似乎是最一致的方式,但这样的小代码是不是有点复杂?那么我怎样才能建立这样一个类?
答案 0 :(得分:1)
您可以通过创建和发布“自我引用”来处理ImageGetter
类中的内容。
在实现文件的类扩展中,声明一个属性
@interface ImageGetter ()
@property (strong, nonatomic) id selfRef;
@end
在requestImageInView:
中,设置self.selfRef = self
以防止重新分配。
在完成方法中,设置self.selfRef = nil
。
备注:实际上即使使用ARC,你也可以管理保留计数:
CFRetain((__bridge CFTypeRef)(self)); // Increases the retain count to prevent deallocation.
CFRelease((__bridge CFTypeRef)(self)); // Decreases the retain count.
但我不确定这是否被认为是ARC的“良好编程”。 欢迎任何反馈!
答案 1 :(得分:0)
如果在切换到ARC时引入了此问题,我应该选择选项1,并将其定义为强属性。
然而,行为与您在选项1中描述的有点不同:将属性设置为nil,并不意味着对象立即被释放,它只会导致零售额的减少。 ARC将处理这个问题,一旦所有引用的对象都“释放”它,对象就会被释放。
答案 2 :(得分:0)
您可以使用以下策略:
ImageGetter* imgGetter = [[ImageGetter alloc] init];
[imgGetter requestImageInView:_viewController.view withCompletionBlock:^(UIImage *image) {
// do stuff with taken image
[imgGetter releaseCompletionBlock]; // With this line, the completion block will retain automatically imgGetter, which will be released after the release of the completionBlock.
}];
在ImageGetter实现类中,创建一个可以在块内调用的方法。
-(void) releaseCompletionBlock
{
completionBlock = nil;
}