2

所以我知道有很多关于这个的问题,但据我所知,这是一个独特的情况,所以我想我会发布它。希望这将添加一些信息,最终可能会给我们一个答案,说明为什么会发生这种情况。我收到错误:wait_fences: failed to receive reply: 10004003,当我的设备旋转时。我的视图动画从以下位置开始:

- (void) willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration

我只在新 iPad 3 上遇到错误。我在原始 iPad 和低至 3GS 的 iPhone 上使用了完全相同的程序。它们都没有出现 wait_fences 错误,而且它们的旋转速度都比 iPad 3 快。

我几乎只使用 Core Graphics 来绘制视图。我还确保在调整大小时重新绘制它们,这样我就不会得到像素化的视图。如果我在调整大小时禁用重绘,我不会收到此错误(但我会看到拉伸视图)。如果我完全禁用核心图形绘制,我不会收到错误消息(当然,我会看到黑色视图)。

我使用了 Time Profiler,发现问题主要在于绘制渐变: 在此处输入图像描述

我已经更改了代码以填充而不是绘制渐变,这确实缓解了问题。我会说渐变是问题,除了我在其他情况下(除了响应旋转)做这些动画并且它工作得很好。

我还想指出,我特别注意确保我只为实际在屏幕上的视图设置动画。我知道在屏幕外设置动画视图有时会导致发生此错误。

我没有包含动画代码

关于为什么会发生这种情况的任何想法?特别是因为它只发生在 iPad 3 上?

对于那些会问的人,这是执行动画的代码。它通常被包装在 UIView 动画块中。

- (void) setFramesForFocusView:(CustomControl *)focusView atX:(CGFloat)x showInput:(BOOL)showInput{
    CGSize bSize = self.bounds.size;
    CGRect fRect = focusView.frame;
    fRect.size.width = bSize.width;

    CGRect iRect;
    if (focusView.inputViewIsSystemKeyboard){
        if (_keyboardRect.origin.y < 0 || _keyboardRect.origin.y >= CGRectGetMaxY(self.bounds) || CGRectIsEmpty(_keyboardRect) || CGRectGetMaxY(_keyboardRect) > CGRectGetMaxY(self.bounds)) return;
        iRect = _keyboardRect;
    } else {
        iRect = (focusView.inputUIView && showInput) ? CGRectMake(0, bSize.height / 2, bSize.width, bSize.height / 2) : CGRectZero;
    }

    CGRect iaRect = focusView.inputAccessoryUIView.frame;
    CGFloat availableFieldHeight = iRect.origin.y - iaRect.size.height;

    iRect.size.width = bSize.width;
    iaRect.size.width = bSize.width;

    if (!showInput){
        iRect.origin.y = bSize.height;
    }
    iaRect.origin.y = iRect.origin.y - iaRect.size.height;

    iRect.origin.x = x;
    iaRect.origin.x = x;
    focusView.inputUIView.frame = iRect;
    focusView.inputAccessoryUIView.frame = iaRect;

    if (focusView.expandInput){
        fRect.origin.y = 0;
        fRect.size.height = availableFieldHeight;
    } else {
        if (focusView.labelPlacement != LabelPlacementTop && focusView.labelPlacement != LabelPlacementBottom){
            fRect.size.height = _currentView.storedFrame.size.height + [focusView.label.text sizeWithFont:focusView.label.font].height; 
        }
        fRect.origin.y = availableFieldHeight - fRect.size.height;
    }
    if (fRect.size.height > availableFieldHeight){
        fRect.origin.y = 0;
        fRect.size.height = availableFieldHeight;
    }
    fRect.origin.x = x;
    [focusView setLabelPlacement:LabelPlacementTop toFrame:fRect];
}
4

1 回答 1

1

那很快。@RobNapier 是正确的,因为这是一个时间问题。我评论了我的动画,哇,后面还有很多其他的动画!即使我只是明确地为屏幕视图设置动画,还有另一个 ViewController 在我的视图后面接收旋转事件而没有我的……呃……知识?我的意思是,我应该知道对吧?我写了代码。起初我没有意识到,因为我的视图集覆盖了整个屏幕。不幸的是,这将需要大量重写。我使用自定义容器控制器,现在我看到我需要重新考虑我的实现。很多东西都被不必要地旋转/动画化了。但是哇……这回答了很多性能问题……

更新

所以我认为我面临的问题与其他视图控制器动画的额外视图有关。然而,虽然这在技术上是正确的,但它并不像我想象的那样真实,也不像我想象的那样真实。我通过从窗口中删除整个根视图层次结构并仅用我想要旋转的视图控制器替换它来确保没有其他视图被动画化。这肯定有帮助,但并不完全。真的,它只是“降低了门槛”,这样我就不太可能出现“wait_fences”错误。我仍然发现在某些情况下我得到了错误。

我相信我遇到的问题是我使用了 UIScrollView。我的实现管理的子视图数量不定。具体的视图是我自己自定义的一个 UIPickerView 实现,所以你可以想象,它管理的视图数量会变得非常大。我发现如果这些子视图变得太多,我就会开始收到“wait_fences”错误。

所以看起来:如果 UIScollView 是动画的,它将动画它的所有子视图,即使这些子视图不在屏幕上。 这个很重要。我宁愿怀疑很多为这个错误而苦苦挣扎的人可能没有意识到这一点。这些屏幕外子视图中的每一个都在推动您更接近遇到“wait_fences”错误。在我的情况下,解决方案是“简单的”:我要将 UIScrollView 转换为 UITableView。这将意味着重写大量代码,但至少我知道屏幕外的子视图将从屏幕上删除,因此不会动画。

我还注意到其他一些事情:Core-Graphic Gradients 对你的打击很大。如果他们不使用渐变,我可以为更多的屏幕外视图设置动画。当然,我喜欢渐变并且我不愿意放弃它们(这就是我重写我的 PickerView 的原因),但它很有趣而且很重要。

更新 2

完成将我的 UIScrollView 重写为 tableView ,这似乎已经成功了。wait_fences当我旋转屏幕时,我没有延迟也没有错误。

更新 2

所以,是的,wait_fences在 iPad 3 上遇到错误比任何其他 iPad/iPhone 都容易得多。我已经检查了我所有的代码,确保我永远不会为屏幕上没有的任何东西制作动画,所以这个问题已经解决了。当我使用“重”绘图程序时,我仍然wait_fences在 iPad 3 上遇到错误。我发现的东西让我成功了:

  1. 渐变:渐变确实让 CPU 在视网膜屏幕上工作。
  2. 透明度:如果您的视图不是不透明的,CPU 会努力找出视图的透明区域。
  3. 透明颜色:与视图透明度不同。这是将透明颜色/渐变层叠在彼此的顶部以获得“效果”,例如光泽,突出显示任何内容。
  4. 纹理:我发现使用纹理更容易wait_fences出错,但与渐变/透明度所做的完全不同。
于 2012-06-07T19:52:44.793 回答