5

私はこのコードを試しました:

// main.m
#import <stdio.h>

@interface Test 
+ (void)test;
@end
@implementation Test
+ (void)test
{
    printf("test");
}
@end

int main()
{
    [Test test];
    return  0;
}

フレームワークなしで LLVM/Clang を使用すると、次のエラーでコンパイルされません。

Undefined symbols:
  "_objc_msgSend", referenced from:
      _main in main.o
ld: symbol(s) not found
clang: error: linker command failed with exit code 1 (use -v to see invocation)

だから私は追加しましlibobjc.dylibた。コードはコンパイルされましたが、次の実行時例外がスローされました:

objc[13896]: Test: Does not recognize selector forward::
Program received signal:  “EXC_BAD_INSTRUCTION”.

#0  0x9932a4b4 in _objc_error
#1  0x9932a4ea in __objc_error
#2  0x993212b6 in _objc_msgForward
#3  0x99321299 in _objc_msgForward
#4  0x99321510 in _class_initialize
#5  0x99328972 in prepareForMethodLookup
#6  0x99329c17 in lookUpMethod
#7  0x99321367 in _class_lookupMethodAndLoadCache
#8  0x99320f13 in objc_msgSend
#9  0x00001ee5 in start

ルートクラスに必要な実装があることに気付きましたが、次に何をすればよいかわかりません。新しいルート クラスを作成するには何が必要ですか? また、これに関する仕様はありますか?

4

4 に答える 4

7

同じ「学術的な」質問があったので、この質問にたどり着きました。少し調べてみたところ、この質問に対する他の回答が完全に正しくないことがわかりました。

確かに、Apple Objective-C 2.0 ランタイムでは、コードを機能させるために特定のメソッドを実装する必要があります。実際に実装する必要があるメソッドは、クラス メソッドだけinitializeです。

@interface MyBase 
+ (void)test;
@end
@implementation MyBase
+ (void)initialize {}
+ (void)test {
 // whatever
}
@end

initializeクラスを最初に使用すると、ランタイムが自動的に呼び出されます ( Apple のドキュメントで説明されています)。このメソッドを実装していないことが、メッセージ転送エラーの原因です。

(または gcc)でコンパイルclang test.m -Wall -lobjcすると、クラス メソッド test を問題なく呼び出すことができます。オブジェクトの割り当てを機能させることは別の話です。少なくとも、isaインスタンス変数を使用している場合は、基本クラスへのポインターが必要です。ランタイムは、これが存在することを期待しています。

于 2011-01-25T17:39:37.217 に答える
2

Apple ランタイムでは、最小仕様は非常に簡単に説明されています。プロトコル内のすべてのメソッドを実装する必要があります。ここNSObjectを参照してください。これは絶対に自明ではありません。インスタンスを作成できるようにするなど、いくつかの追加関数を追加することをお勧めします。Apple のすべてのフレームワークには、2 つのパブリック ルート クラスしかありません:と. 実際には、ルート クラスを作成する理由はまったくありません。この問題に関する Apple の文書があるかどうかはわかりません。+allocNSObjectNSProxy

実際に行うことは、それらを継承するNSObjectNSProxy、それらの上に構築することです。次のようにすると、コードが機能します。

@interface Test : NSObject
+ (void)test;
@end

Tilo が指摘したように、これは GNU ランタイムのような他のランタイムには当てはまりません。

于 2010-08-27T09:59:01.213 に答える
2

私のシステム (Linux + GCC の GNUstep) では、サンプルを機能させるために、上記の alloc メソッドを次のメソッドに置き換える必要がありました。これは、新しい obj-c ランタイムによるものだと思います (ランタイムのドキュメントはこちら: Mac Developer Library のObjective-C Runtime Reference .

+ alloc
{
  return (id)class_createInstance(self, 0);
}
于 2014-08-20T07:04:50.240 に答える
1

上記の例は、gcc と GNU-runtime で正常にコンパイルされます。Objective-C では通常、スーパー クラスを持たないだけで、どのクラスもルート クラスになることができます。Apple ランタイムが別の何かを必要とする場合、それはランタイム固有です。

さらに、ルート クラスに固有のものがあります。

すべてのインスタンス メソッドは、同じ実装を持つクラス メソッドでもあります (別の方法で明示的に実装されていない場合)。次のアプリの出力:

#import <stdio.h>

@interface Test
+ alloc;
+ (void)test;
- (void)test;
- (void)otherTest;
@end
@implementation Test
+ alloc
{
  return (id)class_create_instance(self);
}

+ (void)test
{
    printf("class test\n");
}

- (void)test
{
    printf("instance test\n");
}

- (void)otherTest
{
    printf("otherTest\n");
}
@end

int main()
{
    id t = [Test alloc];
    [Test test];
    [t test];
    [Test otherTest];
    [t otherTest];
    return  0;
}

だろう:

class test
instance test
otherTest
otherTest

新しいルート クラスを作成する上で最も難しい部分は+allocand-deallocですが、私の例に見られるように、ランタイム (私の場合は GNU ランタイム) がこれを行うことができます。しかし、実行時の割り当てが十分かどうかはわかりません。一部の財団では、独自の割り当てメカニズムを使用して参照カウンターをオブジェクト構造から隠していることを知っています。Appleもこれを行っているかどうか、またランタイムがすでにそれを処理しているかどうかはわかりません。

于 2010-09-16T12:54:35.347 に答える