我在这里遇到了一个难题,不管感谢,我的意思是任何帮助=)
我是一名经验丰富的开发人员,我是Objective-C / iPhone / Cocoa的新手。
我想创建一个类控制器,我可以将NSMutableArray作为参数传递。
然后,我们有:
selTimeIntController = [[SingleSelectPickerViewController alloc] initWithSettings: listOfIntervals :kAlarmIntervalStr :myDataHolder.alarmInterval];
[self.navigationController pushViewController: selTimeIntController animated: YES];
[selTimeIntController release];
这个listOfIntervals是一个已经是alloc / init的NSMutableArray *。
在我的SingleSelectPickerViewController上,我们有:
-(id)initWithSettings:(NSMutableArray*)sourceArray :(NSString*)viewCurrentValue :(NSString*)viewTitle {
if(self = [self initWithNibName: kNibName bundle: [NSBundle mainBundle]]) {
listOfIntervals = [NSMutableArray arrayWithArray: (NSMutableArray*)sourceArray];
currentValue = [[NSString alloc] initWithString: viewCurrentValue];
title = [[NSString alloc] initWithString: viewTitle];
}
return self;
}
通过调试,我能够在我的SingleSelectPickerViewController上看到我的listOfIntervals。
这里我们有SingleSelectPickerViewController'dealloc:
- (void)dealloc {
[super dealloc];
[listOfIntervals release];
[currentValue release];
[title release];
}
但是,每次我实例化我的SingleSelectViewController时,我都会收到一个带有以下堆栈的EXEC_BAD_ADDRESS:
#0 0x96132688 in objc_msgSend ()
#1 0x00003ee2 in -[SingleSelectPickerViewController tableView:numberOfRowsInSection:] (self=0xd38940, _cmd=0x319a6bc0, tableView=0x102e000, section=0) at /Users/Cadu/iPhone/myApp/Classes/SingleSelectPickerViewController.m:115
#2 0x30a86bb4 in -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] ()
#3 0x30a8879b in -[UITableViewRowData rectForFooterInSection:] ()
#4 0x30a883c7 in -[UITableViewRowData heightForTable] ()
#5 0x3094e8e6 in -[UITableView(_UITableViewPrivate) _updateContentSize] ()
#6 0x30940a7d in -[UITableView noteNumberOfRowsChanged] ()
#7 0x3094a2a0 in -[UITableView reloadData] ()
#8 0x30947661 in -[UITableView layoutSubviews] ()
#9 0x00b41d94 in -[CALayer layoutSublayers] ()
#10 0x00b41b55 in CALayerLayoutIfNeeded ()
#11 0x00b413ae in CA::Context::commit_transaction ()
#12 0x00b41022 in CA::Transaction::commit ()
#13 0x00b492e0 in CA::Transaction::observer_callback ()
#14 0x30245c32 in __CFRunLoopDoObservers ()
#15 0x3024503f in CFRunLoopRunSpecific ()
#16 0x30244628 in CFRunLoopRunInMode ()
#17 0x32044c31 in GSEventRunModal ()
#18 0x32044cf6 in GSEventRun ()
#19 0x309021ee in UIApplicationMain ()
#20 0x000020d8 in main (argc=1, argv=0xbffff0b8) at /Users/Cadu/iPhone/MyApp/
知道发生了什么事吗?
答案 0 :(得分:7)
问题的标题是“内存泄漏”。问题中的所有内容都表示“崩溃”。这是一个崩溃,而不是内存泄漏。或者,至少,在修复crashers之前,你不会知道是否有内存泄漏。
最可能的崩溃来源是对listOfIntervals实例变量的错误管理。
listOfIntervals = [NSMutableArray arrayWithArray: (NSMutableArray*)sourceArray];
具体来说,这需要是:
listOfIntervals = [[NSMutableArray arrayWithArray: sourceArray] retain];
正如Mike所说,绕过一个可变的集合引用可能是一个坏主意。如果sourceArray
从您的班级下方更改,会发生什么?你准备好应对吗?
更常见的习惯用法是将你的方法声明为采用NSArray *然后复制数组:
listOfIntervals = [sourceArray mutableCopy]; // or -copy, if you don't need it to be mutable
(1)(NSMutableArray*)
演员阵容是不必要的。知道伤害,但如果不需要它,为什么要这样做呢?
(2)您需要保留listOfIntervals。 + arrayWithArray:将创建一个自动释放的数组,因此,在初始化对象后,该数组为released
,这将导致您看到的崩溃。
(3)-copy& -mutableCopy返回保留的对象,无需调用-retain。
但是,您还需要修复-dealloc
方法:
- (void)dealloc {
// move this [super dealloc];
[listOfIntervals release];
[currentValue release];
[title release];
[super dealloc]; // to here
}
[super dealloc]
必须始终是最后的。 -dealloc并没有什么神奇之处,因此,通过首先调用该函数,您告诉实例释放自己然后通过并清理实例变量。这会导致第二次崩溃(或意外行为)。
总的来说,我建议你重新阅读内存管理指南。
http://developer.apple.com/iPhone/library/documentation/Cocoa/Conceptual/MemoryMgmt/MemoryMgmt.html
答案 1 :(得分:0)
我是Mac编程新手,但我认为你的dealloc方法顺序错误。
应该是:
- (void)dealloc {
[listOfIntervals release];
[currentValue release];
[title release];
[super dealloc];
}
你应该解决这个问题,尽管我认为这不会解决你的问题。
我也不知道你在这做什么:
if(self = [self initWithNibName: kNibName bundle: [NSBundle mainBundle]]) {
//...
}
我认为应该是:
if ( ! [super initWithNibName: kNibName bundle: [NSBundle mainBundle]] ) {
return nil;
}
//...
答案 2 :(得分:0)
或者,你可以
listOfIntervals = [[NSMutableArray arrayWithArray:(NSMutableArray *)sourceArray] retain];
然后使用它并释放它。
上面的答案已经注意到,在释放所有课程分配之前,你调用了[super dealloc]。最后应该调用[super dealloc]。
关于Cocoa内存管理有很多有用的链接,特别是关于alloc / retain功能的使用。这是Cocoa / iPhone编程的重要组成部分。请参阅此示例:Memory management in Cocoa或只是google for it
希望它有所帮助,祝你好运
答案 3 :(得分:0)
你需要回到这个基础知识。
问题1:你正在绕过一个可变的基础对象。
这几乎总是表明糟糕的设计。看看Cocoa / CocoaTouch,您会看到很少使用可变类作为参数传递或返回。这样做几乎总是因为性能限制。
为什么不好?因为在进行调用之后,很容易得到两个或多个共享相同可变对象的对象。如果有人对其进行更改,则其他人无法了解它,可能会导致一些非常奇怪的行为。调试并不好玩。
问题2:您没有保留数组
这是一个内存管理的基础,你绝对必须在尝试过多地挖掘自己之前理解它。 Apple可能比我更好地解释它,但它归结为:
如果您需要访问范围之外的对象,请保留它。稍后完成后释放它。
所以你在这里做的是将自动释放的数组分配到listOfIntervals
实例变量中,当然它会被释放&稍后取消分配,当您下次尝试访问它时炸毁您的应用程序。相反,这是正确的代码:
- (id)initWithIntervals:(NSArray *)sourceArray
currentValue:(NSString *)viewCurrentValue
title:(NSString *)viewTitle
{
if (self = [self initWithNibName:kNibName bundle:nil])
{
listOfIntervals = [sourceArray mutableCopy];
currentValue = [viewCurrentValue copy];
title = [viewTitle copy];
}
return self;
}
注意事项:
[NSBundle mainBundle]
。正如文档所述,NSViewController将自行解决这个问题。NSArray
和NSString
是值对象。也就是说,您的代码对其值感兴趣,而不是实际对象本身。 Cocoa很好地照顾到尽可能高效。-copy
和-mutableCopt
都返回具有+1保留计数的对象,因此在您释放它们之前它们不会去任何地方。适用于典型的实例变量。