我有一个使用autolayout的项目,
我注意到viewWillAppear
之后,{8}会在iOS 8上多次调用viewWillLayoutSubViews
和viewDidLayoutSubViews
对,对于我的情况,它通常是2-3次。
第一个viewDidLayoutSubViews
将获得不正确的帧大小,因此我必须首先避免使用viewDidLayoutSubViews
,然后启动我的观看次数。
然而,当我在iOS 7上测试它时,我发现只有一个viewWillLayoutSubViews
和viewDidLayoutSubViews
对被调用,所以我的代码再次崩溃。
我的问题是,iOS 8对此行为有什么改变?
编辑: 我在这里粘贴了我的演示代码:
在代码中,_pieChart将被添加到self.ChartViewCanvas,而self.ChartViewCanvas将使用autolayout。 _pieChart来自旧的项目代码,它是在没有自动布局的情况下绘制的。
我需要在viewDidAppear之前绘制饼图,因为与storyboard中的其他视图相比,viewDidAppear中的绘图将延迟1秒。我不允许这样做。
有没有办法知道最后的viewDidLayoutSubViews
是什么时候?多次调用[self.ChartViewCanvas addSubview:_pieChart];
会降低性能,有时_pieChart的drawInRect不会每次调用,因此图表不会更新。
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
_pieChart.delegate = self;
if (!_pieChart) {
_pieChart = [[PieChartView alloc] initWithFrame:CGRectMake(0, 0, pieRadius * 2, pieRadius * 2)];
}else {
[_pieChart setFrame:CGRectMake(0, 0, pieRadius * 2, pieRadius * 2)];
}
//_pieChart.translatesAutoresizingMaskIntoConstraints = NO;
if ([_pieChart superview]) {
[_pieChart removeFromSuperview];
}
[self.ChartViewCanvas addSubview:_pieChart];
}
答案 0 :(得分:0)
可能只有Apple知道,但如果一切正常,我就不会处理太多问题。在iOS8中,Apple改变了很多视图控制器(再次),它们是从容器VC和旋转以及UITraitCollections
呈现的。
例如,UIAlertView现在是一个视图控制器,当你显示一个时,你会触发与呈现VC相关的所有机制
如果这个事实产生了一个问题,那么必须说你不应该依赖这些方法被调用多少次,因为它们总是不可预测的,有太多的变量需要考虑。
如果您希望它只被调用一次,那么快速而肮脏的解决方案可以将您的代码包装在dispatch_once
中。
如果您使用自动布局正确添加视图,您将看不到任何类型的错误。
[编辑]
这里有一个关于它如何看起来你的viewDidLoad的小片段:
- (void)viewDidLoad
{
[super viewDidLoad];
//.. your stuff
//We don't need any frame autolayout wil take care of calculating it on its pass
_pieChart = [[PieChartView alloc]initWithFrame:CGRectZero];
_pieChart.delegate = self;
_pieChart.translatesAutoresizingMaskIntoConstraints = NO;
[self.ChartViewCanvas addSubview:_pieChart];
NSDictionary *bindings = NSDictionaryOfVariableBindings(_pieChart);
// We create constraints to tell the view that it needs to sctretch its bounds to the superview
NSString *formatTemplate = @"%@:|[_pieChart]|";
for (NSString * axis in @[@"H",@"V"]) {
NSString * format = [NSString stringWithFormat:formatTemplate,axis];
NSArray * constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:bindings];
[_pieChart.superview addConstraints:constraints];
}
// Do any additional setup after loading the view.
}
当然这将调用drawRect:,当一个视图在显示传递中被标记为脏时调用rect,但在显示之前通常称为autolayout引擎来计算需要布局的视图帧。
答案 1 :(得分:0)
我在我的应用程序上尝试了这一点,发现和你一样:1在iOS7上调用,在iOS8调用3。从堆栈跟踪看,这似乎是在viewWillAppear
之后进行双重布局以及在iOS7上看不到viewDidAppear
之后的额外布局。
我的建议是在viewDidLoad
(或viewWillAppear
)中添加任何视图,然后只在布局子视图中进行布局调整。根据您更新的帖子,例如:
- (void)viewDidLoad{
[super viewDidLoad];
_pieChart = [[PieChartView alloc] initWithFrame:CGRectMake(0, 0, pieRadius * 2, pieRadius * 2)];
[self.ChartViewCanvas addSubview:_pieChart];
_pieChart.delegate = self;
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[_pieChart setFrame:CGRectMake(0, 0, pieRadius * 2, pieRadius * 2)];
}
感兴趣的是iOS7和8呼叫序列之间的区别是:
<强> iOS7 强>
i)viewWillAppear
被召唤。
ii)调用子视图的布局。从堆栈中看,这似乎与导航栏和动画有关。
ii)viewDidAppear
被召唤。
<强> iOS8上强>
i)viewWillAppear
被召唤。
ii)调用子视图的布局。从堆栈中看,这似乎与导航栏和动画有关。
iii)再次调用具有完全相同堆栈的完全相同的布局。因此,堆栈中的某些内容必须从某个位置请求重新运行。
iv)viewDidAppear
被调用。
v)调用额外的子视图布局。这似乎是从推入运行循环的事务驱动的。