一个 bug / Masonry的引入

支持iOS 6/6 Plus的时候碰到这样一个问题:
塞在UITableViewCell里的UIPageControl居中设置失败了,偏右
刚刚设置时下断点查看(6Plus模拟器):
<GrayPageControl: 0x7f96a535c350; baseClass = UIPageControl; frame = (179.5 241.75; 55 6); autoresize = W; layer = <CALayer: 0x7f96a535c4a0>>
 
运行后:
<GrayPageControl: 0x7f96a535c350; baseClass = UIPageControl; frame = (179.333 241.75; 149 6); autoresize = W; layer = <CALayer: 0x7f96a535c4a0>>
 
 
好奇在什么时候被改变的,考虑搞个内存修改断点,上lldb,听从忠告检测CALayer的frame改动而不是UIView的:
(lldb) po pc
<GrayPageControl: 0x15fe26ca0; baseClass = UIPageControl; frame = (160 217.375; 55 6); autoresize = W; layer = <CALayer: 0x174c38500>>

(lldb) break set -F '-[CALayer setBounds:]' -c '$x0 == 0x174c38500'
Breakpoint 113: where = QuartzCore`-[CALayer setBounds:], address = 0x000000018a3eb93c
 
结果是 layoutSubviews: 
#0 0x000000018a3eb93c in -[CALayer setBounds:] ()
#1 0x000000018a3ec684 in -[CALayer setFrame:] ()
#2 0x000000018aa9da3c in -[UIView(Geometry) setFrame:] ()
#3 0x000000018aaba7b4 in -[UIView(Geometry) _applyAutoresizingMaskWithOldSuperviewSize:] ()
#4 0x000000018618cfc8 in __53-[__NSArrayM enumerateObjectsWithOptions:usingBlock:]_block_invoke ()
#5 0x000000018618ce6c in -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] ()
#6 0x000000018aaa9f58 in -[UIView(Geometry) resizeSubviewsWithOldSize:] ()
#7 0x000000018aa9daf4 in -[UIView(Geometry) setFrame:] ()
#8 0x000000018ab7b9d4 in -[UITableViewCellContentView setFrame:] ()
#9 0x000000018abe442c in __53-[UITableView _configureCellForDisplay:forIndexPath:]_block_invoke ()
#10 0x000000018aab24c8 in +[UIView(Animation) performWithoutAnimation:] ()
#11 0x000000018abe3b0c in -[UITableView _configureCellForDisplay:forIndexPath:] ()
#12 0x000000018ad9b4d8 in -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] ()
#13 0x000000018ad9006c in -[UITableView _updateVisibleCellsNow:isRecursive:] ()
#14 0x000000018ab84c44 in -[UITableView layoutSubviews] ()
#15 0x000000018aaa14a4 in -[UIView(CALayerDelegate) layoutSublayersOfLayer:] ()
#16 0x000000018a3f57a8 in -[CALayer layoutSublayers] ()
#17 0x000000018a3f0378 in CA::Layer::layout_if_needed(CA::Transaction*) ()
#18 0x000000018a3f021c in CA::Layer::layout_and_display_if_needed(CA::Transaction*) ()
#19 0x000000018a3efa14 in CA::Context::commit_transaction(CA::Transaction*) ()
#20 0x000000018a3ef798 in CA::Transaction::commit() ()
#21 0x000000018a3e91c8 in CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) ()
#22 0x000000018624ed98 in __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ ()
#23 0x000000018624bd24 in __CFRunLoopDoObservers ()
#24 0x000000018624c104 in __CFRunLoopRun ()
#25 0x00000001861791f4 in CFRunLoopRunSpecific ()
#26 0x000000018f59b6fc in GSEventRunModal ()
#27 0x000000018ab0a10c in UIApplicationMain ()
#28 0x0000000100029ce0 in main 

 

看一下赋值过程:
(lldb) po $x0
<CALayer:0x174c38500; position = CGPoint (215 220.375); bounds = CGRect (0 0; 55 6); delegate = <GrayPageControl: 0x15fe26ca0; baseClass = UIPageControl; frame = (187.5 217.375; 55 6); autoresize = W; layer = <CALayer: 0x174c38500>>; sublayers = (<CALayer: 0x170a3fd40>, <CALayer: 0x1704250a0>, <CALayer: 0x174c38200>, <CALayer: 0x174c38080>); opaque = YES; allowsGroupOpacity = YES; >
(lldb) finish
(lldb) po 0x174c38500
<CALayer:0x174c38500; position = CGPoint (215 220.375); bounds = CGRect (0 0; 110 6); delegate = <GrayPageControl: 0x15fe26ca0; baseClass = UIPageControl; frame = (160 217.375; 110 6); autoresize = W; layer = <CALayer: 0x174c38500>>; sublayers = (<CALayer: 0x170a3fd40>, <CALayer: 0x1704250a0>, <CALayer: 0x174c38200>, <CALayer: 0x174c38080>); opaque = YES; allowsGroupOpacity = YES; >
 
这里借了台iPhone 6/iOS8, cpu是ARM64 所以得参考下面link里bcattle的补充回答,寄存器是$x0, iphone 5/iOS7 上用$r0 但是居然值没变化。模拟器上没成功。另外同样是layoutSubviews 前者是UITableView的,后者是UITableViewCell调用的。
 
 
好奇满足了,然后想办法解决。so上搜索PageControl UITableViewCell layoutSubViews/center 等等,没有看到相关讨论。某天学了一点AutoLayout赶紧过来写一行:
 
 1 [pc setTranslatesAutoresizingMaskIntoConstraints:NO];
 2 [cell.contentView addConstraints:[NSLayoutConstraint
 3                   constraintsWithVisualFormat:@"H:|-0-[pc]-0-|” 
 4                                       options:0 
 5                                       metrics:nil
 6                                         views:NSDictionaryOfVariableBindings(pc)]];
 7  
 8 [cell.contentView addConstraints:[NSLayoutConstraint 
 9                     constraintsWithVisualFormat:[NSString stringWithFormat: @"V:|-%f-[pc]-11-|",  CGRectGetHeight(scroll.frame)-11-6] 
10                                         options:0 
11                                         metrics:nil
12                                           views:NSDictionaryOfVariableBindings(pc)]];

 

不卖关子,成功了。于是结论出来了,AutoLayout升级为必修。Masonry,我来了。

1 [pc mas_makeConstraints:^(MASConstraintMaker * make){
2     make.bottom.equalTo(cell.contentView.mas_bottom).with.offset(-6);
3     make.centerX.equalTo(cell.contentView.mas_centerX);
4 }];

 

尾声:storyboard的预览功能+sizeClass会不会比传统的手码代码快一点呢?
 
2015.03.30
 

posted on 2015-03-30 19:03  kurk  阅读(1170)  评论(0编辑  收藏  举报

导航