记录一个问题, CALayer renderInContext: 在 iOS 8 或者 iOS9 上可能会导致崩溃。
复现步骤,当对一个 view 的 layer 执行 renderInContext: 方法时,如果该 view 的 layer 树的子图层树中有 frame 为 CGRectNULL 或者 position (frame.origin.x / frame.origin.y)中有 INFINITY 的时候, 会导致崩溃。
在 iOS 8 上会导致:
Assertion failed: (transform_is_valid(m)), function CGPathRef CGPathCreateWithRect(CGRect, const CGAffineTransform *), file Paths/CGPath.cc, line 179.
在 iOS 9 上会导致:
2017-09-13 16:34:58.335 UIKitTest[9443:271781] *** Terminating app due to uncaught exception 'CALayerInvalidGeometry', reason: 'sublayer with non-finite position [inf inf]' *** First throw call stack: ( 0 CoreFoundation 0x000000010bf15d85 __exceptionPreprocess + 165 1 libobjc.A.dylib 0x000000010b989deb objc_exception_throw + 48 2 CoreFoundation 0x000000010bf15cbd +[NSException raise:format:] + 205 3 QuartzCore 0x000000010ca8a9ee -[CALayer _renderSublayersInContext:] + 550 4 QuartzCore 0x000000010ca88dee -[CALayer renderInContext:] + 990 5 QuartzCore 0x000000010ca8a9be -[CALayer _renderSublayersInContext:] + 502 6 QuartzCore 0x000000010ca88dee -[CALayer renderInContext:] + 990 7 QuartzCore 0x000000010ca8a9be -[CALayer _renderSublayersInContext:] + 502 8 QuartzCore 0x000000010ca88dee -[CALayer renderInContext:] + 990 ...
如果对 UIView 做截图,可以使用如下方法,自测不会 Crash.
-[UIView drawViewHierarchyInRect:appDelegate.window.bounds afterScreenUpdates:];
总结: 平时开发时, 我们通过计算,很难会出现 CGRectNULL 或者 Position 中出现 INFINITY 的情况, 除非通过 CGRectDivide 等调用, 可能会返回一个 CGRectNULL 但是这个时候,我们一般会对这个返回值做测试, 而 INFINITY 的话, 浮点数溢出可能产生这个值。
旁注: 如果我们计算 frame 时,设置了 NAN 或者通过某种方式产生了包含 NAN 为成员变量的 CGRect 结构体,那么在添加到 view 视图树 或者 layer 图层树中,会直接导致崩溃,这个情况比较直观。记录一下对这些边界值的测试。