如果稍后我会检测到触摸它,我应该释放添加到我的视图中的 UIImageView 吗?

Posted

技术标签:

【中文标题】如果稍后我会检测到触摸它,我应该释放添加到我的视图中的 UIImageView 吗?【英文标题】:Should I release an UIImageView added to my view if I will detect touch on it later on? 【发布时间】:2011-02-06 22:31:44 【问题描述】:

我了解到,如果您创建了一个对象,那么您就拥有它,并且需要在完成后释放它。在这种情况下,我创建了一个 UIImageView 并将其添加到我的视图中,如下所示:

myImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"image.png"]];
[myImageView setFrame:CGRectMake(10,10,100,100)];
[self.view addSubview:myImageView]; 
[myImageView release];

如果我以后想在我的 touchEnded 方法中检测 myImageView 上的触摸:

if([touch view] == myImageView)
    NSLog(@"TOUCHED!");

这可行,但这是正确的,因为我现在在释放它后使用了 myImageView? 以及如何从之前添加的 self.view 中释放 myImageView?

【问题讨论】:

myImageView 是实例变量吗? 这是一个 IBOutlet UIImageView *myImageView,是一个 ivar 吗? @molle:如果它在您的@interface 中声明,是的。 是的,好的,谢谢! @BoltClock @molle 描述的是一个属性。它不是实例变量;两者是互斥的。 【参考方案1】:

Cocoa 内存管理的基本规则是,你应该保留那些你关心的东西,并释放那些你不关心的东西。有极少数例外可以防止保留循环(委托和数据源永远不会保留),但这是您应该遵循的规则。

在这种情况下,如果您将图像存储在 ivar 中,我会继续保留它,而不管它的超级视图将始终保留它,因此您不必“必须”这样做。但是如果视图从它的父视图中删除,你会得到一个悬空指针,然后你会崩溃,所以我通过保留来防御性地编写代码。如果你在这里使用了访问器(你应该这样做),那么这将是自动的并且更安全。

Apple 在 ios 中对此变得更加一致,改变了他们对 IBOutlets 的推荐。在 Mac 上,您不会保留您的 IBOutlets,但在 iOS 中,Apple explicitly instructs 您会这样做。这与您正在讨论的情况相似,我同意 Apple 采取更安全的方法。

【讨论】:

我以前没有看过那个文档(可能是因为我只是一个 iOS 开发者)。这会很有用,+1 我认为您应该更具体地了解 Objective C 中的内存管理(而不是 Cocoa...)。基本规则是您对您创建的事物(使用 alloc、new 或 copy。或者如果您发送保留)负责。换句话说,你拥有所有权。您的措辞过于宽松,会使问题的作者感到困惑。 @6NSString,您描述的是何时创建保留(三个神奇的词),但这并不能回答发帖者关于何时应该保留的问题。这就是我回答的重点。你保留那些你关心的东西,你不依赖别人为你保留它们。在 ObjC 中,您不对自己创建的东西负责。您对它们只有隐式保留(而不是显式保留)。引用计数的对象没有所有者;没有人对其生命周期“负责”,因为一个人负责新/删除。在 ObjC 中,所有的保持者都是平等的。 我同意保留我关心的内容是个好主意,但我认为我不同意你的论点。例如:如果我保留 imageview 并且它的 superview 被释放,我将不会获得指向我的 imageview 的悬空指针,但我仍然无法使用它,因为它不会“可见”,没有触摸等。在这种情况下,保留不能解决该问题。 :( 。如果我要接收触摸,我只需将 GestureRecognizers 添加到 imageview 并释放它。 @6NSString:关于否决票的好问题。我从来没有在一个问题上见过这么多。无论是谁这样做,这都太过分了。【参考方案2】:

只要您的 myUIImageView 对象的保留计数 > 0,它就会仍然存在并且您可以继续使用它。当您第一次将其添加为子视图时,它会收到一条保留消息,因此它的保留计数可能为 2。然后您将其发送释放,因此它的保留计数减少到 1。这意味着它仍然存在于内存中。现在,如果您再次发送 release 或发送removeFromSuperView,那么它的保留计数将为零,您将丢失它。

【讨论】:

好的,我明白了,所以什么时候应该是调用 removeFromSuperView 的好时机,你能在 dealloc 中调用它吗? +1 以对抗疯狂的反对票。 @molle,您几乎永远不会在 dealloc 中调用 removeFromSuperview 。您只会调用它来手动重组视图。 @6NSString 给出了 ObjC 所做的,他是正确的,但我不相信他在提出 you 应该做什么的建议。您应该保留您关心的部分,并在完成后释放它们。如果您将视图添加到超级视图并释放它,那么新的超级视图的问题就是在需要它时一直保留它。 我投了反对票,因为答案没有明确说明您永远不应向对象发送两次release 或向您刚刚释放的对象发送消息。 @6NSString 的回答是理论上的练习,而不是你在实践中应该做的任何事情。【参考方案3】:

行为不稳定,有时您可能会看到它有效,有时您会崩溃。

如果您想使用该变量指向您的图像视图,请保留 ivar(通过使用 retain 属性)。这样可以确保图像视图可供控制器类使用。

【讨论】:

为什么投反对票?这个答案比大多数其他答案更正确。 @kubi:一些流氓反对者,我不知道是谁。感谢您的回复(我想您的支持!)不过,我正要完全删除我的答案。【参考方案4】:

假设 myUIImageView 是您的自定义 UIView 子类的 ivar,只要您的图像视图保持在其父视图中,您的代码就可以工作。图像视图实例可能会被释放,并且您可能会以引用已释放对象的无效指针结束。充其量你会崩溃。

根据内存管理指南,您应该考虑您的图像视图 自定义 uiview 子类关系:

强参考。您拥有图像视图(在创建时),并负责保留/释放它 弱参考。您不拥有该对象,因此保留对它的引用可能很危险。

在您的情况下,它可能是一个强有力的参考。您的 myUIImageView ivar 应该是对象的非原子保留属性。

【讨论】:

【参考方案5】:

如果您以后需要访问您的UIImage,您需要保留它。

如何执行此操作由您自行决定,但您不应该依赖 UIView 为您重新训练您的对象。您创建的情况目前有效,但很脆弱。

【讨论】:

以上是关于如果稍后我会检测到触摸它,我应该释放添加到我的视图中的 UIImageView 吗?的主要内容,如果未能解决你的问题,请参考以下文章

长按和触摸开始

UITextView应检测链接,否则应传播触摸以查看下面的链接

如何检测“长按”

检测到浏览器没有鼠标且仅触摸

检测 UITableViewCell 子视图内的触摸

如何使用 UIGesture 将 UIImage 添加到应用程序中的大多数视图。