【问题标题】:Block leak with __block variable使用 __block 变量阻止泄漏
【发布时间】:2015-03-12 02:42:34
【问题描述】:

我已经确定在requestContentEditingInputWithOptions: 方法中/上发生了很大的内存泄漏。如果我理解正确,它会发生在 img 变量上。如果我将其设为__block __weak,则在我将其分配为(img = [UIImage...]) 之后,该图像已经为零。我在某个地方很傻吗?或者我将如何避免这种内存泄漏?

- (UIImage*) getRightlySizedImgFromAsset:(PHAsset*)asset {

    __block UIImage *img;


    PHContentEditingInputRequestOptions *coptions = [PHContentEditingInputRequestOptions new];
    coptions.canHandleAdjustmentData = ^BOOL(PHAdjustmentData *adjustmentData) { return NO; };

    //semaphore used so the block runs synchronously and I can return img from this method at the end
    dispatch_semaphore_t sem = dispatch_semaphore_create(0);

    [asset requestContentEditingInputWithOptions:coptions completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {
        NSURL* url = [contentEditingInput fullSizeImageURL];
        int orientation = [contentEditingInput fullSizeImageOrientation];

        CIImage* inputImage = [CIImage imageWithContentsOfURL:url options:nil];
        inputImage = [inputImage imageByApplyingOrientation:orientation];
        CIContext *context = [CIContext contextWithOptions:nil];

        img = [UIImage imageWithCGImage:[context createCGImage:inputImage fromRect:inputImage.extent]];

        dispatch_semaphore_signal(sem);
    }];
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);


    if (needToDoSomethingWithImg){
        [self doSomethingWithImage:img];
    }


    return img;
}

【问题讨论】:

  • 与泄漏无关,但使用信号量使异步函数同步运行几乎总是一个坏主意。他们将其设为异步是有原因的。使用异步模式(例如提供您自己的完成处理程序)而不是尝试直接返回图像。
  • 我同意 Rob 的观点。使用信号量使异步调用同步是荒谬的。你最终会阻止你的 UI,这是一个非常糟糕的主意。如果出现网络问题,您最多可以将 UI 锁定 2 分钟,这是非常糟糕的用户体验。您需要重新考虑您的设计。
  • 我对程序员不是太有经验,在我的情况下,目前无法想象一种非混乱的方式来做到这一点。我有大量的任务需要按正确的顺序发生,所有任务都发生在 bg 队列上,并且从这种方法中继续执行这些任务对于整个任务来说似乎非常不合逻辑。但是,是的,也许我只是不知道某种模式。 .
  • 如果你真的想调试泄漏,你需要弄清楚[self doSomethingWithImage:]中发生了什么。此方法只是图片的一部分,您的 img 对象会转移到可能会被不必要地保留的其他地方。
  • 我在同一条评论中写道 - “所有都发生在 bg 队列上”,其中 bg = 背景 ) SO 是一个很好的资源,但我经常看到人们假设没有人知道关于阻止UI 线程.. 如果我知道信号量,我当然应该知道比冻结我的 UI 更好。感谢您在下面的回答和建议!

标签: ios objective-c memory-leaks objective-c-blocks weak-references


【解决方案1】:

通过静态分析器运行此代码(shift+command+B 或从“产品”菜单中选择“分析”)和它会指出createCGImage 正在创建一个您永远不会发布的CGImageRef

您可能想要执行以下操作:

CGImageRef imageRef = [context createCGImage:inputImage fromRect:inputImage.extent];
img = [UIImage imageWithCGImage:imageRef];
CFRelease(imageRef);

顺便说一句,您不应该同步执行此操作。你应该这样做:

- (void) getRightlySizedImgFromAsset:(PHAsset*)asset completionHandler:(void (^)(UIImage *))completionHandler {

    PHContentEditingInputRequestOptions *coptions = [PHContentEditingInputRequestOptions new];
    coptions.canHandleAdjustmentData = ^BOOL(PHAdjustmentData *adjustmentData) { return NO; };

    [asset requestContentEditingInputWithOptions:coptions completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {
        NSURL* url = [contentEditingInput fullSizeImageURL];
        int orientation = [contentEditingInput fullSizeImageOrientation];

        CIImage* inputImage = [CIImage imageWithContentsOfURL:url options:nil];
        inputImage = [inputImage imageByApplyingOrientation:orientation];
        CIContext *context = [CIContext contextWithOptions:nil];

        CGImageRef imageRef = [context createCGImage:inputImage fromRect:inputImage.extent];
        UIImage *image = [UIImage imageWithCGImage:imageRef];
        CFRelease(imageRef);

        // if this stuff needs to happen on main thread, then dispatch it to the main thread

        if (needtodosomethingwithit)
            [self doSomethingWithImage:image];

        if (completionHandler) {
            completionHandler(image);
        }
    }];
}

【讨论】:

  • 非常感谢!经过测试 - 泄漏消失了。我运行了分析仪,但是这个项目又大又乱(我在运行它时怀疑其他地方有泄漏),以至于我设法错过了这个!
【解决方案2】:

Rob 是对的。图像可能很大,所以这就是你有很大泄漏的原因。 Core Foundation 对象的经验法则是“创建规则”。在 Xcode 中搜索“创建规则”并阅读文章。它的要点是:

Core Foundation 函数的名称表明您何时拥有 返回对象:

在名称中嵌入“Create”的对象创建函数;

在名称中嵌入了“复制”的对象复制函数。如果 你拥有一个对象,你有责任放弃所有权 (使用 CFRelease)完成后。

【讨论】:

    猜你喜欢
    • 2014-07-11
    • 1970-01-01
    • 2019-07-17
    • 2015-09-14
    • 2013-12-06
    • 2016-01-01
    • 1970-01-01
    • 2011-11-12
    • 2018-03-11
    相关资源
    最近更新 更多