也许是为了晚会,但是有人会觉得这很有帮助。最近,我需要为客户定制组件,以便重新创建网格可调整大小的叠加UIView。以下应该是工作,即使是很小的尺寸也没有问题。
该代码适用于iPhone(UIView),但可以非常快速地移植到NSView。
- (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextClearRect(context, rect); CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor); //corners CGContextSetLineWidth(context, 5.0); CGContextMoveToPoint(context, 0, 0); CGContextAddLineToPoint(context, 15, 0); CGContextMoveToPoint(context, 0, 0); CGContextAddLineToPoint(context, 0, 15); CGContextMoveToPoint(context, rect.size.width, 0); CGContextAddLineToPoint(context, rect.size.width-15, 0); CGContextMoveToPoint(context, rect.size.width, 0); CGContextAddLineToPoint(context, rect.size.width, 15); CGContextMoveToPoint(context, 0, rect.size.height); CGContextAddLineToPoint(context, 15, rect.size.height); CGContextMoveToPoint(context, 0, rect.size.height); CGContextAddLineToPoint(context, 0, rect.size.height-15); CGContextMoveToPoint(context, rect.size.width, rect.size.height); CGContextAddLineToPoint(context, rect.size.width-15, rect.size.height); CGContextMoveToPoint(context, rect.size.width, rect.size.height); CGContextAddLineToPoint(context, rect.size.width, rect.size.height-15); CGContextStrokePath(context); //border CGFloat correctRatio = 2.0; CGContextSetLineWidth(context, correctRatio); CGContextAddRect(context, rect); CGContextStrokePath(context); //grid CGContextSetLineWidth(context, 0.5); for (int i=0; i<4; i++) { //vertical CGPoint aPoint = CGPointMake(i*(rect.size.width/4), 0.0); CGContextMoveToPoint(context, aPoint.x, aPoint.y); CGContextAddLineToPoint(context,aPoint.x, rect.size.height); CGContextStrokePath(context); //horizontal aPoint = CGPointMake(0.0, i*(rect.size.height/4)); CGContextMoveToPoint(context, aPoint.x, aPoint.y); CGContextAddLineToPoint(context,rect.size.width, aPoint.y); CGContextStrokePath(context); } }
你无意中介绍了一个 倒楣 进入你的算法。每次打电话 moveToPoint 和 lineToPoint 在你的循环中,你实际上是在同一条路径中添加更多行, 所有 每次打电话时都会画出来 stroke 在那条路上。
moveToPoint
lineToPoint
stroke
这意味着你是第一次画一条线,第二次画两条线,第三次画三条线等等......
快速解决方案是 <击> 每次循环使用一条新路径 击> 简单地执行 stroke 后 循环(感谢Jason Coco的想法):
path = [NSBezierPath path]; while (...) { ... [path setLineWidth:1]; [path moveToPoint:startPoint]; [path lineToPoint:endPoint]; } [path stroke];
的 更新: 强> 另一种方法是避免创建它 NSBezierPath 完全,只是使用 strokeLineFromPoint:尖山: 类方法:
NSBezierPath
[NSBezierPath setDefaultLineWidth:1]; while (...) { ... [NSBezierPath strokeLineFromPoint:startPoint toPoint:endPoint]; }
的 更新#2: 强> 到目前为止,我对这些方法做了一些基本的基准测试。我正在使用一个800x600像素的窗口,十个像素的网格间距,我有可可重绘窗口一千次,从800x600扩展到900x700并再次返回。在我的2GHz Core Duo Intel MacBook上运行,我看到以下几次:
Original method posted in question: 206.53 seconds Calling stroke after the loops: 16.68 seconds New path each time through the loop: 16.68 seconds Using strokeLineFromPoint:toPoint: 16.68 seconds
这意味着减速完全是由重复造成的,而且几项微观改进中的任何一项都没有做到实际加速。这应该不足为奇,因为屏幕上像素的实际绘制(几乎总是)比简单循环和数学运算更加处理器密集。
要吸取的教训:
您应该运行Instruments Cpu Sampler来确定大部分时间花在哪里,然后根据该信息进行优化。如果是中风,将它放在循环外面。如果它正在绘制路径,请尝试将渲染卸载到gpu。看看CALayer是否可以提供帮助。