dailyItem.remainingTime = @([dailyItem.remainingTime floatValue] - 1.0);
我的项目因EXC_BAD_ACCESS而崩溃。上面是它破裂的线。
dailyItem
是NSManagedObject,remainingTime
是其属性之一。我对dailyItem
做的事情基本上是用每秒触发一次的计时器来改变这个属性。
countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(countdownForDailyItemTimer:)
userInfo:dailyItem
repeats:YES];
我安排计时器开始计时,每当它触发时,下面的方法都会被调用。
- (void)countdownForDailyItemTimer:(NSTimer *)timer{
if([timer.userInfo isKindOfClass:[DailyItem class]]) {
DailyItem *dailyItem = (DailyItem *)timer.userInfo;
dailyItem.remainingTime = @([dailyItem.remainingTime floatValue] - 1.0);
NSLog(@"counting daily item remaining time: %@", dailyItem.remainingTime);
}
}
几乎每次,在计数几分钟后,项目都会因EXC_BAD_ACCESS而崩溃。 我想知道是否是导致内存问题的托管对象的持续覆盖。
感谢。
更新:
除了覆盖属性,我有多个对象观察dailyItem
。每当remainingTime
发生变化(即每秒),他们就会得到通知并做一些事情。
我在其他地方发现EXC_BAD_ACCESS意味着我试图向已经发布的对象发送消息而不是我之前想过的内存问题。
所以我检查了我的代码中的相关内容,发现这是由于一个未被删除的观察者。我在addObserver: forKeyPath:
和removeObserver: forKeyPath:
中分别在嵌入导航控制器的视图控制器中实现了viewWillAppear
和viewDidDisappear
。当我在边缘滑动以导航回VC中但中途停止并返回时,`viewWillAppear被调用,VC再次注册为观察者但从未被删除,最终结果是同一个VC被注册两次。我记录了一些可能有助于解释这一点的信息。
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
.......
[self.dailyItem addObserver:self
forKeyPath:COUNTDOWN_OBSERVING_KEYPATH
options:0
context:NULL];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
NSLog(@"self.dailyItem observation info when view did disappear:%@", self.dailyItem.observationInfo);
[self.dailyItem removeObserver:self forKeyPath:COUNTDOWN_OBSERVING_KEYPATH];
NSLog(@"self.dailyItem observation info after removal:%@", self.dailyItem.observationInfo);
}
当我直接点击导航栏上的后退按钮时,这是控制台输出。
view did disappear
2014-08-03 19:49:26.645 Daily Plan[35491:13279953] self.dailyItem observation info when view did disappear:<NSKeyValueObservationInfo 0x7b939b40> (
<NSKeyValueObservance 0x79f3a140: Observer: 0x79f3c1d0, Key path: countingState, Options: <New: YES, Old: YES, Prior: NO> Context: 0x0, Property: 0x79f368f0>
<NSKeyValueObservance 0x7b96b610: Observer: 0x79f3b570, Key path: remainingTime, Options: <New: NO, Old: NO, Prior: NO> Context: 0x0, Property: 0x7b937990>
)
2014-08-03 19:49:26.645 Daily Plan Without CocoaPods[35491:13279953] self.dailyItem observation info after removal:<NSKeyValueObservationInfo 0x79f36470> (
<NSKeyValueObservance 0x79f3a140: Observer: 0x79f3c1d0, Key path: countingState, Options: <New: YES, Old: YES, Prior: NO> Context: 0x0, Property: 0x79f368f0>
)
这次我试图向后滑动,但中途停了下来。回到VC后,我再次点击后退按钮。
view did disappear
2014-08-03 19:49:43.152 Daily Plan[35491:13279953] self.dailyItem observation info when view did disappear:<NSKeyValueObservationInfo 0x79e18a90> (
<NSKeyValueObservance 0x79f3a140: Observer: 0x79f3c1d0, Key path: countingState, Options: <New: YES, Old: YES, Prior: NO> Context: 0x0, Property: 0x79f368f0>
<NSKeyValueObservance 0x7b8675a0: Observer: 0x7b86c8d0, Key path: remainingTime, Options: <New: NO, Old: NO, Prior: NO> Context: 0x0, Property: 0x7b937990>
<NSKeyValueObservance 0x7b8675a0: Observer: 0x7b86c8d0, Key path: remainingTime, Options: <New: NO, Old: NO, Prior: NO> Context: 0x0, Property: 0x7b937990>
)
2014-08-03 19:49:43.152 Daily Plan [35491:13279953] self.dailyItem observation info after removal:<NSKeyValueObservationInfo 0x7b8675e0> (
<NSKeyValueObservance 0x79f3a140: Observer: 0x79f3c1d0, Key path: countingState, Options: <New: YES, Old: YES, Prior: NO> Context: 0x0, Property: 0x79f368f0>
<NSKeyValueObservance 0x7b8675a0: Observer: 0x7b86c8d0, Key path: remainingTime, Options: <New: NO, Old: NO, Prior: NO> Context: 0x0, Property: 0x7b937990>
)
(lldb)
在第二种情况下,当我点击后退按钮进入另一个VC时,之前的VC只被删除一次,但已经被添加了两次,让它仍然在观察(此时它已经从在另一个VC中,计时器(全局计时器)仍然每秒触发,remainingTime
的{{1}}也在变化,但方法dailyItem
无法找到目标,从而导致EXC_BAD_ACCESS。
了解了这一切后,我在observeValueForKeyPath: ofObject:
中重新定位了addObserver
方法,问题就解决了。
我在寻找原因的过程中学到了两件事:
viewDidLoad
和ViewWillDisappear
。
我真的很喜欢在边缘滑动。这就是为什么我认为EXC_BAD_ACCESS是由于NSManagedObject的不断覆盖而不是我的滑动,两者都发生得太频繁了。