Objective c 属性的基础内存管理

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

对于不使用ARC的项目,假设我的类上有一个属性:

@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
类行为,这让人隐约感到不舒服(不过,您显然不能使用<