Objective c 属性的基础内存管理
对于不使用ARC的项目,假设我的类上有一个属性:Objective c 属性的基础内存管理,objective-c,memory-management,core-foundation,Objective C,Memory Management,Core Foundation,对于不使用ARC的项目,假设我的类上有一个属性: @property (assign) CGPathRef pathRef; 我有一个方法在某个点更新这个路径引用,例如: UIBezierPath *bezierPath = [UIBezierPath bezierPathWithOvalInRect:rect]; self.pathRef = CGPathCreateCopy(bezierPath.CGPath); 在我的dealloc中,我做了如下工作: - (void)dealloc
@property (assign) CGPathRef pathRef;
我有一个方法在某个点更新这个路径引用,例如:
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithOvalInRect:rect];
self.pathRef = CGPathCreateCopy(bezierPath.CGPath);
在我的dealloc中,我做了如下工作:
- (void)dealloc
{
CGPathRelease(self.pathRef);
self.pathRef = nil;
[super dealloc];
}
当运行静态分析器时,我得到了使用cgpathlease
的线路的内存建议:
不正确的对象引用计数递减率不是
此时由调用方拥有
我认为我是在这里做一些事情,但这似乎是在解释如何将基础对象交给核心动画API。
<> P>是否有人对此提出建议,如何在没有静态分析器警告的情况下管理这个基础对象? < P>您不拥有属性访问器的返回值。改用实例变量
CGPathRelease(_pathRef);
或者(最好)您可以自己实现访问器方法并包括内存管理
- (void)setPathRef:(CGPathRef)val
{
if (_pathRef)
{
CGPathRelease(_pathRef);
_pathRef = NULL;
}
if (val)
{
_pathRef = CGPathCreateCopy(val);
}
}
您不拥有属性访问器的返回值。改用实例变量
CGPathRelease(_pathRef);
或者(最好)您可以自己实现访问器方法并包括内存管理
- (void)setPathRef:(CGPathRef)val
{
if (_pathRef)
{
CGPathRelease(_pathRef);
_pathRef = NULL;
}
if (val)
{
_pathRef = CGPathCreateCopy(val);
}
}
在这个场景中,另一个明显的解决方案是只使用
UIBezierPath
对象,它使您摆脱了CGPathRef
create/release逻辑的杂草,绕过了静态分析器的特性。因此,定义一个属性:
@property (nonatomic, retain) UIBezierPath *bezierPath;
然后,当您要设置它时:
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithOvalInRect:rect];
self.bezierPath = bezierPath;
当您需要CGPath
时,只需从UIBezierPath
中抓取即可,例如:
CGContextAddPath(context, self.bezierPath.CGPath);
然后在dealoc
中,您可以释放它:
- (void)dealloc
{
[_bezierPath release];
[super dealloc];
}
这样,您可以享受对象内存语义的简单性,可以使用一些<代码> UIBezierPath 的便利方法,可以使用不适用于核心基础类型的其他技术(例如,代码> AutoLeleS/<代码>),但是每当您需要时,仍然可以获得<代码> CGPath < /代码>。p>
有时你必须使用戴伦(+ 1)所建议的技术之一,特别是当没有与核心基础类型相对应的逻辑对象时,但是在这个<代码> CgPaTRAFF 示例中,我通常使用<代码> UIBezierPath < /Cord>对象。考虑到您已经从一个UIBezierPath
对象开始,它甚至更加引人注目。在这个场景中,另一个明显的解决方案是只使用UIBezierPath
对象,它使您摆脱了CGPathRef
创建/发布逻辑的杂草,并绕过了这个静态分析器特性。因此,定义一个属性:
@property (nonatomic, retain) UIBezierPath *bezierPath;
然后,当您要设置它时:
UIBezierPath *bezierPath = [UIBezierPath bezierPathWithOvalInRect:rect];
self.bezierPath = bezierPath;
当您需要CGPath
时,只需从UIBezierPath
中抓取即可,例如:
CGContextAddPath(context, self.bezierPath.CGPath);
然后在dealoc
中,您可以释放它:
- (void)dealloc
{
[_bezierPath release];
[super dealloc];
}
这样,您可以享受对象内存语义的简单性,可以使用一些<代码> UIBezierPath 的便利方法,可以使用不适用于核心基础类型的其他技术(例如,代码> AutoLeleS/<代码>),但是每当您需要时,仍然可以获得<代码> CGPath < /代码>。p>
有时你必须使用戴伦(+ 1)所建议的技术之一,特别是当没有与核心基础类型相对应的逻辑对象时,但是在这个<代码> CgPaTRAFF 示例中,我通常使用<代码> UIBezierPath < /Cord>对象。考虑到您已经从一个UIBezierPath
对象开始,它更引人注目。+1关于您的第一个解决方案,除了CGPathRelease(_pathRef)
中的dealoc
中的cgpathRef=CGPathCreateCopy(bezierPath.CGPath)
之外,您显然也会使用ivar进行分配代码>。这消除了另一个静态分析器警告。关于自定义setter解决方案,虽然它具有一定的优雅性(a),但除非您将属性定义为非原子的,否则您将使用此setPathRef
获得警告;(b)有一个assign
属性实际上参与了retain
类似的行为,这让人隐约感到不舒服(尽管,你显然不能对非对象使用retain
),所以我建议在属性声明中发表评论来说明这一点。嗨,@Rob,请您解释一下,如果该属性被定义为原子属性
,他为什么会收到警告?此外,代码的哪一部分表明它正在从事类似于保留
的行为,尽管它是分配
?谢谢。@Unheilig原子问题源于这是一种同步机制。但是合成的getter不可能将原子锁定与自定义setter相协调,因为它无法确切地知道自定义setter在做什么。@Unheilig关于类似retain
-的行为,也许我应该说类似copy
-的行为,但基本问题是相同的。您有一个setter,它正在释放旧值并创建一个具有+1保留计数的副本。这不是assign
memory语义。这就是copy
内存语义。通常应该声明反映setter实际行为的属性内存语义。+1关于您的第一个解决方案,除了cgpathlease(_pathRef)
中的dealloc
,您显然也会使用ivar进行赋值,例如\u pathRef=CGPathCreateCopy(bezierPath.CGPath);
。这消除了其他静态分析器警告。关于您的自定义setter解决方案,虽然它具有一定的优雅性(a)除非您将属性定义为非原子的,否则您将得到此setPathRef
的警告;以及(b)有一个assign
属性实际上参与了retain
类行为,这让人隐约感到不舒服(不过,您显然不能使用<