我有一个UIViewController
IBOutlet
,UILabel
,标签在XIB中连接。
#import <Foundation/Foundation.h>
@interface MyViewController : UIViewController {
IBOutlet UILabel *aLabel;
}
@end
根据iOS Programming: The Big Nerd Ranch Guide (2nd Edition)第7章
当[MyViewController]重新加载其视图时,将从XIB文件创建一个新的UILabel实例。
因此,它建议在viewDidUnload
中发布标签。
- (void)viewDidUnload {
[super viewDidUnload];
[aLabel release];
aLabel = nil;
}
作为一名C#程序员,我已经把它鼓起来,为事物分配nil / null是没有意义的。虽然我可以看到它在Objective-C中更有意义,但它仍然会略微提升我对代码美感的感觉*。我删除了它,一切正常。
但是,当我尝试加载NIB时尝试对MKMapView
应用程序错误EXC_BAD_ACCESS
执行类似的操作。
#import <Foundation/Foundation.h>
@interface MyViewController : UIViewController {
IBOutlet MKMapView *mapView;
}
@end
- (void)viewDidUnload {
[super viewDidUnload];
[mapView release];
mapView = nil; // Without this line an exception is thrown.
}
为什么mapView
未设置为nil
时出现错误,而aLabel
未设置为nil
时出现错误?
*我意识到我需要调整我对新语言的代码美感,但这需要时间。
事实证明,我对aLabel
未被引用感到错误。不知道是什么让我觉得不是。
然而,这仍然留下了为什么在加载NIB时它们被引用的问题。
设置字段或属性后,会向旧值发送释放消息(合成属性集方法发送释放消息,或setValue:forKey:
发送消息(如果是字段)。由于旧值已经发布,因此会生成EXC_BAD_ACCESS
。
答案 0 :(得分:2)
viewDidUnload
。
在View堆栈中,可能存在设备可以通过释放未使用的对象来释放内存的情况。想象一下,你有一个带有许多视图控制器的导航堆栈。堆栈中较低的接口视图控制器无法访问,但仍在使用内存。所以通常一个好主意是找出任何无法访问的界面元素。然后在需要时使用viewDidLoad重新加载它们。
通常在ViewDidUnload
中,您应该释放从Nib文件创建或在ViewDidLoad
方法中分配的任何视图对象
您的mapView
正在抛出异常,因为您的视图控制器正在尝试访问MapView
,但mapView
已被释放。将插座设置为nil时,将忽略发送给它的任何消息。
答案 1 :(得分:2)
这是因为内存管理,特别是缺少垃圾收集。
在C#中(如您所知),不再包含不在范围内的对象。在objective-c中,这不会发生。完成后,您必须依赖保留/释放来告诉对象。
你的mapView bug展示的objective-c引用计数方法有一个缺点。在对象上调用release
可能会导致它被释放。但是,你指向对象的指针仍然指向同一个地方 - 你的对象就不再存在了。
例如
// We create an object.
MyObject *object = [[MyObject alloc] init];
// At this point, `object` points to the memory location of a MyObject instance
// (the one we created earlier). We can output that if we want :
NSLog(@"0x%08X", (int)myObject);
// You should see a number appear in the console - that's the memory address that
// myObject points to.
// It should look something like 0x8f3e4f04
// What happens if we release myObject?
[myObject release];
// Now, myObject no longer exists - it's been deallocated and it's memory has been
// marked as free
// The myObject pointer doesn't know that it's gone - see :
NSLog(@"0x%08X", (int)myObject);
// This outputs the same number as before. However, if we call a method on myObject
// it will crash :
NSLog(@"%@", myObject);
在objective-c中,如果您尝试在nil
上调用消息,则不会发生任何事情。因此,如果每次完成对象并在其上调用release时,您还应将其设置为nil
- 这意味着如果您再次尝试使用该指针,它将不会崩溃!