我遇到过这个问题几次,想知道正确的方法。
举个例子,假设我正在编写一个iPhone应用程序,我想要一个使用块的自定义警报视图类。
所以我写了这个课,然后在我的代码中我去了:
MyAlertView *alert = [MyAlertView alertWithBlahBlahBlah...];
[alert addButton:@"button" withBlock:^{ ... }];
[alert show];
在警报视图类的某个地方,我们有
- (void)addButton:(NSString *)button withBlock:(void (^))block {
[_blocks setObject:[block copy] forKey:button];
}
- (void)show {
... drawing stuff ...
UIButton *button = ...
[button addTarget:self selector:@selector(buttonPressed:) ...];
...
}
- (void)buttonPressed:(id)sender {
((void (^)())[_blocks objectForKey:[sender title]])();
}
因此,警报视图现在显示就好了。问题是,如果我点击一个按钮,它会尝试将buttonPressed:
选择器发送到显示的MyAlertView
对象。但是,MyAlertView
此时已从超级视图中删除。 ARC决定由于警报视图不再由任何人拥有,因此应该取消分配,而不知道按钮将来需要发送消息。点击按钮时会导致崩溃。
将警报视图保留在内存中的正确方法是什么?我可以使MyAlertView
对象成为使用它的类的属性,但这有点愚蠢(如果我想一次显示两个警报怎么办?)。
答案 0 :(得分:7)
如果某个对象留在内存中,并且您没有对它的引用,则称为内存泄漏。正如我在评论中所说,你需要保持一些类型的引用,以便a)它不被释放,b)你可以向它发送消息,c)你可以解除分配它在你的课程被解除分配之前。
最明显的方法是使用班级中的属性。既然你说你不想这样做(也许你有很多),那么另一种可能的解决方案是保留一组你计划重用并最终解除分配的缓存对象。
答案 1 :(得分:1)
我认为您可以使用performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay
在runloop中保留警报视图。
实际上,我刚刚使用此技能遇到了UIAlertView的包装器实现。
查看UIAlertView input wrapper了解更多详情。
答案 2 :(得分:1)
很简单,你打破了内存管理规则。 ARC不会改变规则,只是自动化它们。如果你需要一个物体来保持活力,它需要一个拥有者。应用程序对象图中的每个对象,一直回到应用程序委托,都有一个所有者。可能并不明显该所有者是什么(有时所有者可能是自动释放池),但有一个。
如果你想要这个视图,它需要由某些东西拥有,即使它不是“当前正在使用”。如果它在屏幕上,它应该是视图层次结构的一部分。如果不是,理想的所有者很可能是创建它的对象。