【问题标题】:What is causing <Error>: CGContextSetBaseCTM: invalid context 0x0 when implementing loadView?是什么导致 <Error>: CGContextSetBaseCTM: invalid context 0x0 在实现 loadView 时?
【发布时间】:2014-04-04 22:25:56
【问题描述】:

我有一个在 loadView 中执行此操作的 ViewController:

self.view = [[UIView alloc] init];

有时这会导致控制台出现以下错误:

:CGContextSetBaseCTM:无效的上下文 0x0。这是一个严重的错误。此应用程序或它使用的库正在使用无效的上下文,从而导致系统稳定性和可靠性的整体下降。此通知是出于礼貌:请解决此问题。这将成为即将到来的更新中的致命错误。

如果您改为拨打[super loadView],则不会发生这种情况。

为什么?

【问题讨论】:

  • 类似的问题似乎表明这可能没什么。您是否使用界面构建器文件(xib)?如果您的视图控制器使用这些,您不应该编写 loadView 方法。另外,您是否使用任何第三方框架?

标签: ios objective-c uiview uiviewcontroller


【解决方案1】:

如果您在拥有图形上下文之前尝试在图形上下文中或对图形上下文执行操作,则可能会发生这种情况。 您可以在 OS X 上看到相同的内容。 确保您的视图实际上位于窗口中的视图层次结构中。 Core Graphics / Quartz,不会为您提供没有窗口的图形上下文。 在 iOS 上只有一个窗口。 UIView 的子类可以使用 viewDidMoveToWindow 或 viewDidMoveToSuperview 作为检查窗口是否为 nil 和 superview 是否为 nil 的好时机。 这告诉您应该可以获得有效的上下文。 NSView 也有类似的方法可以覆盖。

我有。尽管如此,在 OS X 上看到的 Apple 应用程序也会向控制台发送相同的消息,因此如果它是由 Apple 框架代码发出的,您可能无法对其进行任何处理,除非提交错误。

在这种情况下,init 会给你一个 UIVIew,但它不是指定的初始化程序 initWithFrame: 和 OS X 上的 NSView 相同。所以你的视图没有框架,也没有坐标空间。因此,当您没有有效上下文时,有时会调用需要有效图形上下文的代码。它可能是您的代码,也可能是框架代码。一些未记录的事情发生在未记录的订单中。通常,如果您使用推荐的方法并按正确的顺序做事,则无需担心。

因此,在尝试执行任何需要有效 CGContext 的操作之前,您需要设置框架属性。当你尝试改变它时,你还需要确保你有一个有效的 CGContext。 错误说 CGContextSetCTM 这是一个 CGContext 函数,用于在图形上下文上设置转换。使用 CGContextGetCTM 很容易做到这一点。如果传入的上下文无效,则会出现此错误。所以,问题是,这是你的代码吗?还是别人的?

在 UIViewController 子类中考虑以下内容

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.aView = [[UIView alloc] init];
//  self.aView.frame = CGRectMake(0, 0, 30, 30);
// Uncomment the above line and your error will go away. Not because you set a size greater than zero, but because you set an origin point and a size for the frame.
// Set the frame after the view is in the window view hierarchy and the error will stop occurring.
    self.aView.backgroundColor = [UIColor redColor];
    [self.view addSubview:self.aView];

    CGContextRef context = UIGraphicsGetCurrentContext();
// This context is actually NULL.
    CGAffineTransform CTM = CGContextGetCTM(context);
// Above line will give you a nice similar error. (get instead of set)
    [self.view setNeedsDisplay];
}

我们不知道操作是否使用自动布局。没有发布足够的代码。 如果添加可满足的 NSLayoutConstraints,Autolayout 系统将创建原点,从而可以创建有效的 CGContext。 但问题的关键是必须在上下文可以访问或修改之前设置源点和大小,因为没有它,你有一个 NULL CGContext。 使用自动布局,必须在访问或修改上下文之前添加约束。 对于手动布局框架,必须在访问或修改上下文之前设置框架(零矩形或其他)。

指定初始化器要求它的原因是因为它是确保 CGContext 为 NULL 时没有任何东西击中的最安全时间。

您绝对可以在 initWithFrame: 中将 CGZeroRect 设置为您的框架,并且您应该使用 Autolayout。 你绝对仍然可以使用 init 来代替,尽管没有记录,只要你在任何东西到达你的 CGContext 之前设置一个框架或添加约束。 它没有记录,所以它是有风险的。 您应该始终使用 initWithFrame: 如果您不使用 xib/nib/storyboard(那些将从 initWithCoder 中的 xib/nib/storyboard 获取框架:)

最好的建议仍然是使用指定的初始化器,但事实是,在视图移动到有效窗口中的有效视图层次结构之前,CGContext 不能实际存在,因为上下文是从父视图上下文中派生的窗口中的有效层次结构。

【讨论】:

  • 你可以用init创建一个UIView,但是以后可以随时设置frame属性。在将视图作为子视图或根视图添加到有效窗口中之前,不会创建上下文本身。直到第一次绘图/布局通过时才使用框架。自动布局做到了这一点。它在最后一分钟计算事情。但即使没有它,直到最后一分钟,您才不需要也不应该真正需要框架。 initWithFrame: 只是让你免于后期工作。如果您在获得有效上下文之前尝试设置或获取 CTM,或者将无效的 CGContextRef 传递给它,则该错误很容易重现。
【解决方案2】:

我相信当视图尝试创建一个具有空边界的CGContextRef (CGRectZero) 时,可能会发生这种情况。为了确保不会发生这种情况,您应该在初始化时给视图一个框架。我通常使用

[UIView initWithFrame:[[UIScreen mainScreen] applicationFrame]];

【讨论】:

  • yip,零矩形会导致错误的计算
  • 使用自动布局,您绝对可以提供零矩形。关键是指定的初始化器设置了其他需要的东西
猜你喜欢
  • 1970-01-01
  • 2012-09-27
  • 2018-03-18
  • 2012-12-21
  • 2016-01-08
  • 1970-01-01
  • 1970-01-01
  • 2014-05-23
  • 1970-01-01
相关资源
最近更新 更多