Hol*_*nce 17 iphone cocoa-touch memory-management objective-c
我想弄清楚以下情况推荐的做法是什么.某些对象(如CLLocationManager或MKReverseGeocoder)将其结果异步发送到委托回调方法.可以在回调方法中释放CLLocationManager或MKReverseGeocoder实例(或者它可能是什么类)吗?关键是你不再需要那个对象,所以你告诉它停止发送更新,将其委托设置为nil,然后释放对象.
伪代码:
@interface SomeClass <CLLocationManagerDelegate>
...
@end
@implementation SomeClass
...
- (void)someMethod
{
CLLocationManager* locManager = [[CLLocationManager alloc] init];
locManager.delegate = self;
[locManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
// Do something with the location
// ...
[manager stopUpdatingLocation];
manager.delegate = nil;
[manager release];
}
@end
Run Code Online (Sandbox Code Playgroud)
我想知道这种使用模式是否被认为总是好的,如果它被认为永远不行,或者它是否取决于类?
有一个明显的情况是释放委托对象会出错,即如果它在通知委托后需要做的事情.如果委托释放对象,则其内存可能会被覆盖并且应用程序崩溃.(这似乎是我的应用程序在特定环境中使用CLLocationManager时发生的情况,仅在模拟器上.我试图弄清楚它是否是模拟器错误或者我正在做的事情是否存在根本缺陷.)
我一直在寻找,我无法找到一个确定的答案.有没有人有权威的来源可以回答这个问题?
这是一个非常好的问题,我等了几个小时,希望有人会给出足够的答案,但因为没有人回复,我会试一试.首先,我会评论你的方法,然后我试着建议我如何解决这个问题.
发布这绝对是一个非常糟糕的主意 - 从而从其委托中释放一个对象.试想一下对象(如CLLocationManager)如何调用它们的委托 - 它们只是在某个方法的中间调用它们.当对委托的调用完成后,代码的执行将返回到已经解除分配的对象的方法.BAM!
让我们暂时忘记这是一个坏主意的事实.我看到两个选项如何轻松解决这个问题.首先,autorelease不是release给对象一个更长时间的垃圾邮件 - 它至少可以从代表返回.对于大多数情况来说这应该足够了,至少如果API的作者完成了她的工作并且在主API类后面封装了逻辑(在CLLocationManager的情况下它可能正在等待GPS关闭......).第二个选择是延迟发布(performSelector:withObject:afterDelay:想到),但这更像是一个解决方案,用于严格实现的API.
因此,如果发布它不是一个好主意,那么它是什么?
那么,你通过发布一个CLLocationManager真正获得了什么?释放这几个字节的内存不会导致您的应用程序在系统内存不足时终止.无论如何,你真的只需要一次当前用户的位置吗?
我建议你将与CLLocationManager相关的任务封装到一个单独的类中,甚至可能是一个单独的类 - 该类将成为它的委托,它将负责与CLLocationManager通信并通知你的应用程序结果(可能通过发送NSNotification).CLLocationManager将从该类释放dealloc,并且永远不会作为委托回调的结果.stopUpdatingLocation应该足够了,释放几个字节的内存 - 好吧,你可以在你的应用程序进入后台时这样做,但只要你的应用程序运行,释放这几个字节就不会显着改善内存消耗.
**加法**
委托人拥有作为委托的对象的所有权是自然而正确的.但是代理不应该因回调而释放对象.但是有一个例外,它是回调告诉你处理结束了.作为这样的一个例子是NSURLConnection的connectionDidFinishLoading:在文档其中规定'代表将接收没有另外的消息’.您可以让一个类下载一堆文件,每个文件都有不同的NSURLConnection(将您的类作为委托),分配和释放它们作为文件下载进度.
CLLocationManager的行为是不同的.您的程序中应该只有一个CLLocationManager实例.该实例由一些代码管理,可能是一个单例 - 一个可以在应用程序进入后台时释放,在唤醒时重新初始化.CLLocationManager它的生命周期与其管理阶层相同,管理阶层也充当代表.
不,这种模式总是被认为是错误的.它打破了可可内存管理规则.manager对象作为参数传入.您没有通过新的,分配或复制获得它,也没有保留它.因此,您不能发布它.