Rodhos Soft

備忘録を兼ねた技術的なメモです。Rofhos SoftではiOSアプリ開発を中心としてAndroid, Webサービス等の開発を承っております。まずはご相談下さい。

Tensorflowをあらためてやってみた。

あらためてTensorflowをやってみた。以前より理解は進んでいる気がする。

#coding:UTF-8

import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

import tensorflow as tf

## 画像は28*28ピクセル = 784ピクセル
## この画像から0,...,9という番号を判断したい。

# 入力変数定義 float32型で、(None, 784)の2階のテンソルを作る。
x = tf.placeholder(tf.float32, [None, 784])
# 重み 初期値ゼロで(784,10)の2階のテンソルを作る。
W = tf.Variable(tf.zeros([784, 10]))
# バイアス 初期値0で(10)の1階のテンソルをつくる
b = tf.Variable(tf.zeros([10]))
# ソフトマックス活性化関数
y = tf.nn.softmax(tf.matmul(x, W) + b)


# 正解
right_answer = tf.placeholder(tf.float32, [None, 10])

# クロスエントロピーの定義 (最小二乗法でも良かったが)
cross_entropy = -tf.reduce_sum(right_answer*tf.log(y))

# 勾配降下法で重みを調整する
# 学習比率 0.01
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

#初期化
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)

# 学習中
for i in range(1000):
    # データを取得 1回で100個のデータ(バッチ)を持ってくる
    batch_xs, batch_ys = mnist.train.next_batch(100)
    # ステップを実行
    sess.run(train_step, feed_dict={x: batch_xs, right_answer: batch_ys})


## 結果表示 ##

# それぞれの分布から最も確率の高いもの同士を見比べ同じであるかを調べる。
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(right_answer,1))

# 正答率を計算する。
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))

# 精度表示
print(sess.run(accuracy, feed_dict={x: mnist.test.images, right_answer: mnist.test.labels}))

StoreKitメモ

参考

以下を参考にした。
d.hatena.ne.jp

以下がデータフォーマットがあり詳しい
ameblo.jp

qiita.com


SKProductRequest

initWithProductIdentifiers:でプロダクトIDを指定しプロダクト情報を取得するリクエスト(SKProductsRequest)を作成する。
これは非同期で結果がかえる。
didReceiveResponse、didFailWithError、requestDidFinish。
SKProductsResponceに結果が入っている。

SKProductsResponce

ここからSKProductが取れる。

SKProduct

ここからlocalizedTitle,localizedDescription, price, priceLocale, productIdentifier等が取得できる。

プレゼンタに加えてドメイン層を入れる

プレゼンタを導入した後は今回はさらにドメイン層(UseCase)を取り入れたい。

プレゼンタ

プレゼンタはUseCaseにまとめられた処理を用いてビューないしUseCaseからの返事を処理する。

ユースケース

UseCaseはビジネスロジックを記述するところでそれのみで単体テストできるもの。

アイコンの表示云々のロジックはビジネス層でデータ層のモデル(エンティティ)をアイコン表示するしない情報(これがビューモデル)に変換して(この部分をtranslatorとして切り出すのも可能)プレゼンタに返す。
プレゼンタはビューにビューモデルを渡す。
ビューはビューモデルの指示通りにビューを更新する。
各境界はプロトコルを用いてやりとりする。(このプロトコルを介するのがポイント、逆にプロトコルの設計次第でうまくいくかが変わりそう。)

導入として

1. プレゼンタが行う処理をユースケースに委譲
2. ユースケースはビューモデルを作りプレゼンタに返す。ビューモデルに変換する部分はトランスケーターとして切り出す。
3. 受け取ったビューモデルはビューに渡す。
4. ビューはビューモデルの支持通りに書き換える。
5. これらのやりとりは全てプロトコル(インターフェース)を介して行うようにする。

ユースケースつまりビジネスロジック部分はUIともデータ層(ネットワーク、外部フレームワーク)とも分離され、単体テストにかけることができる。アイコンの出しわけロジック、購入処理、ログイン処理などは全てユースケースとして分離される。

Adaptive Design

UITraitCollection

バイスの情報が入っている。

  1. Size class (H,V)
  2. iphone/ipad
  3. 倍率

Size Class

以下を参考
qiita.com

各種UI部品のUITaraitCollectionでの変化

以下を参考
qiita.com

  1. UISplitViewController Master/Detailの両方が見える時、Masterだけが見える時
  2. Presentation Controller
  3. UIAppearance

show

ViewControllerの階層関係を気にせず次のvcを呼ぶメソッド
親は適宜、targetViewController(forAction 、を実装し、そのshowができるvc(例えばナビゲーションvc)を見つける。
showを実装しているvcは委譲されて実行される。

FaceBookグラフ

単に以下のようにやるだけでJSONが返却される。

                let req = FBSDKGraphRequest(graphPath: "me"
                    , parameters: ["fields":"id,email,name"])
                req?.start(completionHandler: { (con, result, error) in
                    if let error = error {
                        print("error")
                        return
                    }
                    print("\(result)")

実際に取れる内容はグラフのエクスプローラでweb上で試してみることができる。
Graph APIエクスプローラ - 開発者向けFacebook

FaceBookログイン

基本はdevelopers.facebook.com
にすべて書いてある。

フレームワークとしてFBSDKCoreKit、FBSDKLoginKitあたりをDLして入れる。ここでpodを使っても良い。
info.plistの設定でFaceBookAppIDの文字列を間違えないようにする。

FBSDKCoreKitのFBSDKApplicationDelegateへAppDelegateのメッセージを流すようにする。

ログイン処理はFBSDKLoginKitを使う。
便利UIとしてFBSDKLoginButtonがすでに用意されている。FBSDKLoginButtonDelegateでログイン結果を受け取る。

ログインで得たトークンはキーチェインに保存されるので、キーチェインの使用を許可(Capabilitiesで)しておく。

FBSDKAccessTokenのcurrentで現在のトークンがわかるのでログイン済みかは判断できる。そこからユーザIDを取得できる。

ハフマン符号

"AABABCAC"を単純にbitを割り当てるとA 00, B 01, C 10のように1文字に2ビットで、計16ビットかかる。

出現頻度を調べる。

"AABABCAC"のAは4、Bは2、Cは2で現れる。

ハフマン木をつくる。

最も低い出現頻度とその次のものを取ってくる。今は,B,C。

{B,C}

次の出現頻度のものはAなので

{A,{B,C}}

というハフマン木ができる。

根元から0,1をふっていく。

A = 0

B = 10
C = 11

よってハフマン符号によって
0 0 10 0 10 11 0 11

で、計12ビットに圧縮できた。

復号方法

"0" 0 10 0 10 11 0 11 ... ハフマン木に0*はないのでA確定

A "0" 10 0 10 11 0 11 

A A 10 0 10 11 0 11 

以下同様にハフマン木を見ていけば復号できる。
A A B A A B A B 

参考したサイト

michisugara.jp

insertion sort 挿入ソート

O(n^2)な実行時間。ほぼ整列している場合は非常に速い。

1. 先頭から整列してない数を探す。
2. その数を整列させるように差し込む。

  • 2,3,5,4,2
  • 2,3,5,"4",2
  • 2,3,"4",5,2 
  • 2,3,4,5,2
  • 2,3,4,5,"2"
  • "2",2,3,4,5

ドメイン駆動

参考にしたもの
ドメイン駆動設計 ( DDD ) をやってみよう
ドメイン駆動設計のためのオブジェクト指向入門
実践に向けたドメイン駆動設計のエッセンス



3つのレイヤー

ポイント

ドメインを隔離する。UIとデータ形式から。生のデータを使わない。結果は加工されたモデルを渡す。
計算、加工、判断のロジックを一箇所に集めること。実現手段の隠蔽。各自の型の定義(基本データ型を使わない)。値オブジェクト。一覧オブジェクト。
(if,list,string,etc)も使わない。

プレゼン層はプレゼンタからドメイン層を使うがドメイン層はプレゼン層をつかわない。
ドメイン層のユースケースリポジトリを介してデータを受け取るがそれはモデルの形にしてプレゼン層に渡す。
トランスレータはモデルの変換を行う。

業務の関心事にドメインオブジェクトを作り、公開メソッドは業務と関連するものにする。

ルールのクラス化

  • Procedure(手順) 状態を持たない
  • Policy(ポリシー) ルールの集まり。状態を持たない
  • Rule(ルール) 集まって一つのポリシーを作る

集約(アグリゲート)

一緒に使うもの部品をあつめた一つのクラス

ReSwiftの流れ

ReSwiftというSwiftのRedux実装のライブラリを触ってみました。

github.com

  1. アプリはStoreを一個持ちStoreはこちらで定義した状態(State)を持ちます。
  2. 各種のReducerというのをStoreに登録します。
  3. ReducerはActionが発行されたらどのようにStateを変更するのか各自で定義します。
  4. ボタンがタップされたなどのイベントが起きたとき、プログラマはアクションをストアに送ります(dispatch)、するとストアではReducerに今の状態とアクションを食わせて新しい状態にします。
  5. 新しい状態はそれを監視(subscribe)しているオブジェクトにnewStateとして通知されるという具合です。

擬似コードでのまとめ

State定義

Action定義

各種Reducer定義

Reducer (Action, State) -> State

Store作成

Store = {State, Reducers}

状態更新を受取りたい場合

Store.subscribe(User)

タップのイベント等が起きたことを通知

Store.dispatch(Action)

reducerによってState更新され状態変更が通知される。

ViewControllerはアクションを発行し状態変更通知を受けたら状態に基づいてUIを変更するという流れになります。

参照

簡単なコードサンプルとして
GitHub - ReSwift/CounterExample: Demo Application of Unidirectional Data Flow in Swift, Built with ReSwift

より実際的な実装例は以下にありました。
qiita.com

マルチスレッドのデザインパターン

以下を参照しつつマルチスレッドのデザインパターンを概観し、適宜Swiftでの実装を考える。


Single Threaded Execution (同時にできない)

クリティカルセクション

Immutable (不変)

Guarded Suspension (用意できるまで待つ)

Balking (用意できないならやめる)

Producer-Consumer (生産者と消費者をわける)

Read-Write Lock (書く人は一人、読むのは誰でも)

Thread-Per-Message (処理を他のスレッドに任せる)

Worker Thread (スレッドを貯めておいて仕事を振る)

Future (任せておいた仕事の結果を同期的に受け取る)

Two-Phase Termination (適切な終了処理)

Thread-Specific Storage (スレッド毎に保存できる領域を確保しておく)

Active Object (自律的なオブジェクト)

Switで実装してみた。
github.com

GLKitミニマム2 OpenGL

テンプレートからOpenGL部分を残し、データを三角形の回転するだけに変えてみたもの。

頂点シェーダー

attribute vec4 position;

uniform mat4 modelViewProjectionMatrix;

void main()
{
    gl_Position = modelViewProjectionMatrix * position;
}

フラグメントシェーダー

void main()
{
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}


GLKViewController本体

import GLKit
import OpenGLES

func BUFFER_OFFSET(i: Int) -> UnsafePointer<Void> {
    let p: UnsafePointer<Void> = nil
    return p.advancedBy(i)
}

let UNIFORM_MODELVIEWPROJECTION_MATRIX = 0
let UNIFORM_NORMAL_MATRIX = 1
var uniforms = [GLint](count: 2, repeatedValue: 0)

class GameViewController: GLKViewController {
    
    var program: GLuint = 0
    
    var modelViewProjectionMatrix:GLKMatrix4 = GLKMatrix4Identity
    var normalMatrix: GLKMatrix3 = GLKMatrix3Identity
    var rotation: Float = 0.0
    
    var vertexArray: GLuint = 0
    var vertexBuffer: GLuint = 0
    
    var context: EAGLContext? = nil
    var effect: GLKBaseEffect? = nil
    
    deinit {
        self.tearDownGL()
        
        if EAGLContext.currentContext() === self.context {
            EAGLContext.setCurrentContext(nil)
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.context = EAGLContext(API: .OpenGLES2)
        
        if !(self.context != nil) {
            print("Failed to create ES context")
        }
        
        let view = self.view as! GLKView
        view.context = self.context!
        view.drawableDepthFormat = .Format24
        
        self.setupGL()
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        
        if self.isViewLoaded() && (self.view.window != nil) {
            self.view = nil
            
            self.tearDownGL()
            
            if EAGLContext.currentContext() === self.context {
                EAGLContext.setCurrentContext(nil)
            }
            self.context = nil
        }
    }
    
    func setupGL() {
        EAGLContext.setCurrentContext(self.context)
        
        self.loadShaders()
        
        self.effect = GLKBaseEffect()
        self.effect!.light0.enabled = GLboolean(GL_TRUE)
        self.effect!.light0.diffuseColor = GLKVector4Make(1.0, 0.4, 0.4, 1.0)
        
        glEnable(GLenum(GL_DEPTH_TEST))
        
        glGenVertexArraysOES(1, &vertexArray)
        glBindVertexArrayOES(vertexArray)
        
        glGenBuffers(1, &vertexBuffer)
        glBindBuffer(GLenum(GL_ARRAY_BUFFER), vertexBuffer)
        glBufferData(GLenum(GL_ARRAY_BUFFER), GLsizeiptr(sizeof(GLfloat) * gVertexData.count), &gVertexData, GLenum(GL_STATIC_DRAW))
        
        glEnableVertexAttribArray(GLuint(GLKVertexAttrib.Position.rawValue))
        glVertexAttribPointer(GLuint(GLKVertexAttrib.Position.rawValue),
                              3,
                              GLenum(GL_FLOAT),
                              GLboolean(GL_FALSE),
                              GLsizei(sizeof(GLfloat)*3),
                              BUFFER_OFFSET(0))
        
        glBindVertexArrayOES(0)
    }
    
    func tearDownGL() {
        EAGLContext.setCurrentContext(self.context)
        
        glDeleteBuffers(1, &vertexBuffer)
        glDeleteVertexArraysOES(1, &vertexArray)
        
        self.effect = nil
        
        if program != 0 {
            glDeleteProgram(program)
            program = 0
        }
    }
    
    // MARK: - GLKView and GLKViewController delegate methods
    
    func update() {
        let aspect = fabsf(Float(self.view.bounds.size.width / self.view.bounds.size.height))
        let projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0), aspect, 0.1, 100.0)
        
        self.effect?.transform.projectionMatrix = projectionMatrix
        
        var baseModelViewMatrix = GLKMatrix4MakeTranslation(0.0, 0.0, -4.0)
        baseModelViewMatrix = GLKMatrix4Rotate(baseModelViewMatrix, rotation, 0.0, 1.0, 0.0)
        
        
        // Compute the model view matrix for the object rendered with ES2
        var modelViewMatrix = GLKMatrix4MakeTranslation(0.0, 0.0, 1.5)
        modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, rotation, 1.0, 1.0, 1.0)
        modelViewMatrix = GLKMatrix4Multiply(baseModelViewMatrix, modelViewMatrix)
        
        normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelViewMatrix), nil)
        
        modelViewProjectionMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix)
        
        rotation += Float(self.timeSinceLastUpdate * 0.5)
    }
    
    override func glkView(view: GLKView, drawInRect rect: CGRect) {
        glClearColor(0.65, 0.65, 0.65, 1.0)
        glClear(GLbitfield(GL_COLOR_BUFFER_BIT) | GLbitfield(GL_DEPTH_BUFFER_BIT))
        
        glBindVertexArrayOES(vertexArray)
        
        // Render the object again with ES2
        glUseProgram(program)
        
        withUnsafePointer(&modelViewProjectionMatrix, {
            glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, UnsafePointer($0))
        })
        
        withUnsafePointer(&normalMatrix, {
            glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, UnsafePointer($0))
        })
        
        glDrawArrays(GLenum(GL_TRIANGLES), 0, Int32(gVertexData.count/3))
    }
    
    // MARK: -  OpenGL ES 2 shader compilation
    
    func loadShaders() -> Bool {
        var vertShader: GLuint = 0
        var fragShader: GLuint = 0
        var vertShaderPathname: String
        var fragShaderPathname: String
        
        // Create shader program.
        program = glCreateProgram()
        
        // Create and compile vertex shader.
        vertShaderPathname = NSBundle.mainBundle().pathForResource("Shader", ofType: "vsh")!
        if self.compileShader(&vertShader, type: GLenum(GL_VERTEX_SHADER), file: vertShaderPathname) == false {
            print("Failed to compile vertex shader")
            return false
        }
        
        // Create and compile fragment shader.
        fragShaderPathname = NSBundle.mainBundle().pathForResource("Shader", ofType: "fsh")!
        if !self.compileShader(&fragShader, type: GLenum(GL_FRAGMENT_SHADER), file: fragShaderPathname) {
            print("Failed to compile fragment shader")
            return false
        }
        
        // Attach vertex shader to program.
        glAttachShader(program, vertShader)
        
        // Attach fragment shader to program.
        glAttachShader(program, fragShader)
        
        // Bind attribute locations.
        // This needs to be done prior to linking.
        glBindAttribLocation(program, GLuint(GLKVertexAttrib.Position.rawValue), "position")
        glBindAttribLocation(program, GLuint(GLKVertexAttrib.Normal.rawValue), "normal")
        
        // Link program.
        if !self.linkProgram(program) {
            print("Failed to link program: \(program)")
            
            if vertShader != 0 {
                glDeleteShader(vertShader)
                vertShader = 0
            }
            if fragShader != 0 {
                glDeleteShader(fragShader)
                fragShader = 0
            }
            if program != 0 {
                glDeleteProgram(program)
                program = 0
            }
            
            return false
        }
        
        // Get uniform locations.
        uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX] = glGetUniformLocation(program, "modelViewProjectionMatrix")
        uniforms[UNIFORM_NORMAL_MATRIX] = glGetUniformLocation(program, "normalMatrix")
        
        // Release vertex and fragment shaders.
        if vertShader != 0 {
            glDetachShader(program, vertShader)
            glDeleteShader(vertShader)
        }
        if fragShader != 0 {
            glDetachShader(program, fragShader)
            glDeleteShader(fragShader)
        }
        
        return true
    }
    
    
    func compileShader(inout shader: GLuint, type: GLenum, file: String) -> Bool {
        var status: GLint = 0
        var source: UnsafePointer<Int8>
        do {
            source = try NSString(contentsOfFile: file, encoding: NSUTF8StringEncoding).UTF8String
        } catch {
            print("Failed to load vertex shader")
            return false
        }
        var castSource = UnsafePointer<GLchar>(source)
        
        shader = glCreateShader(type)
        glShaderSource(shader, 1, &castSource, nil)
        glCompileShader(shader)
        
        //#if defined(DEBUG)
        //        var logLength: GLint = 0
        //        glGetShaderiv(shader, GLenum(GL_INFO_LOG_LENGTH), &logLength)
        //        if logLength > 0 {
        //            var log = UnsafeMutablePointer<GLchar>(malloc(Int(logLength)))
        //            glGetShaderInfoLog(shader, logLength, &logLength, log)
        //            NSLog("Shader compile log: \n%s", log)
        //            free(log)
        //        }
        //#endif
        
        glGetShaderiv(shader, GLenum(GL_COMPILE_STATUS), &status)
        if status == 0 {
            glDeleteShader(shader)
            return false
        }
        return true
    }
    
    func linkProgram(prog: GLuint) -> Bool {
        var status: GLint = 0
        glLinkProgram(prog)
        
        //#if defined(DEBUG)
        //        var logLength: GLint = 0
        //        glGetShaderiv(shader, GLenum(GL_INFO_LOG_LENGTH), &logLength)
        //        if logLength > 0 {
        //            var log = UnsafeMutablePointer<GLchar>(malloc(Int(logLength)))
        //            glGetShaderInfoLog(shader, logLength, &logLength, log)
        //            NSLog("Shader compile log: \n%s", log)
        //            free(log)
        //        }
        //#endif
        
        glGetProgramiv(prog, GLenum(GL_LINK_STATUS), &status)
        if status == 0 {
            return false
        }
        
        return true
    }
    
    func validateProgram(prog: GLuint) -> Bool {
        var logLength: GLsizei = 0
        var status: GLint = 0
        
        glValidateProgram(prog)
        glGetProgramiv(prog, GLenum(GL_INFO_LOG_LENGTH), &logLength)
        if logLength > 0 {
            var log: [GLchar] = [GLchar](count: Int(logLength), repeatedValue: 0)
            glGetProgramInfoLog(prog, logLength, &logLength, &log)
            print("Program validate log: \n\(log)")
        }
        
        glGetProgramiv(prog, GLenum(GL_VALIDATE_STATUS), &status)
        var returnVal = true
        if status == 0 {
            returnVal = false
        }
        return returnVal
    }
}

var gVertexData: [GLfloat] = [
    -0.5, -0.0, 0.0,
    0.5,-0.5,0.0,
    -0.5,0.5,0.0
]

GLKitミニマム

テンプレートを三角形が回転するだけのコードに削ってみた。

import GLKit
import OpenGLES

func BUFFER_OFFSET(i: Int) -> UnsafePointer<Void> {
    let p: UnsafePointer<Void> = nil
    return p.advancedBy(i)
}

class GameViewController: GLKViewController {
    
    var rotation: Float = 0.0
    
    var vertexArray: GLuint = 0
    var vertexBuffer: GLuint = 0
    
    var context: EAGLContext? = nil
    var effect: GLKBaseEffect? = nil
    
    deinit {
        self.tearDownGL()
        
        if EAGLContext.currentContext() === self.context {
            EAGLContext.setCurrentContext(nil)
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.context = EAGLContext(API: .OpenGLES2)
        
        if !(self.context != nil) {
            print("Failed to create ES context")
        }
        
        let view = self.view as! GLKView
        view.context = self.context!
        view.drawableDepthFormat = .Format24
        
        self.setupGL()
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        
        if self.isViewLoaded() && (self.view.window != nil) {
            self.view = nil
            
            self.tearDownGL()
            
            if EAGLContext.currentContext() === self.context {
                EAGLContext.setCurrentContext(nil)
            }
            self.context = nil
        }
    }
    
    func setupGL() {
        EAGLContext.setCurrentContext(self.context)
        
        self.effect = GLKBaseEffect()
        self.effect!.light0.enabled = GLboolean(GL_TRUE)
        self.effect!.light0.diffuseColor = GLKVector4Make(1.0, 0.4, 0.4, 1.0)
        
        glEnable(GLenum(GL_DEPTH_TEST))
        
        glGenVertexArraysOES(1, &vertexArray)
        glBindVertexArrayOES(vertexArray)
        
        
        glGenBuffers(1, &vertexBuffer)// 頂点バッファポインタ生成
        glBindBuffer(GLenum(GL_ARRAY_BUFFER), vertexBuffer)// 有効化

        // バッファに転送
        glBufferData(GLenum(GL_ARRAY_BUFFER),
                     GLsizeiptr(sizeof(GLfloat) * gVertexData.count),
                     &gVertexData,
                     GLenum(GL_STATIC_DRAW))
        
        // 属性指定に頂点の位置を用いる事を指定
        glEnableVertexAttribArray(GLuint(GLKVertexAttrib.Position.rawValue))
        
        //
        glVertexAttribPointer(GLuint(GLKVertexAttrib.Position.rawValue),
                              3,// 1頂点あたりの要素の数 三次元なのでx,y,zの3
                              GLenum(GL_FLOAT),
                              GLboolean(GL_FALSE), // ノーマライズされているか
                              GLsizei(sizeof(GLfloat)*3), // 格納されているデータの間隔
                              BUFFER_OFFSET(0)) // データは並んでいる。
        
        glBindVertexArrayOES(0)
    }
    
    func tearDownGL() {
        EAGLContext.setCurrentContext(self.context)
        
        glDeleteBuffers(1, &vertexBuffer)
        glDeleteVertexArraysOES(1, &vertexArray)
        
        self.effect = nil
    }
    
    // MARK: - GLKView and GLKViewController delegate methods
    
    func update() {
        
        let aspect = fabsf(Float(self.view.bounds.size.width / self.view.bounds.size.height))
        let projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0), aspect, 0.1, 100.0)
        
        self.effect?.transform.projectionMatrix = projectionMatrix
        
        var baseModelViewMatrix = GLKMatrix4MakeTranslation(0.0, 0.0, -4.0)
        baseModelViewMatrix = GLKMatrix4Rotate(baseModelViewMatrix, rotation, 0.0, 1.0, 0.0)
        
        // Compute the model view matrix for the object rendered with GLKit
        var modelViewMatrix = GLKMatrix4MakeTranslation(0.0, 0.0, -1.5)
        modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, rotation, 1.0, 1.0, 1.0)
        modelViewMatrix = GLKMatrix4Multiply(baseModelViewMatrix, modelViewMatrix)
        
        self.effect?.transform.modelviewMatrix = modelViewMatrix
        
        rotation += Float(self.timeSinceLastUpdate * 0.5)
    }
    
    override func glkView(view: GLKView, drawInRect rect: CGRect) {
        glClearColor(0.65, 0.65, 0.65, 1.0)
        glClear(GLbitfield(GL_COLOR_BUFFER_BIT) | GLbitfield(GL_DEPTH_BUFFER_BIT))
        
        glBindVertexArrayOES(vertexArray)
        
        // Render the object with GLKit
        self.effect?.prepareToDraw()
        
        glDrawArrays(GLenum(GL_TRIANGLES) , 0, Int32(gVertexData.count/3))
    }
}


var gVertexData: [GLfloat] = [
    -0.5, -0.0, 0.0,
    0.5,-0.5,0.0,
    -0.5,0.5,0.0
]