当我使用静态方法从资产对象获取图像 exif 字典时发生内存泄漏,

it happened a memory leaks when I getting image exif dictionary from a asset object using a static method,

以下是导致内存泄漏的方法调用树

//get the exif info of image asset background
  @autoreleasepool {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    self.dataSource = [NSMutableArray new];
    __weak typeof(self) weakSelf = self;
    dispatch_async(queue, ^{
        for (int i = 0; i < self.selectImageList.count; i++) {
            PFALAssetImageItemData *dataEntity = weakSelf.selectImageList[i];
            //getting the object usering an image asset

            ImageExifInfoEntity *imageExifEntity = [ImageExifInfoEntity getAlbumImageFromAsset:dataEntity.imageAsset imageOryder:i];

            LOG(@"%@",imageExifEntity.description);
            [weakSelf.dataSource addObject:imageExifEntity];
        }

        //back main thread update views
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.collectionView reloadData];
            [self hideHud];
        });
    });
}

在这段代码中,我想使用静态方法和线程中的资产创建 ImageExifInfoEntity:

[ImageExifInfoEntity getAlbumImageFromAsset:dataEntity.imageAsset imageOryder:i];

该方法新建一个ImageExifInfoEntity类型的对象,并通过静态方法获取exif Dictionary

+(ImageExifInfoEntity *)getAlbumImageFromAsset:(ALAsset *)asset category:(NSString *)category imageOryder:(NSInteger)imageOrder{
   ImageExifInfoEntity *albumImage = [ImageExifInfoEntity new];
   ..........
   albumImage.imageSize     = [UIImage imageSizeWithAlasset:asset];
   albumImage.exifDic      = [ImageExifInfoEntity getExifInfoFromAsset:asset] == nil ? @{}:[ImageExifInfoEntity getExifInfoFromAsset:asset];
   ..........
}

最后,我在发生内存泄漏的地方使用这种方法得到了一个 exif 字典

+(NSDictionary *)getExifInfoFromAsset:(ALAsset *)asset {
   NSDictionary *_imageProperty;
   __weak ALAsset *tempAsset = asset;
   ALAssetRepresentation *representation = tempAsset.defaultRepresentation;
   uint8_t *buffer = (uint8_t *)malloc(representation.size);
   NSError *error;
   NSUInteger length = [representation getBytes:buffer fromOffset:0 length:representation.size error:&error];
   NSData *data = [NSData dataWithBytes:buffer length:length];
   CGImageSourceRef cImageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
   CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(cImageSource, 0, NULL);
   _imageProperty = (__bridge_transfer  NSDictionary*)imageProperties;
   free(buffer);
   NSLog(@"image property: %@", _imageProperty);
   return _imageProperty;

}

这是仪器分析结果

call tree

the final method that cause memory leaks

__bridge替换为__bridge_transfer,这样ARC就会负责释放内存

我觉得你应该打电话给CFRelease(cImageSource);来发布图片来源。见文件:https://developer.apple.com/library/ios/documentation/GraphicsImaging/Reference/CGImageSource/#//apple_ref/c/func/CGImageSourceCreateWithData

An image source. You are responsible for releasing this object using CFRelease.

CGImageSourceCreateWithData()是创建函数。

CGImageSourceRef cImageSource = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);

根据CF内存规则,必须用CFRelease()释放。