我正在使用终端仿真应用程序通过telnet连接到我的unix服务器,我正在使用tableview(一个单元格用于一个文本行)。令我烦恼的是,当服务器发送大量文本数据以响应某些命令时,这会使应用程序响应(延迟)触摸屏幕上的任何按钮或任何手势,因为绘图在主线程中,不允许其他进程工作,除非它完了。
解决这个问题应该是什么样的完美方法,我是否需要OperationQueue,我对此并不了解。
我需要像绘图一样的东西,我可以顺利地与app交互(这可以暂停绘图)。
我认为drawRect我需要更长的时间,实际上我正在做的不是reloadData或ReloadTableCell,我在tableview的文本行单元格中有一个可变的属性字符串,并且需要添加文本时对于那个单元格,我只是替换该可变属性字符串中的字符,并为调用drawRect的单元格调用setNeedsDisplay。在drawRect中,我的代码如下 -
-(void)drawRect:(CGRect)rect
{
_cursorView.frame = CGRectMake(([_delegate cursorXInTextLine:self] - 1 )* 6, 0, 6, 10);
[self drawText:0 yPosition:0 canvasWidth:self.bounds.size.width canvasHeight:10];
}
- (void)drawText:(CGFloat)xPosition yPosition:(CGFloat)yPosition canvasWidth:(CGFloat)canvasWidth canvasHeight:(CGFloat)canvasHeight
{
//Draw Text
CGRect textRect = CGRectMake(xPosition, yPosition, canvasWidth, canvasHeight);
[self.textLineText drawInRect: textRect];
}
执行textReplacement的其他方法如下 -
-(void)initializeWithStringChar:(NSString*)charString
{
NSInteger len = charString.length;
while (len > 0) {
//length can be displayed.
NSInteger cutLength = totalCols - cursorX + 1;
if (len < cutLength) {
cutLength = len;
}
NSString *str = [charString substringToIndex:cutLength];
[self placeTextInCurrentTextLine:str :YES :YES :YES];
charString = [charString substringFromIndex:cutLength];
len -= cutLength;
}
}
-(void)placeTextInCurrentTextLine:(NSString *)text :(BOOL)needsToReplace :(BOOL)useCurrentCharAttrs :(BOOL)adjustCursor{
TextLineCell *textLineCell = (TextLineCell *)[self.telnet_TableView cellForRowAtIndexPath:currentLineIndexPath];
if (cursorX > totalCols) {
if (self.autowrap == YES) {
[self goNewLineAndResetCursor:YES];
textLineCell = (TextLineCell *)[self.telnet_TableView cellForRowAtIndexPath:currentLineIndexPath];
}
else
cursorX--;
}
NSAttributedString *attrText;
if (useCurrentCharAttrs) {
//Use current chars attributes
attrText = [[NSAttributedString alloc]initWithString:text attributes:currentCharAttrDict];
}
else{
//Use default chars attributes
attrText = [[NSAttributedString alloc]initWithString:text attributes:defaultCharAttrDict];
}
NSMutableAttributedString *attrLineText = [telnet_ScreenData objectAtIndex:currentLineIndexPath.row];
if (needsToReplace) {
//Replace chars with existing
[attrLineText replaceCharactersInRange:NSMakeRange(cursorX - 1, text.length) withAttributedString:attrText];
}
else{
//Insert and shift chars
[attrLineText insertAttributedString:attrText atIndex:cursorX - 1];
//shift out the last characters
attrLineText = [[NSMutableAttributedString alloc]initWithAttributedString:[attrLineText attributedSubstringFromRange:NSMakeRange(0, totalCols)]];
}
[telnet_ScreenData replaceObjectAtIndex:currentLineIndexPath.row withObject:attrLineText];
if (adjustCursor) {
cursorX = cursorX + (int)text.length;
}
if (textLineCell) {
textLineCell.textLineText = attrLineText;
[textLineCell setNeedsDisplay];
}
else{
[_telnet_TableView scrollToRowAtIndexPath:homeIndexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
}
答案 0 :(得分:1)
编辑:placeTextInCurrentTextLine::::
(方法名称不好)通过调用cellForRowAtIndexPath:
直接编辑表格视图单元格。这迫使系统创建一个可能不在屏幕上的单元格(甚至可能弹出缓存中的单元格)。如果生成了大量单元格,这实际上可能会强制创建否则永远不需要的单元格。数据源的工作是被动,并在请求时配置单元格。
当文本出现时,您应该找出哪些文本在哪些行上,然后调用insertRowsAtIndexPaths:withRowAnimation:
告诉表视图有新数据。然后等待它询问您特定的行,当它发生时,为它配置一个单元格。您没有维护表视图单元格的集合。您只需配置您要求的一个单元格,理想情况下使用dequeueReusableCellWithIdentifier:forIndexPath:
从现有单元格中删除现有单元格。在任何给定的时间,应该只存在与屏幕上的行一样多的单元格(可能还有一些用于滚动)。有关详细信息,请参阅Populating a Dynamic Table View with Data。
tableview是一个有趣的解决方案。我会选择UITextView
,因为它更适合处理大型文本块。但谁知道,tableview可能是一个相当聪明的解决方案(我可以看到它甚至可能比我的方式更好)。
所有性能问题的主要问题是实际问题发生的地方。您需要先使用Time Profiler运行Instruments,然后查看您在哪里花费时间。然后你可以研究如何改进它。
也就是说,有几个相当明显的事情你可能做错了。首先,您必须正确管理表格单元格重用。在cellForRowAtIndexPath:
中,您应该获取以前使用过的已离开屏幕的单元格(使用dequeueReusableCellWithIdentifier:
),然后只需使用新数据重新配置它。您应该不在每次调用cellForRowAtIndexPath:
时创建一个新单元格。你应该让你的单元格尽可能简单(你可能只需要一个UILabel
修改文本)。
您还必须非常小心,以避免致电reloadData
。由于您将继续添加到最后,因此您需要致电insertRowsAtIndexPaths:withRowAnimation:
。这种方式UITableView
不必重新计算所有内容。
在后端,如果您发现将传入流量解析为行是昂贵的,那么您一定要将解析移出主队列。原则上,NSOperationQueue
是“最高抽象”,通常使用可用的最高抽象是一个很好的建议。也就是说,我发现大多数人“获取”调度队列比操作队列更容易。许多操作队列API都基于pre-GCD并发系统,因此大部分文档都涵盖了当今很少使用的主题。我建议您阅读Dispatch Queues section of the Concurrency Programming Guide以熟悉它们。管理调度队列是iOS开发人员的一项关键且非常常见的技能。
但是第一步,就像表现一样,是对乐器感到满意,并确保你知道你的节目实际发生了什么。