使用 __block 变量阻止泄漏
Block leak with __block variable
我有一个很大的内存泄漏,我已经确定发生 in/on requestContentEditingInputWithOptions:
方法。如果我理解正确的话,它会发生在 img
变量中。如果我把它设为 __block __weak
,那么在我分配它 (img = [UIImage...])
之后,图像就已经是 nil 了。我在某个地方很傻吗?或者我将如何避免这种内存泄漏?
- (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;
}
运行这段代码通过静态分析器(shift+command+B 或从 "Product" 菜单中选择 "Analyze"),它会指出 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);
}
}];
}
Rob 说得对。图像可能很大,所以这就是你有大泄漏的原因。 Core Foundation 对象的经验法则是 "create rule." 在 "Create Rule" 上的 Xcode 中搜索并阅读文章。它的要点是这样的:
Core Foundation functions have names that indicate when you own a
returned object:
Object-creation functions that have “Create” embedded in the name;
Object-duplication functions that have “Copy” embedded in the name. If
you own an object, it is your responsibility to relinquish ownership
(using CFRelease) when you have finished with it.
我有一个很大的内存泄漏,我已经确定发生 in/on requestContentEditingInputWithOptions:
方法。如果我理解正确的话,它会发生在 img
变量中。如果我把它设为 __block __weak
,那么在我分配它 (img = [UIImage...])
之后,图像就已经是 nil 了。我在某个地方很傻吗?或者我将如何避免这种内存泄漏?
- (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;
}
运行这段代码通过静态分析器(shift+command+B 或从 "Product" 菜单中选择 "Analyze"),它会指出 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);
}
}];
}
Rob 说得对。图像可能很大,所以这就是你有大泄漏的原因。 Core Foundation 对象的经验法则是 "create rule." 在 "Create Rule" 上的 Xcode 中搜索并阅读文章。它的要点是这样的:
Core Foundation functions have names that indicate when you own a returned object:
Object-creation functions that have “Create” embedded in the name;
Object-duplication functions that have “Copy” embedded in the name. If you own an object, it is your responsibility to relinquish ownership (using CFRelease) when you have finished with it.