祝大家十一月快乐

好吧,我在项目上尝试了Xcode Build并进行了分析,结果显示出一些异常的泄漏,就我对Objective C的了解我还是无法接受。

所以我决定提出一个测试项目,并在这里询问。

MemoryTestController.h

@interface MemoryTestController : UIViewController{
  UIImageView *tstImageView;
}
@property(nonatomic,retain) UIImageView *tstImageView;
@end

MemoryTestController.m
@implementation MemoryTestController
@synthesize tstImageView;

- (void)viewDidLoad{
  [super viewDidLoad];

  self.tstImageView  = [[UIImageView alloc] //<==This object is leaking
                           initWithFrame:<SomeFrame>];
  self.tstImageView.image = [UIImage imageNamed:@"SomeImage.png"];
  [self.view addSubview:tstImageView];
  [tstImageView release];
}

-(void)dealloc{
  [tstImageView release];
  [super dealloc];
}
@end

当我尝试构建和分析时,clang静态分析器说

xx线上物体的潜在泄漏

罪魁祸首是
self.tstImageView  = [[UIImageView alloc]initWithFrame:<SomeFrame>];

我想我每次分配/保留时都会释放一次。我是否缺少某些东西,或者静态分析器有一些错误?

编辑:那里有泄漏吗?

好吧,我在仪器中使用Leak工具运行了上述项目。即使我尝试了很多次,也没有显示任何泄漏。我应该相信谁?静电分析仪或泄漏仪?

最佳答案

您的问题是如何释放它:

- (void)viewDidLoad{
  [super viewDidLoad];

  self.tstImageView  = [[UIImageView alloc] //<==This object is leaking
                           initWithFrame:<SomeFrame>];
  self.tstImageView.image = [UIImage imageNamed:@"SomeImage.png"];
  [self.view addSubview:tstImageView];
  [tstImageView release]; // << here
}

您应该这样做:
- (void)viewDidLoad{
  [super viewDidLoad];

  UIImageView * imageView  = [[UIImageView alloc] initWithFrame:<SomeFrame>];
  imageView.image = [UIImage imageNamed:@"SomeImage.png"];
  self.tstImageView  = imageView;
  [imageView release];
  [self.view addSubview:self.tstImageView];
}

该检查器是正确的,因为它不能假定该变量与您设置的变量相同。因此,在OP中使用的表单可能会导致引用计数不平衡,因为在ivar上发布消息时,ivar的值可能不是您为其分配的值。

对于UIImageView,这些情况不太可能发生,并且在您的程序上下文中也不太可能,但是这些示例应使您了解为什么检查器认为object-> ivar关联不可信:

在创建图像视图和通过ivar释放它的消息之间,您具有:
  self.tstImageView  = [[UIImageView alloc] initWithFrame:<SomeFrame>];
  self.tstImageView.image = [UIImage imageNamed:@"SomeImage.png"];
  [self.view addSubview:tstImageView];

1)通过设置器分配图像视图
2)通过吸气剂访问图像视图
3)添加到self.view时直接访问ivar

设置程序可能已复制或使用了缓存的值
  • UIImageView是一个不好的例子,但是检查器不知道通常如何传递类型-即使这样,(有时)它也会做出不安全的假设。

  • 最简单的例子是:
    - (void)setName:(NSString *)inName {
      NSString * prev = name;
      if (inName == prev) return;
      if (0 == [inName count]) name = @"";
      else name = [inName copy];
      [prev release];
    }
    
  • 同时,ivar拥有的值可能会发生变化。在这种情况下,这不太可能出现问题,但可以说,将图像视图添加为子视图可​​能最终会在添加子视图,替换或删除您传递的图像视图的过程/效果中回调并更改self。在这种情况下,您传递的变量视图将泄漏,并且用它替换的视图将具有负不平衡。

  • 这些都不会在您的示例中发生,但确实会在现实世界的程序中发生,并且检查器是根据局部性而不是属性来正确评估(检查器无法假设方法调用中发生的大部分事情)。在这种情况下,还鼓励一种良好的惯用风格。

    编辑:那里有泄漏吗?

    好吧,我使用
    仪器中的泄漏工具..即使我尝试也未显示任何泄漏
    很多次..我应该相信谁?静电分析仪或泄漏
    仪器?

    静态分析器表示存在潜在的泄漏,因为它无法保证遵循的引用/分配被正确保留/释放。您可以通过更改程序以使其看起来像我在示例中编写的那样,来保证引用计数正确并请使用静态分析器。

    您编写的方式使分析仪无法遵循参考。

    如果您没有泄漏,也没有僵尸,那就没有泄漏。但是该解决方案易于修复-并且程序在开发过程中可以进行更改。使用我发布的表单要容易得多,因此对于工具集和您来说,验证程序是否正确都更加容易。静态分析器并不总是正确的,但是您应该调整程序以使其满意,因为静态分析非常有用。我发布的程序对于人类来说也更容易理解和确认它是正确的。

    关于iphone - 静态分析仪显示错误泄漏? (XCode 4.0,iOS 4.3及更高版本),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7990977/

    10-09 16:28
    查看更多