在 Objective-C 中保留计数和工厂方法

Posted

技术标签:

【中文标题】在 Objective-C 中保留计数和工厂方法【英文标题】:Retain count and factory methods in Objective-C 【发布时间】:2011-09-30 11:58:15 【问题描述】:

我之前一直在这个论坛上寻找创建工厂函数以从 nib 构造自定义视图的最佳方法(here 是我以前的帖子)

我现在使用以下代码:

+ (LoadingV *)loadingViewCopyFromNib 
   
    LoadingV *view = nil;   
    NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"LoadingV" owner:self options:nil];
    view = (LoadingV*)[nibViews objectAtIndex: 0];

    // Setting up properties
    CGRect frm = view.progress.frame;
    frm.size.width *=1.5;
    frm.size.height *=1.5;
    view.progress.frame = frm;
    view.waitLbl.text = NSLocalizedString(@"Please wait", @"");     
    return view;    <------- warning is here


// In .h file
...
LoadingView* loadV;
@property (nonatomic, retain) LoadingView* loadV;

// in .m file
@synthesize loadV;
...
self.loadV = [LoadingV loadingViewCopyFromNib];

当我构建和分析时,我收到以下有关工厂功能的警告:

/LPAPP/Classes/LoadingV.m:34:5 返回 +0 保留计数的对象 到预期 +1(拥有)保留计数的调用者

为什么会这样?我知道在函数中分配的局部变量不会超出其范围,除非它们被保留和自动释放。但在我的情况下,我没有创建一个新对象,只是返回一个对现有对象的引用。那么为什么我会收到警告呢?像这样进行是否安全:)

干杯 自动对焦

【问题讨论】:

显然分析器会在返回保留对象的前缀(init、copy 等)中计算“加载”。 我认为你是对的!将更改 API 名称并删除 Copy。过去的实现有所不同,然后在不注意命名约定的情况下对其进行了修改。欢呼 您使用的是哪个版本的 XCode?.. clang/llvm 3.0 (ios 5 beta) 将为 ARC/ARC 转换内置不同的命名约定处理,也许它有点小问题 我没有使用 XCode 4,因为我在安装它时遇到了糟糕的体验。我回到带有 SDK 4.3.3 的 XCode 3.2.5(或 4.3.1 不确定:p) 我刚刚测试了更改函数名称并删除 Copy 并且一切正常。不再警告!伙计们干杯 【参考方案1】:

虽然迈克是对的,但警告的原因完全不同。 您的方法名称包括“copy”,它被解释为返回 +1 保留计数(类似于 alloc、init)。请记住,一旦您过渡到 ARC,这可能会导致问题!

【讨论】:

这是不正确的,只有 'copy' 或 'mutableCopy' 的 前缀 它被解释为 +1 保留计数。 是的,苹果比其他人更喜欢记录一些“功能”......分析器的工作方式似乎有点不同......【参考方案2】:

当涉及到像NSArray 这样的集合类时,objectAtIndex: 和其他类似访问器返回的引用不能保证在父容器被释放时保持有效。换句话说,objectAtIndex: 不会返回自动释放的对象。

这意味着一旦它来自的数组被释放,你返回的指针可能最终会变得无效。

要解决此问题,请在您的退货声明中使用retain+autorelease

return [[view retain] autorelease];

更新:

我无法在我的 Xcode 版本中重现此警告。但也许马丁是正确的,您正在使用的 GCC/clang 版本错误地解释了“副本”。最新的 Xcode 和 gcc/clang 编译器不会出现此警告,并且规则是只有 prefix 的“copy”或“mutableCopy”被​​解释为返回 +1 保留对象。

【讨论】:

是的,你可能是对的,当然分析器是错误的——返回的对象在下一次自动发布之前是“好的”,除非改变 Objective-C 以识别 nibViews 已经通过超出范围。 分析仪没有错。是的,今天的实现细节使得对象将保持有效,但分析器只处理代码违反的对象所有权规则。如果将来某些底层实现发生变化,您的原始代码可能会停止工作。 实现在未来总是会改变,在不改变上述任何代码的情况下打破这一点。但当然,这样的更改会破坏很多应用程序(并不是说 Apple 会通过他们的更改破坏很多应用程序)。 顺便说一下,静态分析器到底在抱怨哪一行?我无法重现此分析器警告。 我认为从 objectAtIndex 返回的对象将保持活动状态,直到下一次自动释放,因为它是对已经在自动释放数组(nibViews)中的对象的引用。调用 self.loadV =... 甚至可以让它活得更久。这就是为什么我不确定警告并想问的原因。我将更改函数的名称并删除 Copy,因为我认为 Daniel R Hicks 有一个观点

以上是关于在 Objective-C 中保留计数和工厂方法的主要内容,如果未能解决你的问题,请参考以下文章

Objective-C 确定哪些对象保留另一个对象

Objective-C 自动引用计数和垃圾回收有啥区别?

有人能告诉我在objective-c中保留和释放到底做了啥吗?

为啥在启用 ARC 的项目中不需要维护保留计数

电子工票系统|RFID服装实时生产管理系统|工厂制衣服装生产管理软件工厂车间生产管理软件

如何从 Swift 调用 Objective-C 类的工厂方法?