• 検索結果がありません。

スライド 1

N/A
N/A
Protected

Academic year: 2021

シェア "スライド 1"

Copied!
138
0
0

読み込み中.... (全文を見る)

全文

(1)

プレゼンテーション資料

21回 エンバカデロ・デベロッパーキャンプ

2012年3月9日~10日

(2)
(3)

時間 セッション概要 14:00~14:30 【G1】オープニングセッション 「2012年 - エンバカデロの製品戦略」 エンバカデロ・テクノロジーズ 日本法人代表 藤井 等 14:30~15:30 【T2】テクニカルセッション 「実践!Delphiデバッグテクニック」 株式会社シリアルゲームズ 取締役・シニアエンジニア 細川 淳 15:30~15:40 休憩 15:40~16:40 【T3】テクニカルセッション 「Delphi/C++Builder + FastReportで作る実用レポート出力」 株式会社ドリームハイブ 代表取締役 山本 悟 16:40~16:50 休憩 16:50~17:50 【T4】テクニカルセッション 「FireMonkeyファーストインプレッション」 有限会社エイブル 富永 英明 17:50~18:00 休憩 18:00~20:00 【W5】 ワークショップ 「FireMonkeyアプリケーション構築実習」 司会:エンバカデロ・テクノロジーズ エヴァンジェリスト 高橋智宏 20:00~20:30 休憩・移動 プログラム 3月9日

(4)

時間 セッション概要 9:00~9:50 【W6】ワークショップ 「挑戦!Delphiクイズで実力チェック」 エンバカデロ・テクノロジーズ エヴァンジェリスト 高橋智宏 9:50~10:00 休憩 10:00~10:50 【T7】テクニカルセッション 「RadPHPでスマホアプリを作ろう!」 エンバカデロ・テクノロジーズ エヴァンジェリスト 高橋智宏 10:50~11:00 休憩 11:00~11:50 【T8】テクニカルセッション 「Delphi言語再入門」 株式会社シリアルゲームズ 取締役・シニアエンジニア 細川 淳 東洋テクニカルシステム株式会社 システム開発部 福士 光 11:50~12:00 休憩 12:00~12:50 【T9】テクニカルセッション 「Delphi/C++BuilderでiOS/Macアプリを作ろう!」 エンバカデロ・テクノロジーズ エヴァンジェリスト 高橋智宏 3月10日 ネットワークの使用について ・ セッション会場では、無線LANをご利用いただけますが、オンライン配信パフォーマンスに影響を与える恐れがあ るため、 会場無線LANを用いたUstream、GotoWebinar、YouTube等のビデオ視聴、その他のダウンロードなどはお控えください。 セッション資料のダウンロード ・ セッション資料の最新版ならびに配布資料に含まれないプレゼンテーション資料については、後日Embarcadero Developer

(5)

17Th Developer Camp

「RadPHPで

スマホアプリを作ろう!」

エンバカデロ・テクノロジーズ エヴァンジェリスト 高橋智宏 【T7】テクニカルセッション

(6)

アジェンダ

RadPHP XE2 に関するアップデート

Web画面のレイアウト調整

– 横幅が重要 • PHP & JavaScriptのイベントの実装詳細 – 画面右端に張り付くボタンを実機で確認

• iOS (iPhone 4, iPad 2)

• Android 2.2~ (スマホ, タブレット) • Windows Phone 7.5

• BlackBerry

少し本格的なWebアプリを作ってみる

– jQuery Mobile 特有の注意点!!

– TMS社のIntraWeb iPhone Controls Packのデモアプリと同様のものを

Webアプリをフルスクリーンで

デモ

(7)

17Th

Developer Camp

RadPHP XE2 に関する

アップデート

(8)

アップデート – 主な変更点

Update 4

– ビルド番号: 4.4.0.1656

ZendFrameworkのサンプルを追加

– ZHttp, ZJson, ZJsonServer, ZRestClient, ZRestServer

モバイル端末の背景を追加

– 各種Android端末

– BlackBerry

JQuery Mobile 1.0 final を統合

– jQuery 1.6.4 を内蔵

PhoneGap 1.3.0 を統合

(9)

17Th

Developer Camp

jQuery Mobile

(10)

jQuery Mobile とは?

• 2010年8月11日に始まったオープンソースプロジェクト

• jQueryをベースに、モバイルデバイスのWebブラウザに特化したGUIを

提供するJavaScriptライブラリおよびCSS

(11)

サポートされるプラットフォーム

(12)

横幅は重要

基本的に、モバイルWebアプリは横スクロールしません

– もちろん、縦スクロールはします

Web画面の横幅は、端末ごとに異なります

– さらに、iOS, Android, WP7 では、端末の回転により変化します – 横幅は、JavaScriptの window.innerWidth で取得可能

(13)

端末の回転を検知するには?

iOS

– jQuery Mobile の orientationchangeイベント を利用する

• window.onresizeイベントの監視は不要!!

Android 2.2~

– window.onresizeイベントを利用する • orientationchangeイベント が来ても無視する!! – innerWidthは回転前の値を示すので使えない…

Windows Phone 7.5

– window.onresizeイベントを利用する • そもそも orientationchangeイベント が発生しない…

BlackBerry

(14)

viewport metaタグのwidthパラメータ

スマホでもタブレットでも width=320 でOK !?

– WP7以外の端末 • window.innerWidth  端末の向きに応じた実際の横幅 – Windows Phone 7.5 • window.innerWidth  常に320 !? – 端末が横向きなら画面全体が拡大表示されてしまう!! • viewoport で width=device-width を指定すると… – window.innerWidth  端末の向きに応じた実際の横幅

(15)

画面右端に張り付くボタン

• PHP側の実装 • 手順その1 : MPageのOnCreateイベント – WP7に対処 • 手順その2 : MPageのOnStartBodyイベント – ボタンの移動を行う関数をJavaScriptで記述 – jQueryのAPIで、ボタンの外側のdivのCSSの left を変更

(16)

画面右端に張り付くボタン

• 手順その3 : MPageのOnOrientationChange Javascriptイベント – Android に対処 • 手順その4 : MPageのOnPageShow Javascriptイベント – Android, WP向けにonresizeイベントハンドラのインストール – とりあえず、すぐにボタンの移動を行う

(17)

実機で確認 – 画面サイズ, ボタンサイズ, 回転

• iPhone 4, iPad 2

• Androidスマホ, Androidタブレット

• Windows Phone 7.5

(18)

17Th

Developer Camp

少し本格的な

Webアプリ

(19)

jQuery Mobile 特有の注意点

複数のWebページのイメージが、単一のWeb画面内で同

居することがある

– Ajaxを利用した画面遷移 • 例: 横にスライドしながら新しいページが表示される場合 – そのため、あるページを設計・実装する際、その中に配置す るコンポーネント名は、複数ページ全体で一意になるように すべき。 • 同一のidを持つHTML要素が、同居して競合を起こすのを防ぐ • 独自に、コンポーネント名(変数名)の命名規約を設けてくださ い。

iOS 5.0 の iPhone の Safari 向けには、MPageの

touchOverflowEnabledプロパティを false に設定!!

(20)

まずは、お手本となるWebアプリを確認

Delphi XE2(C++Builder XE2)

– IntraWeb XII

– TMS IntraWeb iPhone Controls Pack(トライアル版)の

(21)

メインページ – デザイン

MListは、PHP側で動的に構築

MLink 画面遷移に使う。単にボタンとしても使える MobileTheme テーマを指定する。 カスタムテーマへの応用も可 MList リストビュー。行数は可変なので、高さが変わる 項目クリック時に編集ページに遷移させる。 MToolBar 複数のMlinkを配置できる Settingクリック時に設定ページに遷移させる

(22)

メインページ – コード

MPageのOnCreateイベントで、MListの項目を動的に生

(23)

設定ページ – デザイン

Saveボタン: PHPの $_SESSION 変数をAjaxで更新

MLink 遷移元(前)のページに戻る、特別なリンク MToggle 2つの値を管理できるトグルスイッチ MButton 画面情報をPHPに送信 AjaxモードでRadPHPのイベントハンドラを起動可

(24)

設定ページ – コード

トグルスイッチの値を $_SESSION で管理。最初に画

面を生成する際に、トグルスイッチの初期値を指定

[Back]ボタンに関する処理は無い

– Webブラウザ内だけで、前の画面を復帰させてしまう。 • 前の画面の内容を、PHP側で更新できないので注意!!

(25)

編集ページ – デザイン

Backボタンは、UpdateボタンでAjax更新後、モードを変更

MLink 遷移元(前)のページに戻る、特別なリンク MEdit 文字列を編集する MSlider 例: 最小値(0)~最大値(100) のスライダ MComboBox 項目を選択するコンボボックス。複数選択可 MButton 画面情報をPHPに送信 AjaxモードでRadPHPのイベントハンドラを起動可

(26)

編集ページ – コード

MSliderとMComboBoxの値はテキトーに設定する

– [Save]ボタンを押して、Ajax経由で画面を更新

Backボタンは、[Save]ボタンで画面を更新後、メインペー

ジを明示的に呼び出すリンクに変化させる。

– メインページの内容を更新して表示させたいので

(27)

17Th

Developer Camp

iOS で Webアプリを

フルスクリーン表示

4

(28)

iOS専用のタグを<head>…</head>に追加

MPageのOnShowHeaderイベントを利用

– スプラッシュ画像を用意 – iPhone,iPhone(Retina),iPad用に3種類のアイコンを用意 – フルスクリーン可であることを知らせるmetaタグ

iOSのSafariで[ホーム画面に追加]を利用

(29)

17Th Developer Camp

「Delphi言語再入門」

株式会社シリアルゲームズ 取締役 細川 淳 【T8】テクニカルセッション

(30)

17Th

Developer Camp

Classについて改めて

(31)

class

• Delphi を使う上で切っても切れない class 型 • class 型について、どの位の事をご存じですか? • 良くは判らないけど、component もクラスだし、Form を作ったら強制的 にクラスになっちゃうから、ただ何となく使っている? • ここでは、そんな class 型について深く見ていくことにします – ただ、そもそも class とはなんぞや?という話はしません – もう少し深く見ていきます。

(32)

class 定義

class 定義はヘルプより下記の様になっています

type

className = class [abstract | sealed] (ancestorClass)

memberList end;

abstaract, sealed って?

(33)

class 属性

abstract 属性

– 抽象クラスを表す属性です – この属性を指定するとクラスは抽象クラスとなり生成が禁 じられ……ません • 下位互換性を保つために抽象クラスの生成が許可されて います →実質 abstract 属性は、あまり意味がありません。 • しかし、abstract メソッドがある場合、警告が出ます – abstract メソッドについては後述

(34)

class 属性

sealed 属性

– sealed を付けて宣言すると、そのクラスを継承する事が できなくなります • Java の final と同じです。 – Delphi にも final はあるのですが、メソッドに付けます。 • ただし class helper は使えます – 拡張するだけなので当然ですね – class helper でメソッドを隠蔽可能です

(35)

class 属性 - sealed

type

TTestClass = class sealed public

procedure Test; virtual; end;

TTestClass2 = class(TTestClass) public

procedure Test; override; end;

ここで、下記のエラーが発生する

(36)

class 属性 - sealed

type

TTestClass = class sealed public

procedure Test; virtual; end;

TTestClass2 = class helper for TTestClass procedure Test; end; class helper として拡張するのは OK メソッドを隠蔽して元の Test を呼ばないようにできる 隠蔽した元の Test は inherited Test; として呼び出し可能

(37)

class 定義 - ancestorClass

• ancestorClass は継承元クラス – 何も指定しないと TObject を継承します • TObject もクラスとして定義されている(System.pas)ので TObject って一体なんだ!という話になりますが…… • コンパイラマジックの一種と考えて良いと思います • TObject • TObject は特別なクラスです。 • 全てのクラス型の大元になります。 • TObject のメソッドを使えないクラスはありません。 • record 型もメソッドを持てるようになりましたが、class 型との最 大の相違は TObject を先祖にもつか?ということです。 つまり、record 型は TObject を先祖にもちません

(38)

class とクラス参照型(メタクラス)

Delphi 言語では class も1つのオブジェクト(※)です。 例えば Application.CreateForm(TForm1, Form1); は、皆さん見たことがあると思います。 ここで、見て欲しいのが TForm1 と書いてあるところです。 class は型ですが、型そのものを引数として渡しています。 これは integer などでは不可能な事です。 このように class 型を参照する型を「クラス参照型」といいます(「メタクラス」 ともいいます)

(39)

class とクラス参照型(メタクラス)

Application.CreateForm の宣言を見てみます procedure TApplication.CreateForm(

InstanceClass: TComponentClass; var Reference);

TComponentClass = class of TComponent; こんな風になっています。

ここで、赤枠で囲った部分がクラス参照型の宣言です。

このようにクラス型そのものを渡す事によって、Factory を作ったり、多態性 を確保する事が容易になります。

(40)

class とクラス参照型(メタクラス)

type

TFigure = class(TObject) public

procedure Draw; virtual; abstract; end;

TFigureClass = class of TFigure; TTriangle = class(TFigure)

public

procedure Draw; override; end;

TRect = class(TFigure) public

procedure Draw; override; end;

TFigureDrawer = class(TObject) private

FFigure: TFigure; public

constructor Create(const iFigureClass: TFigureClass); procedure Draw;

end;

constructor TFigureDrawer.Create(const iFigureClass: TFigureClass); クラス参照型を定義

三角形を描画する

(41)

class クラスメソッド

class にはクラスメソッドといわれるものがあります。 具体的には このように宣言の前に "class" をつけたメソッドです。 クラスメソッドはインスタンスを必要としません。 つまり のように呼び出すことができます。 さて、Method1(); と Method2(); の違いはなんでしょうか……? type

TFoo = class(TObject) public

class procedure Method1;

class procedure Method2; static; end; procedure Test; begin TFoo.Method1; TFoo.Method2; end;

(42)

classクラスメソッドと静的メソッド

普通に考えるとクラスメソッドはインスタンスが存在しないため、Self が存在しません。 それは、Self とは、インスタンスを表しているからです。 しかし!ここで、Delphi では Class もオブジェクトである、という事を思い出してください! Method1; の中で Self を参照できてしまうのです! type

TFoo = class(TObject) public

class procedure Method1;

class procedure Method2; static; end;

class procedure TFoo.Method1();

begin Self.Method2; Self.Create; end; クラスメソッド中の Self はクラスオブジェクトそのものを 指します。 なので、このように Self をクラスのように使えるのです。

(43)

class クラスメソッドと静的メソッド

それに対して "static" 指定をされたクラスメソッドは、Self を持ちません。 このことから、static 指定されたメソッドを特に「静的メソッド」と呼びます。

type

TFoo = class(TObject) public

class procedure Method1;

class procedure Method2; static; end;

class procedure TFoo.Method2();

begin

Self.Create; end;

ここで、下記のエラーが出ます

(44)

class クラスメソッドと静的メソッド

ちなみに、バイナリレベルでも違いがでます。 static 指令がない Method1 の呼び出しでは、 eax レジスタに Self を代入して呼び出していま す。 しかし、Method2 ではシンプルに何もせずに 呼び出しているだけです。 特にクラス参照型を欲しない場合は static 指 令を付けた静的メソッドを使うとコードサイズが 若干小さくなります。 type

TFoo = class(TObject) public

class procedure Method1;

class procedure Method2; static; end; procedure Test; var Foo: TFoo; begin Foo := TFoo.Create; TFoo.Method1(); Foo.Method1(); TFoo.Method2(); end; Unit1.pas.58: TFoo.Method1;

0051A757 A16CA65100 mov eax,[$0051a66c] 0051A75C E853020000 call TFoo.Method1 Unit1.pas.59: Foo.Method1;

0051A761 8B45FC mov eax,[ebp-$04] 0051A764 8B00 mov eax,[eax] 0051A766 E849020000 call TFoo.Method1

(45)

class メンバの可視性

private, protected, public, published

– これらの指定を、もちろん見たことがあると思います。

– private, protected, public については、説明は不要かと

思いますが、一応説明すると下表の様になります 可視性 自分自身 継承先クラス 同一ユニット private ○ ○ protected ○ ○ ○ public ○ ○ ○ strict private ○ strict protected ○ ○

(46)

classメンバの可視性 - published

published と public は、公開範囲は同じように思えます

では、何が違うのでしょうか?

published は public と違い RTTI を生成します。

RTTI とは「実行時型情報」

です。

※本来「型」とは、コンパイル時に必要なものです。

たとえば、Integer 型に Class のインスタンスを代入しようとすればコンパイルエラー になります。

しかし、Integer 型と Class のインスタンスは同じ4バイトです(32bitの時)。 CPU から見たときに違いはありません。

(47)

class メンバの可視性 - published

published 指定されたメンバは

– ソースコードレベルの可視性は同じ – RTTI が生成される – RTTI を介して外部のプログラムがメンバーを参照できる • オブジェクトインスペクタでプロパティを編集できるのは、こ のためです。 – メソッドの overload はできない • もちろん public では overload できます。

(48)

class メンバの可視性 - published

public, published の違いについて誤解を恐れずにいうと

public は、

ソースコードレベルで公開

– ソースコード中でメンバを参照できる

published は、

バイナリレベルで公開

– コンパイル済みのバイナリに対して、参照できる

となります

(49)

class のバインディング

RTTI が出てきたので、ここでバインディングについても

見ていきます。

バインディングとは

– virtual – dynamic – override のことです。

(50)

class のバインディング

virtual と dynamic

– virtual と dynamic はソースコードレベルでは同じ動作を します。 – どちらも、override 可能、abstract 指定可能です。 – 違いをヘルプで引くと下記の様に書かれています。 – 意味はわかるけど仕組みが判りませんね バインディング 最適化 備考 virtual 実行速度を最適化 最も効率的な方法 dynamic サイズを最適化 たまにしかオーバーライドされない時に使用する

(51)

class のバインディング

実際の所、実装上の違いは、どうなっているかというと となります。 先ほどの表の「たまにしかオーバーライドされない時に使用する」というのは 「派生先でメソッドテーブル」が生成されないため、コードサイズが小さくなる 、という意味です。 バインディング 意味 virtual 派生クラスでもメソッドテーブルが生成される dynamic 基本クラスにのみメソッドテーブルが生成される

(52)

class のバインディング - VMT

• VMT とは Virtual Method Table の事です。

Method1 Method2 Method3 Method4 VMT メソッドの呼び出しは、Table への参照に置 き換わります 概念的にはメソッドのポインタへの配列です。 たとえば、ソースコードに Method1(); という呼び出しコードがあった場合 VMT[0](); といったコードになる、ということです。 Method1(); VMT 内の 0 番目の参照を呼び出す

(53)

class のバインディング - VMT と override

override

Method1 Method2 Class Foo の VMT Method1 Method2 Class Bar の VMT type

TFoo = class(TObject) public

procedure Method1(); virtual; procedure Method2(); virtual; end;

TBar = class(TFoo) public

procedure Method1(); override; end;

テーブルの内容が置き換わる!

//擬似コードとして書くと

VMT[0] := @TFoo.Method1; // Method1 のアドレスが入った // TBar で TFoo の Method1 を override すると

(54)

class のバインディングと abstract

abstract

Method1 Method2 Class Foo の VMT Method1 Method2 Class Bar の VMT type

TFoo = class(TObject) public

procedure Method1(); virtual; abstaract; end;

TBar = class(TFoo) public

procedure Method1(); override; end;

場所が確保されているだけで 中身は無い!

//擬似コードとして書くと

VMT[0] := nil; // アドレスは nil !

// TBar で TFoo の Method1 を override すると

(55)

メソッドポインタ

今まで見てきた通り Class には2つの構成要素があります。 – Self インスタンスのアドレスを表す – Method メソッドのアドレス クラス参照型は、クラスオブジェクトのアドレスを渡しています。 アドレスは、32bit のマシンでは4バイトで表されます。 VMT に格納されているメソッドのアドレスも4バイトです。 Self が指すクラスのインスタンスも4バイトです。

(56)

メソッドポインタ

Object 必要なバイト数 Self 4 byte Method 4 byte 計 8 byte type

TFoo = class(TObject) private

FEvent: TNotifyEvent;

procedure TestEvent(Sender: TObject);

end; procedure Test; var Foo: TFoo; begin Foo := TFoo.Create; Foo.FEvent := Foo.TestEvent; end; Foo と TestEvent で、それぞれ4バイト必要 Delphi の Pointer 型は4バイトしか格納できないけど…… どうやって、アドレスを代入しているのか?? ここで、イベントについてちょっと見てます。

(57)

メソッドポインタ

Delphi では「メソッドポインタ」を使ってイベントを管理しています。 ヘルプを引用すると メソッドポインタは,特定のクラスインスタンスの特定のメソッドを指す特殊なポインタ型です。 メソッドポインタはほかの手続き型と同じように動作しますが,手続き型と違ってクラスインスタン スへの隠されたポインタを保持しています。 つまり、メソッドポインタは、コードを書いていると気づきませんが、実は8バ イトのポインタなのです。 メソッドポインタの宣言には下記の様に of object を指定します。 type

TTestEvent = procedure(Sender: TObject; iFoo: TFoo) of object;

var

(58)

メソッドポインタ - TMethod

type

TFoo = class(TObject) private

procedure Method;

end;

procedure Test;

type

TProc = procedure of object;

var Foo: TFoo; Proc: TProc; Method: TMethod; begin Foo := TFoo.Create; Proc := Foo.Method; Method := TMethod(Proc); TProc(Method)(); Foo.Free; TMethod という面白い機構が存在します。 TMethod は 8 byte のレコードで、メソッドポインタを保持できます メソッドポインタは TMethod へキャスト可能で す。 そして、TMethod もメソッドポインタにキャスト できます。 procedure Test; type

TProc = procedure of object;

var Foo: TFoo; Proc: TProc; begin Foo := TFoo.Create; TMethod(Proc).Data:= Foo; TMethod(Proc).Code:= Foo.MethodAddress('Method') Proc; Foo.Free; こんな風にも書けます

(59)

メソッドポインタ - TMethod

type

TProc = procedure of object; TFoo = class(TObject)

private FMsg: String; procedure Method; end; procedure TFoo.Method; begin ShowMessage(FMsg); end; procedure Test; var Foo: TFoo; Bar: TFoo; Proc: TProc; Method: TMethod; begin Foo := TFoo.Create; Bar := TFoo.Create; Foo.FMsg := 'Foo' Bar.FMsg := 'Bar'; Proc := Foo.Method; Method := TMethod(Proc); TProc(Method)(); Method.data := Bar; TProc(Method)(); TMethod は Code, Data という2つのメンバを持っています。

Code は、メソッドのアドレス Data は、インスタンスのアドレス です。

(60)

17Th

Developer Camp

Classの演習

(61)

TMethodCaller を作る

いままで、通して来てクラスについての理解が深まったと

思います。

(62)

TMethodCaller の要件

クラスとメソッド名を引数にもつ静的メソッド

– メソッドの名前は仮に execute とした場合、下記の様に 呼び出せる • TMethodCaller.Execute(TTestClass, 'Method');

このメソッドを呼び出すとクラスを生成し、該当メソッドを

呼び出す

– つまり、上記の例は↓と同じ事をする • (TTestClass.Create).Method();

なお、呼び出せるメソッドは引数を持たない手続きとしま

(63)

TMethodCaller - RTTI

RTTI を扱うクラスがあります。

それを使うとメソッドの引数なども簡単に取得できます。

それを使えば今回のように引数なしのメソッドではなくて

も、安全に呼び出すことができます。

– 腕に自信がある方は、是非挑戦してみてください。

(64)

TMethodCaller - 宣言部

unit uMethodCaller;

interface type

TMethodCaller = class(TObject) private

type TCalledProc = procedure of object; public

class procedure Execute( const iClass: TClass;

const iMethodName: String); static; end;

(65)

TMethodCaller - 実現部

implementation

class procedure TMethodCaller.Execute( const iClass: TClass;

const iMethodName: String);

var Obj: TObject; Proc: TCalledProc; begin Obj := iClass.Create; try TMethod(Proc).Data := Obj; TMethod(Proc).Code := Obj.MethodAddress(iMethodName); if (TMethod(Proc).Code <> nil) then

Proc; finally Obj.Free; end; end; end.

(66)

TMethodCaller - 使い方

type

TTestClass = class(TPersistent) // TObject から生成すると published のところで警告発生 published procedure Test; end; procedure TTestClass.Test; begin ShowMessage('TEST'); end;

procedure TForm1.Button1Click(Sender: TObject);

begin

TMethodCaller.Execute(TTestClass, 'Test');

(67)

17Th Developer Camp

「Delphi言語再入門」

~拡張されたRTTIを試してみる

東洋テクニカルシステム株式会社 システム開発部 福士 光 【T8】テクニカルセッション

(68)

アジェンダ

従来のRTTIでできること

Delphi 2010で新しく拡張されたRTTI(拡張RTTI)で

できるようになったこと

試してみる(1)~クラス内のメンバの列挙

試してみる(2)~クラス内のメンバの値の取得

拡張RTTIと属性を使う上での注意事項

(69)

基本知識~RTTIとは?

RTTI(実行時型情報)とは?

– RunTime Type Informationの略(Informationではなく Identificationとすることもある)。 – 実行時にメモリ上のオブジェクトのデータ型に関する 情報を取得、操作できる。 – Delphiでは従来からpublished宣言を行うことでRTTIが 生成され、 IDEがコンポーネントの持つRTTIを利用して いる。 – Delphi 2010/XE/XE2ではRTTIが拡張され、より多くの ことが可能になった(実行バイナリのサイズが大きくなる という副作用がある)。

(70)

17Th

Developer Camp

従来のRTTIでできること

(71)

従来のRTTIでできること(1)

(System.)TypInfoユニット

実行時にプロパティの型情報を探す。

– publishedなプロパティのみ(コンパイラ指令{$M+} または {$TYPEINFO ON}が必要) – GetPropInfo関数、GetPropList関数など – PPropInfo = ^TPropInfo (レコード型へのポインタ)

実行時に型情報を元に値を取得、設定する。

– GetXXXXProp/SetXXXXProp関数(XXXXは対象となる プロパティの型による)

DelphiのIDEがフォームをストリーム化したりプロパティ

エディタで使用しているのはご存知のとおり。

(72)

従来のRTTIでできること(2)

仮想メソッドテーブル(VMT)

– virtual/overrideと宣言されたメソッドのテーブル (クラスごとに存在)

動的なメソッドのテーブル

– dynamic/overrideあるいはmessageと宣言された メソッドのテーブル(テーブル上では動的メソッドなのか メッセージハンドラなのかは区別されていない)

(73)

17Th

Developer Camp

拡張RTTIでできるように

なったこと

(74)

拡張RTTIでできるようになったこと(1)

(System.)RTTIユニット

実行時にフィールド、プロパティ、メソッドの型情報を

取得する。

– コンパイラ指令{$RTTI}で拡張RTTIをプロパティ、 フィールド、メソッドのそれぞれに対してどの範囲 (published/public/protected/private)のものに 付けるのかを制御 – クラス型(class)またはレコード型(record)が対象 →型情報そのものは全ての型(Integer, Boolean, ...)に 存在している

(75)

拡張RTTIでできるようになったこと(2)

実行時に型情報とインスタンスへのポインタを元に

各種の操作を行う。

– フィールドの値の取得、設定 – プロパティの値の取得、設定 – メソッドの呼び出し(invocation)

(76)

拡張RTTIでできるようになったこと(3)

属性(attribute)による注釈付け(annotation)

– クラス型あるいはレコード型に属性で注釈を付ける – クラス型あるいはレコード型のメンバ(フィールド、 プロパティ、メソッド)に属性で注釈を付ける • .NET Frameworkと同様の記法を使う [<Attr>] [<Attr>(<parameterlist>)] • 先頭の“T”と末尾の“Attribute”、コンストラクタの “.Create”を省略できる [T<Attr>Attribute.Create]

(77)

拡張RTTIでできるようになったこと(4)

属性(attribute)による注釈付け(annotation)

– カスタム属性(custom attribute)の宣言 • (プロパティやフィールドの値ではなく)属性クラスの型で 区別する →例外ハンドラを記述するときに例外オブジェクトの型で 区別を行うのと同様に • コンストラクタで渡した値(定数のみ)をフィールドまたは プロパティに保存して参照することもできる • TCustomAttributeクラスから派生したカスタム属性 クラスを宣言して使用する

(78)

拡張RTTIでできるようになったこと(5)

属性(attribute)による注釈付け(annotation)

– 実行時にクラス型、レコード型に付けられている属性を 抽出する – 実行時にクラス型、レコード型のメンバに付けられている 属性を抽出する

属性を使う状況

– 同じ型から派生していても区別して処理したい – 同じ型のメンバでも区別して処理したい

(79)

拡張RTTIでできるようになったこと(6)

拡張RTTIと属性についての補足。

– 拡張RTTIはデフォルトでは以下の範囲に付けられている (Systemユニットで定義) – Delphi 2010以降の実行ファイルが大きくなってしまう 原因のひとつ – {$RTTI EXPLICIT ...}で(継承元クラスの指定とは 独立して)拡張RTTIを付ける範囲を指定できる

可視性 private protected public published

フィールド 〇 〇 〇 〇

プロパティ × × 〇 〇

(80)

拡張RTTIでできるようになったこと(7)

拡張RTTIと属性についての補足。

– 属性は検索、抽出されるときに実体が生成される →検索、抽出しなければ性能上のペナルティはない →実行バイナリ、占有メモリのサイズのペナルティはある – 拡張RTTIを扱うコードは遅い

どのような場合に拡張RTTIを使えばよいのか?

– クラスに対する汎用な処理の記述 →ORマッパやXMLへのシリアライズ/デシリアライズ →クラス構造のツリー表示

(81)

17Th

Developer Camp

試してみる(1)

クラス内のメンバの列挙

(82)

クラス内のメンバの列挙(1)

TRTTIContext ((System.)RTTIユニット)

– 全ての操作はここから始まる

– 高度なレコード型

– 内部リソースの管理、解放のためクラスのコンストラクタ、

デストラクタのようにclass function Createと

procedure Freeを呼ぶことが推奨されています uses Rtti; var ctx: TRttiContext; begin ctx := TRttiContext.Create; try // RTTIを扱う finally ctx.Free; end; end;

(83)

クラス内のメンバの列挙(2)

TRTTIContext

– GetTypeメソッド

• 指定されたクラス型のRTTIオブジェクト(TRTTITypeから 派生したクラスのインスタンス)を取得

(84)

クラス内のメンバの列挙(3)

TRTTIType

– クラス型(RTTIオブジェクトの基底クラス)

– GetPropertiesメソッド

• 所属するクラスのプロパティのRTTI情報を全て取得

function GetProperties: TArray<TRttiProperty>;

– GetFieldsメソッド

• 所属するクラスのフィールドのRTTI情報を全て取得

function GetFields: TArray<TRttiField>;

– GetMethodsメソッド

• 所属するクラスのメソッドのRTTI情報を全て取得

function GetMethods: TArray<TRttiMethod>;

– 階層順に(継承先から継承元に向かって)RTTI情報が

(85)

クラス内のメンバの列挙(4)

TRTTIType

– GetDeclaredPropertiesメソッド – GetDeclaredFieldsメソッド – GetDeclaredMethodsメソッド – そのクラスで定義したプロパティ/フィールド/メソッドの RTTI情報だけがリストアップされる

(86)

クラス内のメンバの列挙(5)

TRTTIProperty

– クラスのプロパティのRTTI情報

– クラス型(TRTTIMemberから派生)

– Nameプロパティ(名前)

property Name: string;

– Visibilityプロパティ(可視性)

(87)

クラス内のメンバの列挙(6)

それでは実際に試してみましょう。

– 新規作成→VCLフォームアプリケーション – フォーム上にボタン(Button1)とメモ(Memo1)を配置 – メモのAnchorsにakRightとakBottomを追加、 crollBarsをssBothに変更。

(88)

クラス内のメンバの列挙(7)

procedure TForm1.EnumProperties(AObject: TObject);

const

MemberVisibilities: array [TMemberVisibility] of String = ('private', 'protected', 'public', 'published');

var

ctx: TRttiContext; prop: TRttiProperty;

begin

Memo1.Lines.Add('Class: ' + AObject.ClassName); ctx := TRttiContext.Create;

try

for prop in ctx.GetType(AObject.ClassType).GetProperties do begin

Memo1.Lines.Add(' Property: ' + prop.Name +

‘ (’ + MemberVisibilities[prop.Visibility] + ‘)’); end; finally ctx.Free; end; end;

procedure TForm1.Button1Click(Sender: TObject);

begin

EnumProperties(Form1); EnumProperties(Button1); EnumProperties(Memo1);

(89)

クラス内のメンバの列挙(8)

とりあえず実行してみましょう。

Memo1.Lines.Addの行にブレークポイントを設定し、

prop(TRttiProperty)を評価してみる。

(90)

17Th Developer Camp

試してみる(2)

クラス内のメンバの値の

取得

5

(91)

クラス内のメンバの値の取得(1)

TValue ((System.)RTTIユニット)

– 拡張RTTIでデータを格納する – 高度なレコード型 – バリアントもどき(“バリアント型の軽量版”) – 実際のデータはFDataフィールド(TValueDataレコード 型、共用体)に格納している

(92)

クラス内のメンバの値の取得(2)

TValue

– Kindプロパティ

• 型の種類を列挙として取得

property Kind: TTypeKind;

– TypeInfoプロパティ

– TypeDataプロパティ

• 型の情報をレコード型として取得

property TypeInfo: PTypeInfo read GetTypeInfo;

(93)

クラス内のメンバの値の取得(3)

TValue

– IsXXXXメソッド/プロパティ • 格納されているデータの状態を問い合わせる IsEmpty/IsObject/IsInstanceOf/IsClass/IsOrdinal/IsType/IsArray – AsXXXX/TryAsXXXXメソッド • 格納されているデータを特定の型で取得する AsObject/AsClass/AsOrdinal/AsType/AsInteger/AsBoolean AsExtended/AsInt64/AsInterface/AsString/AsVariant/AsCurrency TryAsOrdinal/TryAsType

(94)

クラス内のメンバの値の取得(4)

TValue

– 暗黙の型変換(implicit conversion) • データを格納する string/Integer/Extended/Int64/TObject/TClass/Boolean – FromXXXXメソッド • データを格納する FromVariant/From<T>/FromOrdinal/FromArray – ToStringメソッド • データをとりあえず文字列化

(95)

クラス内のメンバの値の取得(5)

TRTTIPropertyとTValue

– TRTTIProperty.GetValue

• 特定のインスタンスのプロパティの値を取得

function GetValue(Instance: Pointer): TValue;

– TRTTIProperty.SetValue

• 特定のインスタンスのプロパティの値を設定

procedure SetValue(Instance: Pointer; const AValue: TValue);

– TRTTIPropertyが示しているのは型に関する情報で

(96)

クラス内のメンバの値の取得(6)

こちらも試してみましょう。

– GetValueでプロパティの値を取得して、 TValue.ToStringで文字列化します – GetValueは例外が起きるかもしれないので try...except...endで保護します

procedure TForm1.EnumProperties(AObject: TObject);

const

MemberVisibilities: array [TMemberVisibility] of String = ('private', 'protected', 'public', 'published');

var

ctx: TRttiContext; prop: TRttiProperty; V: TValue;

(97)

begin

Memo1.Lines.Add('Class: ' + AObject.ClassName); ctx := TRttiContext.Create;

try

for prop in ctx.GetType(AObject.ClassType).GetProperties do begin try V := prop.GetValue(AObject); Str := V.ToString; except on E: Exception do begin Str := 'Error (' + E.Message + ')'; end; end;

Memo1.Lines.Add(' Property: ' + prop.Name +

' (' + MemberVisibilities[prop.Visibility] + ')' + ' Value = ' + Str); end; finally ctx.Free; end; end;

クラス内のメンバの値の取得(7)

(98)

クラス内のメンバの値の取得(8)

SetValueメソッドでプロパティの値を変更することも

可能です。

GetValueで取得したTValueのTypeInfo.Kindが

tkClassなら、AsObjectはクラス型のプロパティです。

あるいは

TRTTIPropertyやTRTTIFieldのHandle

プロパティが

nilでなければPTypeInfo

(=^TTypeInfo)なので、Handle.Kindでその

プロパティ

/フィールドの定義の型を知ることもできます。

→再帰処理で複合クラスのトラバースが実現できます。

(99)

17Th

Developer Camp

拡張RTTIと属性を使う上での

注意事項

(100)

拡張RTTIと属性を使う上での注意事項(1)

配列に対するサポートが弱い。

– Delphi XE2ではTRttiTypeにGetIndexedProperties

メソッドが追加されて配列プロパティに関する情報を取得 できるようになったが、通常のプロパティに比べて微妙に 使えない – 静的配列のフィールドもうまく扱えない – 動的配列のフィールドは通常のプロパティ並に扱える ので、配列プロパティ、静的配列のフィールドの代替と して動的配列のフィールドを用意してエイリアス的に使う という回避策が有効

(101)

拡張RTTIと属性を使う上での注意事項(2)

属性のコンストラクタ

– TCustomAttributeのコンストラクタはパラメータを 持たないが、派生したクラスでコンストラクタを定義する ことで値を渡すことができる(フィールド、プロパティでその 値を保持する)

constructor Create(const AFooValue: String);

– しかしコンストラクタのパラメータは定数しか使えない

(文字列定数はOK)

– ポインタでも定数なら使えるはずだが、現実には内部

(102)

17Th

Developer Camp

参考文献

(103)

参考文献 (1)

Delphiのヘルプ

RTTI の操作 (オンライン) http://docwiki.embarcadero.com/RADStudio/ja/RTTI_ %E3%81%AE%E6%93%8D%E4%BD%9C%EF%BC%9A%E3%82%A4%E 3%83%B3%E3%83%87%E3%83%83%E3%82%AF%E3%82%B9

“Rob’s Technology Corner”

“Delphi 2010 - RTTI & Attributes”シリーズ

http://robstechcorner.blogspot.com/2009/09/so-what-is-rtti-rtti-is-acronym-for-run.html

(104)

参考文献 (2)

Delphi 2010 Handbook

– Marco Cantù著 – CreateSpace (http://www.createspace.com/) – ISBN978-1450597265 (ISBN1450597262) – 43.50USD(書籍版)、28.00USD(ebook) http://www.marcocantu.com/dh2010/ http://www.amazon.com/dp/1450597262 (書籍) http://sites.fastspring.com/wintechitalia/product/ delphi2010handbook (ebook/PDF) – 英語ですが表現は比較的平易。 – 拡張RTTIについて記述があります(Chapter 3、4)。

(105)

参考文献 (3)

Delphiクイックリファレンス

– Ray Lischner著 – 光田 秀、竹田 知生訳 – オライリー・ジャパン – ISBN978-4873110400 (ISBN 4-87311-040-8) – 4,725円 http://www.oreilly.co.jp/books/4873110408/ http://www.amazon.co.jp/dp/4873110408 – 残念ながら絶版です。 – 従来のRTTIについて記述があります。

(106)

参考文献 (4)

Inside Delphi

– Ray Lischner著 – 光田 秀訳 – 大野 元久、服部 誠監修 – アスキー – ISBN978-4756119513 (ISBN 4-7561-1951-4) – 9,240円 http://www.amazon.co.jp/dp/4756119514 – こちらも残念ながら絶版です。 – 従来のRTTIについて記述があります。

(107)

17Th Developer Camp

Delphi/C++Builderで

iOS/Macアプリを作ろ

う!

エンバカデロ・テクノロジーズ エヴァンジェリスト 高橋智宏 【T9】テクニカルセッション

(108)

アジェンダ

OS Xで動的ライブラリ(.dylib)

– Delphiで作成して、Delphiアプリから呼び出し – C++Builderで作成して、C++Builderアプリから呼び出し

SQLite3 を利用する

– C++BuilderでOS X内蔵のSQLite3を利用する

OpenCL を利用する

– C++BuilderでOS X内蔵のOpenCLを利用する

OS XでSOAPクライアントを作成する

– Win32/Win64のSOAPサーバーからのTClientDataSetを受信して、 FireMonkeyのStringGridに表示

Update 4 で新たに追加されたFireMonkey向けモ

バイルコネクタ

デモ デモ デモ デモ デモ

(109)

17Th

Developer Camp

OS Xで動的ライブラリ(.dylib)

(110)

Delphiで作成

lib[プロジェクト名].dylib が生成される

(111)

Delphiアプリから呼び出し

external ‘xxxx.dylib’;

(112)

C++Builderで作成

[プロジェクト名].dylib が生成される

– 共有メモリマネージャ(MEMMGR.LIB,BORLNDMM.DLL)は無い

int32_t, char16_t などの型(stdint.h)を使いましょう

(113)

C++Builderアプリから呼び出し

#pragma link ‘xxxx.dylib’

(114)

17Th

Developer Camp

SQLite3 を利用する

(115)

/usr/include/sqlite3.h , /usr/lib/libsqlite3.dylib

[ツール]-[オプション]-[環境オプション]-[リモート

プロファイル]-[リモートパス]

– 必要に応じて、.h と .dylib をPAServerからインポート

(116)

データベースファイルの作成またはオープン

#include <sqlite3.h>

#pragma link ‘libsqlite3.dylib’

sqlite3_open: 作成またはオープン

(117)

テーブルの作成 および 行のINSERT

C++BuilderのUnicodeString型(1文字16ビット)を使用

– 一部、UTF8String型(UTF8Encode関数)を使用

テーブルの存在確認

– システムテーブルにSELECT文を実行 • sqlite3_get_table / sqlite3_free_table

テーブルの作成

– sqlite3_exec で CREATE TABLE文を実行

行のINSERT

– パラメータ付きクエリ (例: …=:param …) – char16_t版の関数を利用 • sqlite3_prepare16 / sqlite3_reset: SQL文の準備 • sqlite3_bind_text16: 文字列パラメータのセット • sqlite3_step: SQL文の実行

(118)
(119)

SELECT文で行を検索

sqlite3_step とその戻り値で結果セットをイテレート

– SQLITE_ROW: 行がある – SQLITE_DONE: 行が無くなった

sqlite3_column_text16 でカレント行の文字列を取得

– 戻り値の型を char16_t* 型にするのを忘れずに!! – C++BuilderのUnicodeString型に変換する

(120)

17Th

Developer Camp

OpenCL を利用する

(121)

OpenCL on Snow Loepard, Lion

OpenCL とは?

出典: wikipedia

C++Builder XE2 がサポートしている OS X

(122)

OpenCL,OpenGL - /System/Library/Frameworks

[ツール]-[オプション]-[環境オプション]-[リモート

プロファイル]-[リモートパス]

– フレームワークとして OpenCL と OpenGL をインポート • OpenGL も忘れずに!! • 必要なヘッダとライブラリが利用できるようになります

(123)

GPUに送り込むカーネルコードを定義

コンパイル前のカーネルコードを文字列で定義

– C言語的なコードを書きます

• char配列でもファイルでもOK

(124)

計算用の初期値, GPUに接続, コードのコンパイル

アプリ(ホスト)側で計算用の初期値(配列)を準備

– この配列の値をGPU(デバイス)にコピーして渡します

1個のGPU(デバイス)に接続して、コードをコンパイル

(125)

GPUで使用するパラメータの作成

パラメータ用の配列をGPU内に作成して、そこに

アプリ(ホスト)側の配列をコピーする

計算結果を格納する配列をGPU内に作成

(126)

GPUで計算実行, 結果を取得して確認, 後始末

• GPU内の複数の計算ユニットで並列実行 – clFinish関数で実行終了を待ち合わせ • clEnqueueNDRangeKernel関数は非同期で実行される • 計算結果の配列をGPUからホストにコピー – clEnqueueReadBuffer関数で取得(読み込みが終わるまで待たされる) – 試しに、CPUの計算結果とGPUの計算結果を比較する • 作成したリソース群を解放

(127)

17Th

Developer Camp

OS XでSOAPクライアントを

作成する

(128)

作成するサンプルシステムの目標・設計

SOAPサーバー

– Win32(またはWin64)のDelphi(またはC++Builder)で作成 – スタンドアロン(.exe)サーバー – ポート番号 8080 – TClientDataSetを返すメソッドをクライアントに公開 • ただし、TClientDataSetそのものではなく、XML化した文字列 (string)を採用

SOAPクライアント

– MacOS X向けFireMonkeyアプリケーション • Delphi または C++Builder で作成 – WSDLからSOAPクライアント用プロキシを生成 • Windows版およびMacOS X版で共通!! – サーバーから取得したTClientDataSetをTStringGridに表示

(129)

SOAPサーバー – データモジュールを用意

• [ファイル]-[新規作成]-[その他]-[Delphiプロジェクト]-[Webサービス]-[SOAP サーバーアプリケーション] – サンプルのSOPAサーバーインターフェースを作成 • サービス名は Employee • [ファイル]-[新規作成]-[その他]-[Delphiプロジェクト]-[Delphiファイル]-[データ モジュール] – TClientDataSet を配置 – [項目の設定]でフィールドを追加 • TIntegerField – FieldName は id • TWideStringField – FieldName は fullname

(130)

クライアントに公開するメソッド

• function getEmployeeDataSetXML: string; stdcall;

– interface と 実装class を編集 • [サービス名]Intf.pas

• [サービス名]Impl.pas

(131)

SOAPクライアント – WSDLをインポート

• [ファイル]-[新規作成]-[その他]-[Delphiプロジェクト]-[Webサービス]-[WSDLインポータ] – FireMonkeyフォームからクライアントプロキシユニットを参照 • FireMonkeyフォーム上に、以下を配置 – TButton – TClientDataSet – TStringGrid • [項目エディタ]で項目(TStringColumn)の追加 – Id – fullname

(132)

SOAPクライアント – TClientDataSetを復元

(133)

17Th Developer Camp

Update 4 で新たに追加された

iOS/FireMonkey向け

モバイルコネクタ

5

(134)

Update 4 をインストールすると…

• iOS FireMonkey(FreePascal)向けのモバイルコネクタがリポ ジトリフォルダに追加される – …¥RAD Studio¥9.0¥ObjRepos¥ja[en]¥dsrest¥connectors¥ • freepascal_ios42 フォルダ: iOS 4.2以降 • freepascal_ios50 フォルダ: iOS 5.0向け • DataSnap RESTサーバーのプロジェクト – DelphiのWebModule用ユニットのuses(例: WebModuleUnit1.pas) • Datasnap.DSProxyFreePascal_iOS

– C++BuilderのWebModule用ユニットの.h(例: WebModuleUnit1.h)

• #include <Datasnap.DSProxyFreepascal_iOS.hpp>

– プロジェクトのproxyフォルダにモバイルコネクタ(必要があればコピー)

• サーバーを起動してWebブラウザまたは専用ツールを起動

(135)

モバイルコネクタをクライアントで利用する

• モバイルコネクタ用の.pasファイル 15個 をプロジェクトに追加 接続先を指定 デフォルトのプロトコルはhttp DataSnapサーバーへの接続 サーバーメソッドの呼び出し DataSnap特有の例外 DBXException

(136)

Windows上で実行すると…

• モバイルコネクタでサーバーメソッドの呼び出しをテストする

– Windows上では、メソッドの呼び出し時に例外が発生する仕様 • XcodeとiPhoneシミュレータでのデバッグが必須

(137)

日本語などのUnicode文字列が化けて送信される

• Update 4 に付属する DSRESTConnection.pas の不具合 – QC#103021 • http://qc.embarcadero.com/wc/qcmain.aspx?d=103021 • uses句 と EncodeUrlNS2関数 に加筆修正を施してください – 予め、リポジトリ内のファイル自体を書き換えておくと便利

(138)

iPhoneシミュレータ上で実行

• 予め、ターミナルからiPhoneシミュレータのプロセスをUTF-8 で起動しておく(日本語などの文字化け対策) – QC#101418 • http://qc.embarcadero.com/wc/qcmain.aspx?d=101418 $ export LANG=ja_JP.UTF-8 $ cd /Developer/Platforms/iPhoneSimulator.platform/Developer/Applications/iPhone¥ Simulator.app/Contents/MacOS $ ./iPhone¥ Simulator • Xcodeでビルドして起動!!

参照

関連したドキュメント

に関して言 えば, は つのリー群の組 によって等質空間として表すこと はできないが, つのリー群の組 を用いればクリフォード・クラ イン形

日本語で書かれた解説がほとんどないので , 専門用 語の訳出を独自に試みた ( たとえば variety を「多様クラス」と訳したり , subdirect

目標を、子どもと教師のオリエンテーションでいくつかの文節に分け」、学習課題としている。例

Frauwallner [1937:287] は下す( Kataoka (forthcoming1) 参照).本質において両者に意見の相違は ないと言うのである( Frauwallner [1937:280, n.1]

本論文での分析は、叙述関係の Subject であれば、 Predicate に対して分配される ことが可能というものである。そして o

つまり、p 型の語が p 型の語を修飾するという関係になっている。しかし、p 型の語同士の Merge

17‑4‑672  (香法 ' 9 8 ).. 例えば︑塾は教育︑ という性格のものではなく︑ )ット ~,..

用できます (Figure 2 および 60 参照 ) 。この回路は優れ た効率を示します (Figure 58 および 59 参照 ) 。そのよ うなアプリケーションの代表例として、 Vbulk