Iphone 为什么在viewDidUnload中将nil分配给IBOutlets?
我有一个Iphone 为什么在viewDidUnload中将nil分配给IBOutlets?,iphone,objective-c,ios,cocoa-touch,uikit,Iphone,Objective C,Ios,Cocoa Touch,Uikit,我有一个UIViewController,它有一个IBOutlet,用于UILabel,标签连接在XIB中 #import <Foundation/Foundation.h> @interface MyViewController : UIViewController { IBOutlet UILabel *aLabel; } @end 作为一名C#程序员,我有一种强烈的感觉,那就是为事物指定nil/null是毫无意义的。虽然我可以看出Objective-C更具意义,但
UIViewController
,它有一个IBOutlet
,用于UILabel
,标签连接在XIB中
#import <Foundation/Foundation.h>
@interface MyViewController : UIViewController {
IBOutlet UILabel *aLabel;
}
@end
作为一名C#程序员,我有一种强烈的感觉,那就是为事物指定nil/null是毫无意义的。虽然我可以看出Objective-C更具意义,但它仍然略微削弱了我的代码美学感*。我把它取了下来,一切都很好
但是,当我尝试使用MKMapView
执行类似操作时,在尝试加载NIB时出现了应用程序错误EXC_BAD_ACCESS
#import <Foundation/Foundation.h>
@interface MyViewController : UIViewController {
IBOutlet MKMapView *mapView;
}
@end
为什么当mapView
未设置为nil
时会出现错误,而当aLabel
未设置为nil
时不会出现错误
*我意识到我需要调整我对新语言的代码审美感,但这需要时间
事实证明,我完全错了,
aLabel
没有被引用。不知道是什么让我觉得不是
然而,这仍然留下了一个问题,即为什么在加载NIB时引用它们
设置字段或属性时,将向旧值发送释放消息(合成属性集方法发送释放消息,或者
setValue:forKey:
发送消息(如果是字段)。由于旧值已被释放,这将导致EXC\u BAD\u ACCESS
viewDidUnload
通常在设备收到内存警告时调用
在视图堆栈中,可能存在设备可以通过释放未使用的对象来释放内存的情况。假设您有一个带有多个视图控制器的导航堆栈。堆栈下部的界面视图控制器不可访问,但仍在使用内存。因此,消除任何无法访问的接口元素通常是一个好主意。然后在需要时使用viewDidLoad重新加载这些文件
通常在ViewDidLoad
中,您应该释放从Nib文件创建的或在ViewDidLoad
方法中分配的任何视图对象
您的
mapView
正在引发异常,因为您的视图控制器正在尝试访问mapView
,但mapView
已被释放。当您将出口设置为nil时,发送给它的任何消息都将被忽略。这是因为内存管理,特别是缺少垃圾收集
在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
——这意味着如果再次尝试使用该指针,它不会崩溃 当我切换到控制器的视图时,在调用控制器的任何方法之前抛出异常。所以我的问题是,什么东西试图访问mapView
而不是试图访问aLabel
?根据我对前面答案的回答,我的问题是什么东西试图访问mapView
,而不是试图访问aLabel
?但事实上,如果有东西试图访问一个已经释放/解除分配的对象,我认为这仍然是一个糟糕的设计。正确的设计(这并不意味着将释放的对象设置为零)应该确保不会发生这种情况。@Rudy Velthuis这是防御:)你不知道你正在使用的apple框架/库中是否有bug-他们可能会尝试自己调用该对象,因此将其设置为nil
将保护你的代码不受其他错误的影响。(并不是说我不同意这是一个糟糕的设计!)@ICR你怎么知道没有任何东西访问你的标签-仅仅因为内存被释放并不意味着它被其他任何东西使用-也许标签被访问的方式不会导致崩溃;)@迪恩沃姆伯恩:对不起,这不是“防御编程”,而是“偏执编程”。更新时出现了错误。从iOS 6.0开始,viewDidUnload被折旧。在内存不足的情况下不再清除视图,因此永远不会调用此方法。
- (void)viewDidUnload {
[super viewDidUnload];
[mapView release];
mapView = nil; // Without this line an exception is thrown.
}
// 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);