Ios 是否忽略UIColor.setFill()错误消息?

Ios 是否忽略UIColor.setFill()错误消息?,ios,swift,uicolor,Ios,Swift,Uicolor,我有两个并排循环的函数来不断绘制两个UIBezierPath,问题是,它们每个都有不同的颜色,所以我需要不断重复UIColor.blackColor().setFill()和UIColor(patternImage:UIImage(名为:“normalpaper.jpg”).setFill(),缺点是它使控制台无法阅读,因为它不断地向你发送警告信息 <Error>: CGContextRestoreGState: invalid context 0x0. This is a seri

我有两个并排循环的函数来不断绘制两个UIBezierPath,问题是,它们每个都有不同的颜色,所以我需要不断重复
UIColor.blackColor().setFill()
UIColor(patternImage:UIImage(名为:“normalpaper.jpg”).setFill()
,缺点是它使控制台无法阅读,因为它不断地向你发送警告信息

<Error>: CGContextRestoreGState: invalid context 0x0. This is a serious error.
This application, or a library it uses, is using an invalid context  and is thereby
contributing to an overall degradation of system stability and reliability. This
notice is a courtesy: please fix this problem. It will become a fatal error in an
upcoming update.
下面是完整的CircleView类 (我对编程还是很陌生,所以可能效率很低)

苹果公司解释了所有这些,我强烈建议在继续使用自定义绘图代码之前阅读。请至少阅读上的部分。


问题是您正在
CircleView
s
drawRect
函数中创建并启动
NSTimer
s。绘图调用只能在正确的上下文中进行(这实际上是您看到的错误试图告诉您的)。通过在从
NSTimer
调用的函数中进行绘图,实际上是在
drawRect
函数外部进行绘图,在这种情况下没有有效的绘图上下文。而且,按照代码的原样,每次系统需要重新绘制视图时,您都将启动新的计时器;随着计时器开始重叠,这可能会很快失控

然而,只要稍微重新安排一下,我们就能做到这一点

请注意:这不一定是处理圆动画的正确方法,但它将解决您所询问的有关无效上下文错误的特定问题

  • drawRect
    中取出所有内容,并将其替换为调用
    eraseCircle
    drawCircle

  • 将您必须递增的逻辑
    x
    y
    ,以及
    eraseX
    eraseY
    drawCircle
    eraseCircle
    中取出,并将其放在
    timerDraw
    timerErase

  • 不要在
    timerDraw
    timerErase
    中直接调用图形代码,而是通过调用来告诉视图系统需要重新绘制视图。这将标记您的视图需要重新绘制,并且视图系统将尽快自动再次调用您的
    drawRect
    函数

  • 覆盖
    didmovetoserview
    并在那里启动计时器,使计时器再次工作;如果它们已经在运行,您还应该添加逻辑来停止它们

  • 步骤1和3是使错误消失的关键点。

    大概是这样的:

    //Creating a view capable of painting the circle
    class CircleView: UIView {
        // Timers
        var drawTimer: NSTimer?
        var eraseTimer: NSTimer?
    
        //Starting X Pos
        var x: CGFloat = 100
        var eraseX: CGFloat = 100
    
        //Starting Y Pos
        var y: CGFloat = 100
        var eraseY: CGFloat = 100
    
        override func drawRect(rect: CGRect) {
            eraseCircle()
            drawCircle()
        }
    
        override func didMoveToSuperview() {
            // If we have active timers, stop them
            if var drawTimer = self.drawTimer {
                // This stops the timer
                drawTimer.invalidate()
                self.drawTimer = nil
            }
    
            if var eraseTimer = self.eraseTimer {
                // This stops the timer
                eraseTimer.invalidate()
                self.eraseTimer = nil
            }
    
            // If we're actually part of the view hierarchy, start the timers
            if self.superview != nil {
                //Creating the looping draw timer
                self.drawTimer = NSTimer.scheduledTimerWithTimeInterval(
                    0.2,
                    target: self,
                    selector: Selector("timerDraw"),
                    userInfo: nil,
                    repeats: true)
    
                //Creating the looping erase timer
                self.eraseTimer = NSTimer.scheduledTimerWithTimeInterval(
                    0.3,
                    target: self,
                    selector: Selector("timerErase"),
                    userInfo: nil,
                    repeats: true)
            }
        }
    
        func drawCircle() {
            //Setting the draw color
            UIColor.blackColor().setFill()
    
            // Creating the rectangle's size
            var drawRect = roundDrawRect(10.0, angle: 7)
    
            //Drawing the rectangle
            drawRect.fill()
    
        }
    
        func eraseCircle() {
            //Setting the eraser color
            UIColor(patternImage: UIImage(named: "normalpaper.jpg")).setFill()
    
            // Creating the rectangle's size
            var eraseRect = roundEraseRect(10.0, angle: 7)
    
            //Drawing the rectangle
            eraseRect.fill()
    
        }
    
        func timerDraw(){
            //Incrementing the coords
            ++y
            ++x
    
            self.setNeedsDisplay()
        }
    
        func timerErase(){
            //Decrementing the coords
            eraseX = x - 2
            eraseY = y - 2
    
            self.setNeedsDisplay()
        }
    
        //Defining the rounded rect erasing (Circle)
        func roundEraseRect(radius: CGFloat, angle: CGFloat) -> UIBezierPath {
    
            //Creating the rounded rect (Circle)
            var roundedRect = UIBezierPath()
    
            roundedRect.moveToPoint(CGPointMake(eraseX,eraseY))
            println(CGPointMake(eraseX,eraseY))
    
            roundedRect.addArcWithCenter(CGPointZero, radius: radius,
                startAngle: 0, endAngle: angle ,
                clockwise: true)
    
            return roundedRect
        }
    
        //Defining the rounded rect drawing (Circle)
        func roundDrawRect(radius: CGFloat, angle: CGFloat) -> UIBezierPath {
    
            //Creating the rounded rect (Circle)
            var roundedRect = UIBezierPath()
    
            roundedRect.moveToPoint(CGPointMake(x,y))
    
            roundedRect.addArcWithCenter(CGPointZero, radius: radius,
                startAngle: 0, endAngle: angle ,
                clockwise: true)
    
            return roundedRect
        }
    }
    

    至于实现您正在尝试的动画的最佳方法,您可以只绘制一次圆,然后在
    UIViewController
    中使用计时器移动整个视图。或者,可能更好,使用。或者,如果您的最终产品将是一款游戏(甚至类似于游戏),那么不妨看看。

    您在哪里调用
    drawCircle()
    eraseCircle()
    ?上下文在这里很重要,因为您只能在非常特定的时间和地点调用绘图代码。@MikeS嘿,Mike。我在一个自定义类中调用它们,该类添加在ViewController的正上方(而不是内部),它是一个名为CircleView的自定义类(我将其作为viewDidLoad内部的子视图添加),它的子类是一个UIView,因此它可以正确地绘制图像,问题是控制台被错误消息垃圾邮件。我将添加整个类供您检查,以确定您是否愿意。问题在于
    drawRect
    中的计时器。你能解释一下你想用这些做什么吗?@MikeS我想做的是让屏幕上的圆圈每隔0.2秒不断移动
    +1x+1y
    。计时器每0.2秒调用一次
    drawCircle()
    函数,该函数以稍微不同的位置绘制圆。与
    eraseCircle()
    函数相同,在稍微延迟后,在旧圆圈位置上绘制一个背景色圆圈,使其产生被擦除的错觉。或者至少,这是目标,它还没有在屏幕上画出图像。。仍然在解决问题。至少,您应该使用计时器,然后从
    drawRect
    内部移动所有绘图代码。但是请先阅读文档。你不需要线程。我现在会读到,至于移动整个背景,这是行不通的,因为我试图实现的目标有点像一个益智游戏,圆圈以预定的速度移动,你点击屏幕来改变它的周围环境,我也不知道这会转化成精灵工具包,我想我会看看那里。谢谢
    //Creating a view capable of painting the circle
    class CircleView: UIView {
    
    //Starting X Pos
    var x: CGFloat = 100
    var eraseX: CGFloat = 100
    
    //Starting Y Pos
    var y: CGFloat = 100
    var eraseY: CGFloat = 100
    
    //Starting the loop of functions
    override func drawRect(rect: CGRect) {
    
        //Creating the looping draw timer
        NSTimer.scheduledTimerWithTimeInterval(
            0.2,
            target: self,
            selector: Selector("timerDraw"),
            userInfo: nil,
            repeats: true)
    
        //Creating the looping erase timer
        NSTimer.scheduledTimerWithTimeInterval(
            0.3,
            target: self,
            selector: Selector("timerErase"),
            userInfo: nil,
            repeats: true)
    
    }
    
    func drawCircle() {
    
        //Setting the draw color
        UIColor.blackColor().setFill()
    
        // Creating the rectangle's size
        var drawRect = roundDrawRect(10.0, angle: 7)
    
        //Incrementing the coords
        ++y
        ++x
    
        //Drawing the rectangle
        drawRect.fill()
    
    }
    
    func eraseCircle() {
    
        //Setting the eraser color
        UIColor(patternImage: UIImage(named: "normalpaper.jpg")).setFill()
    
        //Decrementing the coords
        eraseX = x - 2
        eraseY = y - 2
    
        // Creating the rectangle's size
        var eraseRect = roundEraseRect(10.0, angle: 7)
    
        //Drawing the rectangle
        eraseRect.fill()
    
    }
    
    func timerDraw(){
    
        //DO DRAW LOOP HERE
        drawCircle()
    
    }
    
    func timerErase(){
    
        //DO ERASE LOOP HERE
        eraseCircle()
    
    }
    
    //Defining the rounded rect erasing (Circle)
    func roundEraseRect(radius: CGFloat, angle: CGFloat) -> UIBezierPath {
    
        //Creating the rounded rect (Circle)
        var roundedRect = UIBezierPath()
    
        roundedRect.moveToPoint(CGPointMake(eraseX,eraseY))
        println(CGPointMake(eraseX,eraseY))
    
        roundedRect.addArcWithCenter(CGPointZero, radius: radius,
            startAngle: 0, endAngle: angle ,
            clockwise: true)
    
        return roundedRect
    }
    
    //Defining the rounded rect drawing (Circle)
    func roundDrawRect(radius: CGFloat, angle: CGFloat) -> UIBezierPath {
    
        //Creating the rounded rect (Circle)
        var roundedRect = UIBezierPath()
    
        roundedRect.moveToPoint(CGPointMake(x,y))
    
        roundedRect.addArcWithCenter(CGPointZero, radius: radius,
            startAngle: 0, endAngle: angle ,
            clockwise: true)
    
        return roundedRect
    }
    
    
    
    
    }
    
    class ViewController: UIViewController {
    
    //Creating a view capable of painting the circle
    class CircleView: UIView {
        // Timers
        var drawTimer: NSTimer?
        var eraseTimer: NSTimer?
    
        //Starting X Pos
        var x: CGFloat = 100
        var eraseX: CGFloat = 100
    
        //Starting Y Pos
        var y: CGFloat = 100
        var eraseY: CGFloat = 100
    
        override func drawRect(rect: CGRect) {
            eraseCircle()
            drawCircle()
        }
    
        override func didMoveToSuperview() {
            // If we have active timers, stop them
            if var drawTimer = self.drawTimer {
                // This stops the timer
                drawTimer.invalidate()
                self.drawTimer = nil
            }
    
            if var eraseTimer = self.eraseTimer {
                // This stops the timer
                eraseTimer.invalidate()
                self.eraseTimer = nil
            }
    
            // If we're actually part of the view hierarchy, start the timers
            if self.superview != nil {
                //Creating the looping draw timer
                self.drawTimer = NSTimer.scheduledTimerWithTimeInterval(
                    0.2,
                    target: self,
                    selector: Selector("timerDraw"),
                    userInfo: nil,
                    repeats: true)
    
                //Creating the looping erase timer
                self.eraseTimer = NSTimer.scheduledTimerWithTimeInterval(
                    0.3,
                    target: self,
                    selector: Selector("timerErase"),
                    userInfo: nil,
                    repeats: true)
            }
        }
    
        func drawCircle() {
            //Setting the draw color
            UIColor.blackColor().setFill()
    
            // Creating the rectangle's size
            var drawRect = roundDrawRect(10.0, angle: 7)
    
            //Drawing the rectangle
            drawRect.fill()
    
        }
    
        func eraseCircle() {
            //Setting the eraser color
            UIColor(patternImage: UIImage(named: "normalpaper.jpg")).setFill()
    
            // Creating the rectangle's size
            var eraseRect = roundEraseRect(10.0, angle: 7)
    
            //Drawing the rectangle
            eraseRect.fill()
    
        }
    
        func timerDraw(){
            //Incrementing the coords
            ++y
            ++x
    
            self.setNeedsDisplay()
        }
    
        func timerErase(){
            //Decrementing the coords
            eraseX = x - 2
            eraseY = y - 2
    
            self.setNeedsDisplay()
        }
    
        //Defining the rounded rect erasing (Circle)
        func roundEraseRect(radius: CGFloat, angle: CGFloat) -> UIBezierPath {
    
            //Creating the rounded rect (Circle)
            var roundedRect = UIBezierPath()
    
            roundedRect.moveToPoint(CGPointMake(eraseX,eraseY))
            println(CGPointMake(eraseX,eraseY))
    
            roundedRect.addArcWithCenter(CGPointZero, radius: radius,
                startAngle: 0, endAngle: angle ,
                clockwise: true)
    
            return roundedRect
        }
    
        //Defining the rounded rect drawing (Circle)
        func roundDrawRect(radius: CGFloat, angle: CGFloat) -> UIBezierPath {
    
            //Creating the rounded rect (Circle)
            var roundedRect = UIBezierPath()
    
            roundedRect.moveToPoint(CGPointMake(x,y))
    
            roundedRect.addArcWithCenter(CGPointZero, radius: radius,
                startAngle: 0, endAngle: angle ,
                clockwise: true)
    
            return roundedRect
        }
    }