我正在开发一款iPad应用,它有一个用于滚动数据的滑块。滚动时,将显示地图并更新数据。问题是,如果滚动得足够快(或以某种方式触发竞争条件),应用程序在访问僵尸NSString时崩溃。我已经能够在Profiler中找到它并找到了:
Event Type RefCt Timestamp Size Responsible Library Responsible Caller
Malloc 1 01:55.166.466 16 Foundation -[NSPlaceholderString initWithFormat:locale:arguments:]
Autorelease <null> 01:55.166.472 0 Foundation +[NSString stringWithFormat:]
CFRetain 2 01:55.166.473 0 My Program -[StateView updateVotes:]
CFRetain 3 01:55.166.476 0 UIKit -[UILabel setText:]
CFRelease 2 01:55.166.504 0 My Program -[StateView updateVotes:]
CFRelease 1 01:55.177.661 0 Foundation -[NSAutoreleasePool release]
CFRelease 0 01:55.439.090 0 UIKit -[UILabel setText:]
Zombie -1 01:55.439.109 0 UIKit -[NSString(UIStringDrawing) drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:includeEmoji:]
我在iOS5上使用ARC,所以我根本无法控制保留/释放。即使我是,看着上面,这是正确的。问题似乎是绘图函数和实际更改的UILabel字符串之间的竞争条件。 UILabel释放第一个字符串,因为已设置了一个新字符串,但绘图函数以某种方式保留对它的引用,但没有保留它。
作为一个说明,我没有以任何方式修改UILabel。
有什么想法吗?
---代码添加为更新:
滑块更新:
-(void)sliderValueChanged:(UISlider *)slider {
float position = slider.value - 1790.0f;
int year;
if(position <= 0.0f) {
year = 1789;
} else {
year = 1792 + (floor(position / 4.0f)*4);
}
[self setYear:year];
}
setYear:
-(void)setYear:(int)year {
if (year == currentYear) {
// year didn't change, so don't do anything
return;
}
[yearLabel setText:[[NSString alloc] initWithFormat:@"%i", year]];
currentYear = year;
[self getMapForYear:year];
}
getMapForYear:
-(void) getMapForYear:(int)year {
[self setToMap:[historicalData objectForKey:[NSNumber numberWithInt:year]];
}
setToMap:
-(void) setToMap:(HistoricalMap *)map {
// Label the map
for (State *state in [map states]) {
[mapController setVotes:[state votes] forState:[state abbreviation]];
}
}
setVotes:forState:
-(void)setVotes:(NSNumber *)votes forState:(NSString *)stateAbbreviation {
StateView *state = [states objectForKey:stateAbbreviation];
if (state == nil) {
NSLog(@"Invalid State Votes -- %@", stateAbbreviation);
return;
}
[state updateVotes:votes];
[state setNeedsDisplay];
}
updateVotes:
-(void)updateVotes:(NSNumber *)newVotes {
[self setVotes:newVotes];
NSString *voteString = [[NSString alloc] initWithFormat:@"%@", newVotes];
[voteLabel setText:voteString];
if ([newVotes isEqual:[NSNumber numberWithInt:0]]) {
[[self voteLabel] setHidden:YES];
[[self stateAbbreviationLabel] setHidden:YES];
} else {
[[self stateAbbreviationLabel] setHidden:NO];
[[self voteLabel] setHidden:NO];
}
}
答案 0 :(得分:1)
我认为你试图在滑块移动过程中做太多。单独创建和执行核心数据获取请求似乎是过度的,更不用说更新整个GUI和一系列标签。您是否在设备上测试过此功能?
可能值得分析这些代码部分并查看花费的时间。例如,您可以查看缓存获取请求或结果,或者您可能只需要在滑块停止时或仅沿路径的每n
个增量进行更新。
答案 1 :(得分:0)
你有几个内存泄漏NSString:
[yearLabel setText:[[NSString alloc] initWithFormat:@"%i", year]]; // leak
使用stringWithFormat
方法创建字符串
[yearLabel setText:[NSString stringWithFormat:@"%i", year]];
答案 2 :(得分:0)
[NSString stringWithFormat: **is the best way formatting the string than any other..**