英語版
このページの英語版を見る

Objective-Cとのインターフェイス

DはObjective-Cとのインターフェイスをサポートしている。プロトコル、クラス、サブクラス、インスタンス変数、インスタンス・メソッド、クラス・メソッドをサポートしている、 サブクラス、インスタンス変数、インスタンス・メソッド、クラス・メソッドをサポートしている。 プラットフォームのサポートはコンパイラーによって異なる場合がある。

完全に動作する例は下の方にある。 ある。

クラス

外部クラスを宣言する

import core.attribute : selector;

extern (Objective-C)
extern class NSString
{
    const(char)* UTF8String() @selector("UTF8String");
}

Dからアクセス可能なObjective-Cクラスはすべて、Objective-Cのリンケージで宣言する必要がある。 Objective-Cのリンケージで宣言する必要がある。もし クラスがextern (extern (Objective-C) に加えて)として宣言されている場合、それは外部で定義されていることが期待される。 として宣言されている場合は、外部で定義されていることが期待される。

この @selector属性は 属性は、このメソッドを呼び出すときにどのObjective-Cセレクタを使うべきかを示す。 この属性は Objective-C リンケージを持つすべてのメソッドに付ける必要がある。

プロパティへのバインディング(アクセサメソッド)

import core.attribute : selector;

extern (Objective-C)
extern class MTLRenderPipelineDescriptor : NSObject
{
    NSString label() @selector("label");
    NSString label(NSString) @selector("setLabel:");
}

Objective-Cのクラス@property にバインドする必要がある場合、ゲッターとセッターの両方を生成することに注意しなければならない。 ゲッターとセッターの両方が生成されることに注意しなければならない。値を取得するメソッド(ゲッター)は、プロパティの名前と同じ名前である。 はプロパティ名と同じ名前である。値を設定するメソッド(セッター)は、プロパティの名前と同じ名前である。 は "set"で始まり、大文字のプロパティ名を使う。 プロパティlabel のセッターはsetLabel: である。

クラスを定義する

import core.attribute : selector;

// 外部定義
extern (Objective-C)
extern class NSObject
{
    static NSObject alloc() @selector("alloc");
    NSObject init() @selector("init");
}

extern (Objective-C)
class Foo : NSObject
{
    override static Foo alloc() @selector("alloc");
    override Foo init() @selector("init");

    final int bar(int a) @selector("bar:")
    {
        return a;
    }
}

void main()
{
    assert(Foo.alloc.init.bar(3) == 3);
}

Objective-Cクラスの定義は、外部クラスの宣言とまったく同じである。 しかし、extern として宣言してはならない。

Objective-Cのセマンティクスに合わせるため、staticfinal のメソッドは仮想である。 static メソッドもオーバーライド可能である。

プロトコル

プロトコルを宣言する

import core.attribute : selector;
import core.stdc.stdio : printf;

extern (Objective-C)
interface Foo
{
    static void foo() @selector("foo");
    void bar() @selector("bar");
}

extern (Objective-C)
class Bar : Foo
{
    static void foo() @selector("foo")
    {
        printf("foo\n");
    }

    void bar() @selector("bar")
    {
        printf("bar\n");
    }
}

Objective-Cのプロトコルは、D言語とのインターフェイスとして表現され、 キーワードを使用して宣言される。 interface キーワードを使って宣言される。

Dからアクセス可能なObjective-Cプロトコルはすべて、Objective-Cのリンケージを使って宣言する必要がある。 をObjective-Cリンクで宣言する必要がある。

Objective-Cのプロトコルは仮想クラス(静的)メソッドをサポートしている。これらの メソッドは、プロトコルを実装するクラスによって実装されなければならない。 (を実装するクラスによって実装されなければならない(オプションでない限り)。これらのセマンティクスに合わせるために セマンティクスと一致させるために、static のメソッドはバーチャルである。これはまた、Objective-Cとリンクしている静的メソッド メソッドは本体を持つことができない。

オプションのメソッド

import core.attribute : optional, selector;
import core.stdc.stdio : printf;

struct objc_selector;
alias SEL = objc_selector*;

extern (C) SEL sel_registerName(in char* str);

extern (Objective-C)
extern class NSObject
{
    static NSObject alloc() @selector("alloc");
    NSObject init() @selector("init");
}

extern (Objective-C)
interface Foo
{
    bool respondsToSelector(SEL sel) @selector("respondsToSelector:");
    void foo() @selector("foo");

    // これはオプションのメソッドである
    @optional void bar() @selector("bar");
}

extern (Objective-C)
class Bar : NSObject, Foo
{
    override static Bar alloc() @selector("alloc");
    override Bar init() @selector("init");

    bool respondsToSelector(SEL sel) @selector("respondsToSelector:");

    void foo() @selector("foo")
    {
        printf("foo\n");
    }
}

void main()
{
    Foo f = Bar.alloc.init;

    // インスタンス`f`がメソッド`bar`を実装しているか実行時に確認する
    if (f.respondsToSelector(sel_registerName("bar")))
        f.bar();
    else
        f.foo();
}

Objective-Cのプロトコルはオプショナル・メソッドをサポートしている。オプショナル・メソッドは を実装するクラスが実装する必要はない。 プロトコルを実装するクラスが実装する必要はない。オプショナル・メソッドを安全に呼び出すには、ランタイム・チェックを行う必要がある。 を実行し、受信側がそのメソッドを実装していることを確認する必要がある。

Dでは、オプショナルメソッドは @optional属性で表される。

インスタンス変数

import core.attribute : selector;

// これはオプションのメソッドである
extern (Objective-C)
extern class NSObject
{
    static NSObject alloc() @selector("alloc");
    NSObject init() @selector("init");
}

extern (Objective-C)
class Foo : NSObject
{
    int bar_;

    override static Foo alloc() @selector("alloc");
    override Foo init() @selector("init");

    int bar() @selector("bar")
    {
        return bar_;
    }
}

void main()
{
    auto foo = Foo.alloc.init;
    foo.bar_ = 3;
    assert(foo.bar == 3);
}

インスタンス変数の宣言は、通常の Dクラスと全く同じだ。

壊れやすい基底クラスの問題を解決するために、Objective-Cのインスタンス変数には動的オフセットがある。 にはダイナミック・オフセットがある。つまり、ベース・クラスは つまり、サブクラスが再コンパイルや再リンクをしなくても、ベース・クラスが変更(インスタンス変数の追加や削除)できるということだ。 再コンパイルや再リンクを必要としない。この機能のおかげで、次のようなバインディングを作成するときにインスタンス変数を宣言する必要がない。 インスタンス変数を宣言する必要はない。

インスタンス・メソッドを呼び出す

Objective-Cのインスタンス・メソッドの呼び出しは、通常のDメソッドの呼び出しと同じ構文を使う。 を呼び出すのと同じ構文を使用する:

const(char)* result = object.UTF8String();

コンパイラは、Objective-Cのリンケージがあるメソッドの呼び出しを見つけると、Objective-CコンパイラがObjective-Cのリンケージを呼び出すのと同様の呼び出しを生成する。 コンパイラーは、Objective-Cリンケージがあるメソッドへの呼び出しを見つけると、Objective-Cコンパイラーがメソッドを呼び出すのと同じような呼び出しを生成する。 と同じような呼び出しを生成する。

@selector 属性

@selector 属性はコンパイラが認識する UDAである。これは、Objective-Cのメソッドを呼び出すときに セレクタを指定するために使われる。

Objective-Cのセレクタはコロン文字を含むことができる。 識別子では無効である。Dはメソッドのオーバーロードをサポートしている。 Dはメソッドのオーバーロードをサポートしている。これら2つの理由から この2つの理由から、Dではセレクタを推論するのではなく、手動で指定したほうがよい、 では、セレクタを推論するのではなく、手動で指定できるほうがよい。こうすることで、より自然な名前を持つことができる。 を持つことができる:

import core.attribute : selector;

extern (Objective-C)
extern class NSString
{
    NSString initWith(in char*) @selector("initWithUTF8String:");
    NSString initWith(NSString) @selector("initWithString:");
}

ここでは、メソッドinitWith は2つのバージョンでオーバーロードされている。 in char* もうひとつはNSString である。これら2つのメソッドは つの異なるObjective-Cセレクタにマッピングされている、initWithUTF8String:initWithString:

この属性はdruntimeの core.attribute.属性 属性はバージョン識別子 D_ObjectiveCが有効な場合にのみ定義される。

コンパイラーによるチェック

コンパイラーは以下のチェックを行い、正しい使い方を強制する。 @selector の正しい使用を強制する:

いずれかのチェックに失敗すると、コンパイル・エラーが発生する。

@optional 属性

@optional 属性はコンパイラが認識する UDAである。この属性は、コンパイラに、Objective-Cのリンケージを持つ Objective-Cとのインターフェイス "であることをコンパイラに伝えるために使われる。 オプションであることをコンパイラに伝えるために使われる。つまり、インターフェイスを実装するクラスはそのメソッドを実装する必要がない。 メソッドを実装する必要がないことを意味する。

オプショナルメソッドを安全に呼び出すには、ランタイムチェックを行う必要がある。 を実行する必要がある。

この属性はdruntimeの core.attribute.属性 属性はバージョン識別子 D_ObjectiveCが有効な場合にのみ定義される。

コンパイラーによるチェック

コンパイラーは以下のチェックを行い、正しい使い方を強制する。 @optional の正しい使用を強制する:

いずれかのチェックに失敗すると、コンパイル・エラーが発生する。

D_ObjectiveC バージョン識別子

D_ObjectiveC バージョン識別子は、定義済みのバージョン識別子である。 識別子である。Objective-Cのサポートがターゲットで利用可能な場合に有効になる。 ターゲットで

Objective-Cリンケージ

Objective-Cのリンケージは、クラスにextern (Objective-C) 属性を付けることで実現できる。例:":

import core.attribute : selector;

extern (Objective-C)
extern class NSObject
{
    NSObject init() @selector("init");
}

extern (Objective-C) 。 暗黙のObjective-Cリンケージを得る。

このリンケージはすべてのプラットフォームで認識されるが、Objective-Cがサポートされていないプラットフォームで使用するとコンパイルエラーが発生する。 エラーを発行する。 をサポートしていないプラットフォームで使用すると、コンパイル・エラーが発生する。これにより、Objective-Cが利用できないプラットフォームから、Objective-C宣言を簡単に隠すことができる。 の宣言を簡単に隠すことができる。 version文を使って、Objective-Cが利用できないプラットフォームからObjective-C宣言を簡単に隠すことができる。 文字列ミックスイン" や他の回避策に頼ることなく、Objective-C宣言を簡単に隠すことができる。

メモリ管理

Objective-Cでメモリ管理を行うには、ARC(Automatic Reference Counting)を使うのが望ましい。 使うことだ。 これはDではサポートされていないため、代わりに手動のメモリー管理が必要となる。 が必要となる。これは release Objective-Cの昔のように、Objective-Cのインスタンス上で呼び出すことで実現する。

フレームワーク

ほとんどのObjective-Cのコードは「フレームワーク」と呼ばれるものにバンドルされている。 これは基本的に普通のディレクトリで、.framework という拡張子がついている。 と特定のディレクトリレイアウトを持つ。フレームワークには、ダイナミック・ライブラリ ライブラリ、すべてのパブリック・ヘッダ・ファイル、そしてフレームワークが必要とするリソース(イメージ、サウンドなど)が含まれている。 など)が含まれている。

これらのディレクトリは、Objective-Cのコンパイラーやリンカーのようないくつかのツールによって、フレームワークであると認識される。 コンパイラーやリンカーのようないくつかのツールによってフレームワークとして認識される。のフレームワークとリンクするには、以下のフラグを使う。 DMDからフレームワークとリンクするには、以下のフラグを使う:

-L-framework -L<Framework>
ここで、<Framework> はリンクするフレームワークの名前である。 .framework である。2つの-L フラグは必須である。 リンカは、-framework フラグとフレームワーク名の間にスペースがあることを期待するからである。 フレームワークの名前である。DMDはこれを処理できず、代わりにフレームワーク名を別のフラグとして解釈する。 を別のフラグとして解釈する。

フレームワークのパス

上記のフラグを使うと、リンカは標準フレームワークの パスで検索する。フレームワークの標準検索パスは以下のとおりである:

DMDの次のフラグを使えば、フレームワークを検索する新しいパスを追加できる。 を追加することができる:

-L-F<framework_path>

詳細については、リファレンス・ドキュメント およびld manページを参照のこと。

完全な使用例

この例では、Objective-Cの文字列NSString を作成し、 を使ってメッセージを標準エラーに記録する。 メッセージをNSLog を使って標準エラー出力に記録する。

import core.attribute : selector;

extern (Objective-C)
extern class NSString
{
    static NSString alloc() @selector("alloc");
    NSString initWithUTF8String(in char* str) @selector("initWithUTF8String:");
    void release() @selector("release");
}

これは、以下の宣言を簡略化したものである。 NSString クラスの宣言を簡略化したものである。これは alloc メソッドはクラスのインスタンスを確保する。この initWithUTF8String: メソッドは、UTF-8のC文字列をObjective-C文字列に変換するために使われる。 NSString の文字列に変換する。この release メソッドは、文字列の解放と割り当て解除に使われる。Dは ARCをサポートしていないので をサポートしていないので、Objective-Cのインスタンスを手動で解放する必要がある。

extern (C) void NSLog(NSString, ...);

これは NSLog 関数はシステムログ機能、すなわち標準エラー出力とコンソール出力にメッセージを出力する。 とコンソールにメッセージを出力する。

auto str = NSString.alloc();

NSString というクラスのインスタンスを確保する。

str = str.initWithUTF8String("Hello World!")

Cの文字列を使ってObjective-Cの文字列を初期化する。

NSLog(str);

文字列をstderrに記録すると、次のように表示される。 ターミナルに次のように表示される:

2015-07-18 13:14:27.978 main[11045:2934950] Hello World!
str.release();

文字列を解放し、デアロケートする。

すべてのステップを合わせると次のようになる:

module main;

import core.attribute : selector;

extern (Objective-C)
extern class NSString
{
    static NSString alloc() @selector("alloc");
    NSString initWithUTF8String(in char* str) @selector("initWithUTF8String:");
    void release() @selector("release");
}

extern (C) void NSLog(NSString, ...);

void main()
{
    auto str = NSString.alloc().initWithUTF8String("Hello World!");
    NSLog(str);
    str.release();
}

アプリケーションをコンパイルする際には、必要な この場合はFoundationフレームワークである。例:

dmd -L-framework -LFoundation main.d