省略UIColor.setFill()错误消息



我有两个并排的函数,它们循环不断地绘制两个UIBezierPath,问题是,它们每个都有不同的颜色,所以我需要不断地重申UIColor.blackColor().setFill()UIColor(patternImage: UIImage(named: "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.

因此,我的问题是,有没有一种方法可以做到这一点,不会向我的控制台发送此警告消息?也许是一种使警告信息不会出现的方法?(搜索时找不到)或者可能是一种省略消息的方法?任何意见都非常感谢,感谢阅读-扎克。

-

如果你需要画functions,它们在下面

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()
}

下面的Full CircleView类(我对编程还很陌生,所以可能效率很低)

//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 {

苹果iOS版绘图和打印指南解释了所有这些,我强烈建议在进一步使用自定义绘图代码之前阅读它。至少,请阅读有关iOS绘图概念的部分


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

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

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

  1. drawRect中取出所有内容,并将其替换为对eraseCircledrawCircle的调用。

  2. 取必须从drawCircleeraseCircle中增加xyeraseXeraseY的逻辑,将其放入timerDrawtimerErase中。

  3. 不要直接在timerDrawtimerErase中调用图形代码,而是通过调用setNeedsDisplay()告诉视图系统需要重新绘制视图。这将标记您的视图需要重新绘制,视图系统将尽快自动再次调用drawRect函数。

  4. 通过覆盖didMoveToSuperview并在那里启动计时器,使计时器重新工作;如果它们已经在运行,您还应该添加逻辑来阻止它们。

步骤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中在计时器上移动整个视图。或者,使用核心动画可能更好。或者,如果你的最终产品将是一款游戏(甚至类似游戏),也许可以看看雪碧套装。

相关内容

最新更新