3

I'm relatively new in app development but for interest I want to implement this application on a playground project on Xcode:

http://merowing.info/2015/11/the-beauty-of-imperfection/

All the errors are corrected, but when I press the run Playground button it says "Running" forever without displaying anything. Do you know what I'm doing wrong?

import UIKit
import XCPlayground
import QuartzCore
import PlaygroundSupport

class Animator {
    class TargetProxy {
        init (target: Animator) {
            self.target = target
        }

        weak var target: Animator!
        var totalTime: TimeInterval = 0

        @objc func onFire (dl: CADisplayLink) {
            totalTime += dl.duration
            target.block(totalTime)
        }
    }

    private lazy var displayLink: CADisplayLink = {
        return CADisplayLink(target: TargetProxy(target: self), selector:      #selector(TargetProxy.onFire))}()
    private let block: (TimeInterval) -> Void

    init (block: @escaping (TimeInterval) -> Void) {
        self.block = block
        displayLink.add(to: RunLoop.main, forMode: RunLoopMode.commonModes)
    }

    deinit {
        displayLink.invalidate()
    }
}

func createBlobShape() -> UIBezierPath {
    let ovalPath = UIBezierPath()
    ovalPath.move(to: CGPoint.init(x: 13.71, y: -29.07))
    ovalPath.addCurve(to: CGPoint.init(x: 27.92, y: -14), controlPoint1:   CGPoint.init(x: 20.64, y: -25.95), controlPoint2: CGPoint.init(x: 24.57,   y: -20.72))
    ovalPath.addCurve(to: CGPoint.init(x: 33, y: 0.5), controlPoint1:  CGPoint.init(x: 30.08, y: -9.68), controlPoint2: CGPoint.init(x: 33, y:  -4.64))
    ovalPath.addCurve(to: CGPoint.init(x: 20.82, y: 26), controlPoint1:  CGPoint.init(x: 333, y: 10.93), controlPoint2: CGPoint.init(x: 27.47, y:  17.84))
    ovalPath.addCurve(to: CGPoint.init(x: 0, y: 33), controlPoint1:  CGPoint.init(x: 16.02, y: 31.88), controlPoint2: CGPoint.init(x: 7.63, y:  33))
    ovalPath.addCurve(to: CGPoint.init(x: -16.72, y: 28.33),  controlPoint1: CGPoint.init(x: -6.21, y: 33), controlPoint2:  CGPoint.init(x: -11.89, y: 31.29))
    ovalPath.addCurve(to: CGPoint.init(x: -23.86, y: 22), controlPoint1:  CGPoint.init(x: -19.59, y: 26.57), controlPoint2: CGPoint.init(x: -22.22,  y: 24.28))
    ovalPath.addCurve(to: CGPoint.init(x: -28, y: 17), controlPoint1:  CGPoint.init(x: -25.19, y: 20.16), controlPoint2: CGPoint.init(x: -26.74,  y: 19.46))
    ovalPath.addCurve(to: CGPoint.init(x: -33, y: 0.5), controlPoint1:  CGPoint.init(x: -30.24, y: 12.61), controlPoint2: CGPoint.init(x: -33, y:  5.74))
    ovalPath.addCurve(to: CGPoint.init(x: -23.86, y: -23), controlPoint1:  CGPoint.init(x: -33, y: -9.63), controlPoint2: CGPoint.init(x: -31.23, y:  -17.04))
    ovalPath.addCurve(to: CGPoint.init(x: -4.57, y: -33), controlPoint1:  CGPoint.init(x: -18.17, y: -27.6), controlPoint2: CGPoint.init(x: -12.51,  y: -33))
    ovalPath.addCurve(to: CGPoint.init(x: 13.71, y: -29.07),    controlPoint1: CGPoint.init(x: 0.32, y: -33), controlPoint2:      CGPoint.init(x: 9.53, y: -30.95))
    ovalPath.close()

    return ovalPath
}

func toRadian(degree: Int) -> Float {
    return Float(Double(degree) * (Double.pi / 180.0))
}

let blob = CAShapeLayer()
let blobShape = createBlobShape()
blob.path = blobShape.cgPath
blob.frame = blobShape.bounds
blob.anchorPoint = CGPoint.init(x: 0, y: 0)
blob.fillColor = UIColor.orange.cgColor

var view = UIView(frame: CGRect(x: 0, y: 0, width: 640, height:  480))
view.backgroundColor = UIColor.gray
//grayColor().colorWithAlphaComponent(0.8)
PlaygroundPage.current.liveView = view

blob.position = view.center
view.layer.addSublayer(blob)

let playImageView = UIImageView(image: UIImage(named: "play"))
playImageView.transform = CGAffineTransform.init(scaleX: 0.05, y:    0.05)
playImageView.center = blob.position
view.addSubview(playImageView)

PlaygroundPage.current.needsIndefiniteExecution = true
//XCPlaygroundPage.currentPage.needsIndefiniteExecution = true

let dl = Animator {
    let skewBaseTime = $0 * 0.3

    let rotation = CATransform3DMakeRotation(CGFloat(acos(cos(skewBaseTime))), 0, 0, 1)
    let upscale = 5.0
    let scaleAdjustment = 0.1
    let scale = CATransform3DMakeScale(CGFloat(upscale +  abs(sin(skewBaseTime) * scaleAdjustment)), CGFloat(upscale +  abs(cos(skewBaseTime) * scaleAdjustment)), 1)

    let skewTransform = CGAffineTransform.init(a: 1.0, b: 0.0, c:  CGFloat(cos(skewBaseTime + Double.pi) * 0.1), d: 1.0, tx: 0.0, ty: 0.0)

    CATransaction.begin()
    CATransaction.setValue(kCFBooleanTrue, forKey:   kCATransactionDisableActions)
    view.layer.sublayerTransform =  CATransform3DConcat(CATransform3DMakeAffineTransform(skewTransform),   scale)
    blob.transform = rotation
    CATransaction.commit()
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
Parzival
  • 43
  • 4

3 Answers3

1

Your code works. What you need to do is to open the "Assistant Editor" from the "View" menu to see the result.

enter image description here

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
0

You should correct:

private lazy var displayLink: CADisplayLink = {
    return CADisplayLink(target: TargetProxy(target: self), selector: #selector(TargetProxy.onFire))}()

With:

var displayLink: CADisplayLink {
    let target = TargetProxy(target: self)
    return CADisplayLink(target: target, selector: #selector(target.onFire))
}
sabi
  • 423
  • 2
  • 8
  • I replaced it but it still doesn't show anything. However, at least I now see some numbers increasing (calculations going on) in the last part of the code (animation part). Any idea, why I don't see the bubble?? – Parzival Feb 09 '18 at 07:26
  • In dl = Animator(... change upscale value to 1.0 and you'll see something. – sabi Feb 09 '18 at 12:23
0

By default, Playgrounds are in sync with iCloud. Sometimes it can lead to this "stucks on "Running" bug.

Just go to:

System Preferences - Apple ID - Apps on this Mac using iCloud- iCloud Drive - Options- And then uncheck "Playground"

That little trick prevents syncing and resolves the frozen state of Xcode.

Prevent Playground from Sync

Vitya Shurapov
  • 2,200
  • 2
  • 27
  • 32