保留UIImagePickerController的委托

时间:2013-11-13 12:18:28

标签: ios objective-c memory-management

我写了一个从相机中获取图像的课程。它的标题如下:

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

解决此类问题的常用方法有哪些?

我可以看到一些方法,但是,它们似乎都不是正确的:

  1. 从客户端代码中保留ImageGetter,例如,将其分配给强属性。这里的问题是:我无法通过在获取图像后将此属性设置为nil来释放它,因为这意味着在执行此对象的方法时将对象的保留计数设置为0。此外,我不想要不必要的属性(嗯,这不是一个大问题,但不过)。
  2. 为ImageGetter禁用ARC并在启动时手动保留并在将图像发送回回调后释放。
  3. 制作静态管理器ImageGetterManager,它将具有方法requestImage...,它将创建ImageGetter实例,保留它们,重定向requestImage...调用,从它们获取回调并释放。这似乎是最一致的方式,但这样的小代码是不是有点复杂?
  4. 那么我怎样才能建立这样一个类?

3 个答案:

答案 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;
}