0 本文的程序例子

  先说说代码例子,文章最后面有个程序,直接将代码拷贝到新建的playground文件中,就可以这样展示和调试了

  

 

 

    普通的代码编写过程中直接就在右栏中显示执行结果,点击执行结果右边有两个小图标,一个眼睛的图标,可以直观看到图形或数值(当前状态),另外一个是+号,可以回溯历史数据和变量之间的相关性。 点击+号就可以看到上面的跷跷板和变量执行图,还有右下角的时间轴,可以手动拖放回滚。

 

 

 

  1、什么是playground?playground是Xcode的新的调试程序的一个工具,它提供灵活的数据展示方式,弥补了我们之前调试程序的手段的不足之处,它支持QuickLook多样式调试显示,不用添加测试代码、也不用按Run执行程序,就可以直观地查看运行情况,实时查看变量,可以直接查看的类型有:Color类型、String类型、Image类型、View类型、数据等等,可以自已开发动态展示的代码(实现接口),使用XCPCaptureValue函数观察和回溯动态过程。

  有什么情况不用playground ?游乐场虽好,但毕竟还是游乐场,目前它不支持界面交互,也就是说暂时无法在Playground上玩你实现的游戏。只能看不能动,还有就是无法直接执行你的App程序,毕竟它不是模拟器。

     

  2、playground有什么好处呢?从学习的用途上来说,它便于练习Swift,对初学编程的人来讲更是有好处,不用整天按F6,F7,也不用等虚拟机运行程序看结果。对熟悉的开发者来讲,它便于调试核心算法,测试一些涉及绘制的程序、图像处理等一些又要看得见又不太方便用其他测试代码做到的

    对使用开发环境的人来说,Playground有利于学习和尝试各种API,因为你不用为此设立项目,带着一个文件就可以到处跑

 

  3、 用个例子说明playground怎么用,我们直接上代码吧,我从WWDC2014会上展示的内容好象没有找到代码下载,所以先从视频上抄下一些代码,动手测试一下。这些代码只要直接拷到playground里面去就可以了,我们只要做几个事情

    a、在文件头引入 import XCPlayground,用于下文实现playground的一些接口

    b、实现func XCPCaptureValue<T>(identifier: String, value: T)用于显示程序执行过程中的历史数据,你可以用时间轴回滚,同时也看到变量与变量之间的关系。

    c、实现func XCPShowView(identifier: String, view: NSView),直接显示程序的动态执行过程,两个小孩在跷跷板上玩,然后你看到跷跷板变角度变量的历史过程和实现手动操作回滚

 

代码如下:

 import Cocoa

import QuartzCore

import XCPlayground

 class PlaygroundIconView:NSView {

    let backgroundLayer=CAShapeLayer()

    let seesawBaseLayer=CAShapeLayer()

    let seesawLayer=CAShapeLayer()

    init(){

        super.init(frame:NSRect(x:0,y:0,width:568,height:568))

        

        backgroundLayer.frame=self.bounds

        seesawBaseLayer.frame=NSRect(x:254,y:124,width:60,height:111)

        seesawLayer.frame=NSRect(x:40,y:197, width:488,height:30)

        

        setUpBackgroundLayer()

        setUpSeesawBaseLayer()

        setUpSeesawLayer()

        

        self.wantsLayer=true

        

        self.layer.addSublayer(backgroundLayer)

        self.layer.addSublayer(seesawBaseLayer)

        self.layer.addSublayer(seesawLayer)

    }

    

    func setUpBackgroundLayer(){

        let lineWidth=9.0

        let backgroundPath=NSBezierPath(roundedRect:NSInsetRect(bounds, lineWidth/2, lineWidth/2),xRadius:35.0,yRadius:35.0)

        backgroundPath.lineWidth=lineWidth

        

        backgroundLayer.strokeColor=NSColor.playgroundIconStrokeColor().CGColor

        backgroundLayer.fillColor=NSColor.playgroundIconFillColoer().CGColor

        backgroundLayer.lineWidth=lineWidth

        

        backgroundLayer.path=CGPathFromNSBezierPath(backgroundPath)

    }

    

    func setUpSeesawBaseLayer(){

     

        let seesawBasePath=NSBezierPath()

        

        

        let rectHeight:Int=50;

        

        

        seesawBasePath.moveToPoint(NSPoint(x:0,y:rectHeight))

        seesawBasePath.lineToPoint(NSPoint(x:seesawBaseLayer.bounds.width/2,y:seesawBaseLayer.bounds.height))

        seesawBasePath.lineToPoint(NSPoint(x:seesawBaseLayer.bounds.width,y:50))

         seesawBaseLayer.fillColor=NSColor.whiteColor().CGColor

        seesawBaseLayer.path=CGPathFromNSBezierPath(seesawBasePath)

    }

    

    func setUpSeesawLayer(){

       

        let createChildLayer:()->CAShapeLayer={

            let childLayer=CAShapeLayer()

            let headPath=NSBezierPath(ovalInRect:NSRect(x:60,y:150,width:49,height:49))

            

            let bodyPath=NSBezierPath()

            

            bodyPath.moveToPoint(NSPoint(x:58,y:155))

            bodyPath.lineToPoint(NSPoint(x:88,y:140))

            bodyPath.lineToPoint(NSPoint(x:126,y:100))

            

            bodyPath.lineToPoint(NSPoint(x:120,y:90))

            

            bodyPath.lineToPoint(NSPoint(x:125,y:71))

            

            bodyPath.lineToPoint(NSPoint(x:113,y:71))

            

            bodyPath.lineToPoint(NSPoint(x:112,y:94))

            bodyPath.lineToPoint(NSPoint(x:83,y:113))

            bodyPath.lineToPoint(NSPoint(x:68,y:94))

            

            bodyPath.lineToPoint(NSPoint(x:97,y:70))

            

            bodyPath.lineToPoint(NSPoint(x:122,y:12))

                

            bodyPath.lineToPoint(NSPoint(x:98,y:0))

            

            bodyPath.lineToPoint(NSPoint(x:64,y:41))

            

            bodyPath.lineToPoint(NSPoint(x:7,y:71))

            

            bodyPath.lineToPoint(NSPoint(x:0,y:94))

            

            bodyPath.moveToPoint(NSPoint(x:58,y:155))

            

            let childPath=NSBezierPath()

            

            childPath.appendBezierPath(headPath)

            childPath.appendBezierPath(bodyPath)

            

            childLayer.fillColor=NSColor.whiteColor().CGColor

            childLayer.path=CGPathFromNSBezierPath(childPath)

            

            return childLayer

        }

    

    

    let leftChildLayer = createChildLayer()

    let rightChildLayer = createChildLayer()

    

    rightChildLayer.transform=CATransform3DMakeRotation(M_PI,0.0,0.0,1.0)

    rightChildLayer.geometryFlipped=true

 

    let benchLayer = CALayer()

    

    benchLayer.frame=NSRect(x:0,y:41,width:self.seesawLayer.bounds.width,height:30)

    

    benchLayer.backgroundColor=NSColor.whiteColor().CGColor

    

    leftChildLayer.frame=NSRect(x:25,y:0,width:126,height:200)

    rightChildLayer.frame=NSRect(x:488-(126+25),y:0,width:126,height:200)

    

    seesawLayer.addSublayer(leftChildLayer)

    seesawLayer.addSublayer(rightChildLayer)

    seesawLayer.addSublayer(benchLayer)

    

    seesawLayer.delegate=self

    }

    

    let maxSeesawAngle=M_PI / 12

    

    var currentSeesawAngle = 0.0

    

    var animate:Bool = false{

        

    didSet(oldAnimate){

        if animate != oldAnimate && animate {

            if currentSeesawAngle == 0  {

                

                //@Bailey

                //设置捕捉动态记录和显示的参数

                XCPCaptureValue("Left Seesaw Position",0 )

                 animateSeesawToAngle(maxSeesawAngle,duration: 0.75)

            }

            else

            {

               animateSeesawToAngle(currentSeesawAngle * -1)

            }

        }

    }

    }

    

    func animateSeesawToAngle(angle:CGFloat,duration:CFTimeInterval = 1.5 )-> CAAnimation{

        let angleAnimation = CABasicAnimation(keyPath:"transform")

        angleAnimation.fromValue=NSValue(CATransform3D:seesawLayer.transform)

        

        angleAnimation.toValue=NSValue(CATransform3D:CATransform3DMakeRotation(angle, 0.0, 0.0, 1.0))

        

        angleAnimation.timingFunction = CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseInEaseOut)

        

        angleAnimation.duration = duration

        angleAnimation.delegate=self

        seesawLayer.addAnimation(

            angleAnimation, forKey: "transform")

        

        seesawLayer.transform=CATransform3DMakeRotation(angle,0.0, 0.0, 1.0)

        currentSeesawAngle=angle

        return angleAnimation

        

    }

    

    override func animationDidStop(_:CAAnimation!,finished:Bool){

        if finished && animate {

            

            //@Bailey

            //设置捕捉动态记录和显示的参数

            XCPCaptureValue("Left Seesaw Position",-currentSeesawAngle )

            animateSeesawToAngle(currentSeesawAngle * -1)

        }

    }

}

 

extension NSColor {

    class func playgroundIconFillColoer()->NSColor{

        return NSColor(red:12/255,green:65/255,blue:135/255,alpha:1.0)

    }

    class func playgroundIconStrokeColor()->NSColor{

        return NSColor(red:9/255,green:44/255,blue:91/255,alpha:1.0)

    }

}

 

func CGPathFromNSBezierPath(nsPath:NSBezierPath)->CGPath! {

    if nsPath.elementCount==0{

        return nil

    }

    

    let path=CGPathCreateMutable()

    var didClosePath=false

    for i in 0..nsPath.elementCount{

        var points=NSPoint[](count:3,repeatedValue:NSZeroPoint)

        

        switch nsPath.elementAtIndex(i, associatedPoints: &points){

        case .MoveToBezierPathElement:

            CGPathMoveToPoint(path,nil,points[0].x,points[0].y)

            

        case .LineToBezierPathElement:

            CGPathAddLineToPoint(path, nil, points[0].x, points[0].y)

            

        case .CurveToBezierPathElement:

            CGPathAddCurveToPoint(path,nil, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y)

        case .ClosePathBezierPathElement:

            CGPathCloseSubpath(path)

            didClosePath=true

         }

    }

    if !didClosePath{

        CGPathCloseSubpath(path)

    }

    return CGPathCreateCopy(path)

}

 

let view=PlaygroundIconView()

 

view.animate=true

 

//@Bailey

//显示游乐场跷跷板动态图标以及时间轴用于程序计算回溯

XCPShowView("20140605",view)

 

view

 

 

 

 

 

 

 

 

 

 

//修正程序以适应新swift的语法 ,在 xcode 6.1 下运行

 

 

 

 

 

 

 

 

 

import Cocoa

import Foundation

import QuartzCore

import XCPlayground

import SpriteKit

 

 class PlaygroundIconView:NSView {

    let backgroundLayer=CAShapeLayer()

    let seesawBaseLayer=CAShapeLayer()

    let seesawLayer=CAShapeLayer()

    required init?(coder: NSCoder){

        super.init(frame:NSRect(x:0,y:0,width:568,height:568))

        backgroundLayer.frame=self.bounds

        seesawBaseLayer.frame=NSRect(x:254,y:124,width:60,height:111)

        seesawLayer.frame=NSRect(x:40,y:197, width:488,height:30)

        setUpBackgroundLayer()

        setUpSeesawBaseLayer()

        setUpSeesawLayer()

        self.wantsLayer=true

        self.layer?.addSublayer(backgroundLayer)

        self.layer?.addSublayer(seesawBaseLayer)

        self.layer?.addSublayer(seesawLayer)

    }

    

    func setUpBackgroundLayer(){

        let lineWidth=9.0

        let backgroundPath=NSBezierPath(roundedRect:NSInsetRect(bounds, CGFloat(lineWidth/2), CGFloat(lineWidth/2)),xRadius:35.0,yRadius:35.0)

        backgroundPath.lineWidth=CGFloat(lineWidth)

        backgroundLayer.strokeColor=NSColor.playgroundIconStrokeColor().CGColor

        backgroundLayer.fillColor=NSColor.playgroundIconFillColoer().CGColor

        backgroundLayer.lineWidth=CGFloat(lineWidth)

        backgroundLayer.path=CGPathFromNSBezierPath(backgroundPath)

    }

    

    func setUpSeesawBaseLayer(){

        let seesawBasePath=NSBezierPath()

        let rectHeight:Int=50;

        seesawBasePath.moveToPoint(NSPoint(x:0,y:rectHeight))

        seesawBasePath.lineToPoint(NSPoint(x:seesawBaseLayer.bounds.width/2,y:seesawBaseLayer.bounds.height))

        seesawBasePath.lineToPoint(NSPoint(x:seesawBaseLayer.bounds.width,y:50))

        seesawBaseLayer.fillColor=NSColor.whiteColor().CGColor

        seesawBaseLayer.path=CGPathFromNSBezierPath(seesawBasePath)

    }

    

    func setUpSeesawLayer(){

        let createChildLayer:()->CAShapeLayer={

        let childLayer=CAShapeLayer()

        let headPath=NSBezierPath(ovalInRect:NSRect(x:60,y:150,width:49,height:49))

        let bodyPath=NSBezierPath()

        bodyPath.moveToPoint(NSPoint(x:58,y:155))

        bodyPath.lineToPoint(NSPoint(x:88,y:140))

        bodyPath.lineToPoint(NSPoint(x:126,y:100))

        bodyPath.lineToPoint(NSPoint(x:120,y:90))

        bodyPath.lineToPoint(NSPoint(x:125,y:71))

        bodyPath.lineToPoint(NSPoint(x:113,y:71))

        bodyPath.lineToPoint(NSPoint(x:112,y:94))

        bodyPath.lineToPoint(NSPoint(x:83,y:113))

        bodyPath.lineToPoint(NSPoint(x:68,y:94))

        bodyPath.lineToPoint(NSPoint(x:97,y:70))

        bodyPath.lineToPoint(NSPoint(x:122,y:12))

        bodyPath.lineToPoint(NSPoint(x:98,y:0))

        bodyPath.lineToPoint(NSPoint(x:64,y:41))

        bodyPath.lineToPoint(NSPoint(x:7,y:71))

        bodyPath.lineToPoint(NSPoint(x:0,y:94))

        bodyPath.moveToPoint(NSPoint(x:58,y:155))

        

        let childPath=NSBezierPath()

        childPath.appendBezierPath(headPath)

        childPath.appendBezierPath(bodyPath)

        childLayer.fillColor=NSColor.whiteColor().CGColor

        childLayer.path=CGPathFromNSBezierPath(childPath)

        

        return childLayer

        }

        

        let leftChildLayer = createChildLayer()

        let rightChildLayer = createChildLayer()

        rightChildLayer.transform=CATransform3DMakeRotation(CGFloat(M_PI),0.0,0.0,1.0)

        rightChildLayer.geometryFlipped=true

        let benchLayer = CALayer()

        benchLayer.frame=NSRect(x:0,y:41,width:self.seesawLayer.bounds.width,height:30)

        benchLayer.backgroundColor=NSColor.whiteColor().CGColor

        leftChildLayer.frame=NSRect(x:25,y:0,width:126,height:200)

        rightChildLayer.frame=NSRect(x:488-(126+25),y:0,width:126,height:200)

        seesawLayer.addSublayer(leftChildLayer)

        seesawLayer.addSublayer(rightChildLayer)

        seesawLayer.addSublayer(benchLayer)

        seesawLayer.delegate=self

    }

    let maxSeesawAngle=M_PI / 12

    var currentSeesawAngle = 0.0

    var animate:Bool = false{

    

    didSet(oldAnimate){

            if animate != oldAnimate && animate {

                if currentSeesawAngle == 0  {

                    //@Bailey

                    //设置捕捉动态记录和显示的参数

                    XCPCaptureValue("Left Seesaw Position",0 )

                    animateSeesawToAngle(CGFloat(maxSeesawAngle),duration: 0.75)

                }

                else

                {

                    animateSeesawToAngle(CGFloat(currentSeesawAngle * -1))

                }

            }

        }

    }

    

    func animateSeesawToAngle(angle:CGFloat,duration:CFTimeInterval = 1.5 )-> CAAnimation{

        let angleAnimation = CABasicAnimation(keyPath:"transform")

        angleAnimation.fromValue=NSValue(CATransform3D:seesawLayer.transform)

        angleAnimation.toValue=NSValue(CATransform3D:CATransform3DMakeRotation(angle, 0.0, 0.0, 1.0))

        angleAnimation.timingFunction = CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseInEaseOut)

        angleAnimation.duration = duration

        angleAnimation.delegate=self

        seesawLayer.addAnimation(

            angleAnimation, forKey: "transform")

        seesawLayer.transform=CATransform3DMakeRotation(angle,0.0, 0.0, 1.0)

        currentSeesawAngle=Double(angle)  //tag

        return angleAnimation

    }

    

    override func animationDidStop(_:CAAnimation!,finished:Bool){

        if finished && animate {

            //@Bailey

            //设置捕捉动态记录和显示的参数

            XCPCaptureValue("Left Seesaw Position",-currentSeesawAngle )

            animateSeesawToAngle( CGFloat(currentSeesawAngle * -1)  )

        }

    }

 }

 

 extension NSColor {

    class func playgroundIconFillColoer()->NSColor{

        return NSColor(red:12/255,green:65/255,blue:135/255,alpha:1.0)

    }

    

    class func playgroundIconStrokeColor()->NSColor{

        return NSColor(red:9/255,green:44/255,blue:91/255,alpha:1.0)

    }

 }

 

 func CGPathFromNSBezierPath(nsPath:NSBezierPath)->CGPath! {

    if nsPath.elementCount==0{

        return nil

    }

    let path=CGPathCreateMutable()

    var didClosePath=false

    for i in 0..<nsPath.elementCount{

        var points=[NSPoint](count:3,repeatedValue:NSZeroPoint)

        switch nsPath.elementAtIndex(i, associatedPoints: &points){

        case .MoveToBezierPathElement:

            CGPathMoveToPoint(path,nil,points[0].x,points[0].y)

        case .LineToBezierPathElement:

            CGPathAddLineToPoint(path, nil, points[0].x, points[0].y)

        case .CurveToBezierPathElement:

            CGPathAddCurveToPoint(path,nil, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y)

        case .ClosePathBezierPathElement:

            CGPathCloseSubpath(path)

            didClosePath=true

        }

    }

    if !didClosePath{

        CGPathCloseSubpath(path)

    }

    return CGPathCreateCopy(path)

 }

 

 let view=PlaygroundIconView(coder: NSCoder())

 

 view?.animate=true

 

 //@Bailey

 //显示游乐场跷跷板动态图标以及时间轴用于程序计算回溯

 XCPShowView("20140605",view!)

 view