xcode

[Swift]グラフもレンダリングもイケる!Playgroundが超絶便利!

巷で噂の新iOSアプリ開発言語「Swift」ですが、そのSwiftを使って色々と出来るPlaygroundという新機能が、Xcode6に追加されました。

今回は、そのPlaygroundを使ってどういった事ができるのか、色々試してみました。


Playgroundとは

・Swiftのインタラクティブインタプリタ
・コードを書くとすぐに結果を表示
・グラフの表示やSprite Kitを使ったアニメーションも可能 swift_playground


Playgroundの作成

Xcode起動時に表示される「Welocome to Xcode」ウィンドウの「Get started with a playground」からPlaygroundを作成します。

「Welocome to Xcode」が表示されない場合は、メニューの「Window->Welcome to Xcode」から表示出来ます。

また、「File->New->Playground…」からPlaygroundを作成することもできます。

playground_welocome_to_xcode

create_play_ground
Playground名を入力、Platformを「iOS」にして作成。


Playgroundの画面

画面左側を編集をすると、すぐに右側に結果が表示されます。
playground_editor

タイムラインの表示

「View->Assistant Editor->Show Assistant Editor」でタイムラインが表示されます。

タイムラインでは、コンソールへの出力結果の他に、行ごとの実行結果を表示することが出来ます。

行の右端をマウスオーバーすると表示される+ボタンをクリックすると、タイムラインにその行の実行結果が追加されます。

playground_timeline

 

UI系であればどのように表示されるかを確認することが出来ます。

また、パラメータが変更さえる箇所をタイムラインに追加していくことで、その過程を見る事もできます。

このようなことは、実際にビルドしシミュレータで実行してと手間がかかりますが、Playgroundを使えばすぐに簡単に行えます。


グラフの表示

ループ処理をタイムラインに追加するとグラフが表示され、グラフのポイントをクリックすることで、その値を確認することが出来ます。
playground_graph

こんなグラフだって書けたりします。(分割されてはいますが、、、)
playgroung_heart_formula playgroung_heart_graph


Playgroundをもっと便利にするXCPlaygroundフレームワーク

Playgroundには、XCPlaygroundというユーティリティフレームワークが用意されており、インポートするだけで様々な機能が利用できます。

値のキャプチャリング

「XCPCaptureValue(identifier: String, value: T)」では、同じidentifierで指定をしたものをグルーピングしてタイムライン上に表示してくれます。

以下は、LCG(線形合同法)での値の変化をキャプチャしたものです。

import XCPlayground
var seed: UInt = 1
func lcg() -> UInt {
    let a: UInt = 1664525
    let c: UInt = 1013904223
    let m: UInt = 4294967296
    seed = (a * seed + c) % m
    XCPCaptureValue("lcg", seed)
    return seed
}
for i in 0..<100 {
    lcg()
}

playground_value_capture

値の推移を確認することが確認でき、アルゴリズムのチェックなどに役立ちそうです。
また、数値以外の文字列など全ての型でキャプチャリングすることが出来ます。

非同期処理の実行

Playgroundでは、そのままでは同期処理しか実行出来ませんが、「XCPSetExecutionShouldContinueIndefinitely(continueIndefinitely: Bool)」でtrueを設定することにより、非同期処理の実行も行えるようになります。

XCPSetExecutionShouldContinueIndefinitely(continueIndefinitely: true)
println("開始")
let time1 = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * NSEC_PER_SEC))
let time2 = dispatch_time(DISPATCH_TIME_NOW, Int64(2 * NSEC_PER_SEC))
let time3 = dispatch_time(DISPATCH_TIME_NOW, Int64(3 * NSEC_PER_SEC))
dispatch_after(time1, dispatch_get_main_queue(), { () -> Void in
 println("1秒経過...")
})
dispatch_after(time2, dispatch_get_main_queue(), { () ->Void in
 println("2秒経過...")
});
dispatch_after(time3, dispatch_get_main_queue(), { () -> Void in
 println("3秒経過...")
});
 

上記のコードでは、1秒毎にログを出力します。

class ValueTimer: NSObject {
    var value: Int = 0
    var count: Int = 1
    func start() {
        XCPCaptureValue("value timer", value)
        NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("timerFunction"), userInfo: nil, repeats: true)
    }
    func timerFunction() {
        value += count++
        XCPCaptureValue("value timer", value)
    }
}
XCPSetExecutionShouldContinueIndefinitely(continueIndefinitely: true)
var timer = ValueTimer()
timer.start()
 

もちろんタイマーも使えます。
XCPCaptureValueを使うことで、動的にグラフを描くことも出来ます。

Viewのライブレンダリング

XCPCaptureValueでもViewを表示する事が出来ますが、その時点でのViewの状態が表示されるだけです。
そのため、パラメータを変更し、それを反映させるには再度XCPCaptureValueを使って最新のViewを表示し直す必要があります。

そこで、「XCPShowView(identifier: String, view: UIView)」を使うと、指定したViewを監視しパラメータが変更された際に、最新の状態へ再描画するといったようなことが出来るようになります。

var view = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
XCPShowView("live rendering", view)
view.backgroundColor = UIColor.redColor()
view.layer.borderColor = UIColor.blackColor().CGColor
view.layer.borderWidth = 1.0
view.layer.cornerRadius = 5.0
 

playground_live_rendering
XCPShowViewを使う際の注意点として、監視するViewにはsuperViewを設定してはいけません。
XCPShowViewで、監視されるViewが自動的にタイムライン上のウィンドウに貼り付けられるためです。
また、frameも先に決定する必要があり、後から変更すると正しく反映されません。


Playgroundでのアニメーション

先ほどのXCPShowViewを使うことで、CALayerやSpriteKitのアニメーションを確認することが出来ます。

しかし、残念なことにUIKit上つまりiOSプラットフォームでは、UIViewアニメーションはもちろんCALayerやSpriteKitを使ったアニメーションを正しく実行することが出来ません。

但し、Xcode6のリリースノートに既知のバグであることが記されているので、いずれiOSプラットフォームでもアニメーションが実行出来るようになると思います。

以下、プラットフォームをOS Xでの簡単なCALayerアニメーションを行った例です。

import Cocoa
import XCPlayground
class View: NSView {
    var subLayer: CALayer!
    func setup() {
        self.wantsLayer = true
        subLayer = CALayer()
        subLayer.frame = CGRect(x:0, y:0, width:50, height:50)
        subLayer.position = CGPoint(x: self.frame.size.width/2.0, y: self.frame.size.height/2.0)
        subLayer.backgroundColor = NSColor.redColor().CGColor
        self.layer?.addSublayer(subLayer)
    }
    func animate() {
        var animation = CABasicAnimation(keyPath:"transform")
        animation.fromValue = NSValue(CATransform3D: CATransform3DIdentity)
        animation.toValue = NSValue(CATransform3D: CATransform3DMakeScale(2.0, 2.0, 1.0))
        animation.duration = 1.0
        animation.autoreverses = true
        animation.delegate = self
        subLayer.addAnimation(animation, forKey: "transform")
    }
    override func animationDidStop(anim: CAAnimation!, finished flag: Bool) {
        animate()
    }
}
var view = View(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
XCPShowView("animation", view)
view.setup()
view.animate()

色々試してみて

アルゴリズムの確認や、使ったことのないAPIを試すには良い環境かなと思います。
また、UI系の表示もサポートされていて、そういった確認をするのにも非常に便利です。

なにより、ビルドし直さなくてもすぐに結果が確認できるのが最高ですね!

[参考] WWDC2014 – Swift Playgrounds(https://developer.apple.com/videos/wwdc/2014/#408)

この記事を書いた人

タケシ
タケシ
まだまだ修行中のiOSエンジニア。
最近はAndroidに興味があったり(出来るとは言っていない)
気づいたら春に。。。
Pocket