19

のオーバーロードは@危険な領域に足を踏み入れ始めていますが、Clang 3.1 での新しい Objective-C リテラルの追加が気に入っています。残念ながら、新しいリテラルは私にはあまり役に立ちません。コードが AppKit とやり取りする必要がある場合を除いて、私は独自のカスタム フレームワークを優先して Foundation クラスの使用をほとんどやめました (さまざまな理由で、そのほとんどは、使用されるメモリ割り当てパターンを直接制御する必要があるためです)。オブジェクトによって)。

新しく作成されたオブジェクトをカスタム クラスとして渡すために、いつでもランタイムのトリックを使用できます (これは、Apple 以外の GCC ランタイムのみが-fconstantstring=classフラグをサポートするため、文字列オブジェクト リテラルで既に行う必要があることです) が、これはハックです。せいぜい、最初から同等の Foundation クラスを置き換えることによって得たすべての利点を捨ててしまいます。

文字列オブジェクト リテラルとは異なり、Clang が実装する新しいリテラルは実際には定数クラスではありません (メモリ レイアウトがハードコーディングされている場合)。代わりに、適切なメッセージがそれぞれのクラスに送信され、実行時に新しいオブジェクトが作成および初期化されます。オブジェクトを自分で作成した場合と結果は変わりません。理論的には、使用されるクラスと新しいリテラルによって呼び出されるメソッドがハードコードされていないことを意味します。実際には、私自身のカスタム クラスとメソッドを指すようにそれらを変更する方法を見つけることができません (実際には、カスタム クラスを指すだけで十分です。実行時にダミー メソッドを実際のメソッドに指すことは難しくありません)。 )。

これを最初に調べたとき、私が求めていることを行うために使用できるフラグのセットを見つけることを本当に望んでいましたが、何も見つからなかったので、誰かが解決策を持っていることを願っています.

4

2 に答える 2

12

@compatibility_alias一部の Objective-C リテラルのクラスをキーワード トリックで置き換えることができます。

これが例です。

@compatibility_alias NSNumber AAA;

もちろん、新しいクラスに適切な実装を提供する必要があります。

#import <Foundation/NSObject.h>

@interface  AAA : NSObject
+ (id)numberWithInt:(int)num;
@end

@implementation AAA
+ (id)numberWithInt:(int)num
{
    return  @"AAAAA!!!";    // Abused type system just to check result.
}
@end

@compatibility_alias NSNumber AAA;

これで、Clang が作業を行います。これが数値、配列、辞書リテラルで機能することを確認しました。残念ながら、文字列リテラルは静的に発行されるように見えるため、機能しません。

@compatibility_aliasキーワードの詳細については、こちらを参照してください。

ノート

キーワードは現在のコンパイル ユニットに適用されるコンパイラ ディレクティブであるため@compatibility_alias、コンパイル ユニットを分離して、Apple の Foundation Kit の NSObject クラスとのシンボルの重複を避ける必要があります。これが私がやった方法です。

main.m

#import "test.h" // Comes before Foundation Kit.
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        NSLog(@"return of test = %@", test());
        // insert code here...
        NSLog(@"Hello, World!");

    }
    return 0;
}

test.h

id test();

test.m

#import "test.h"
#import <Foundation/NSObject.h>

@interface  
AAA : NSObject
+ (id)numberWithInt:(int)v;
+ (id)arrayWithObjects:(id*)pobj count:(int)c;
+ (id)dictionaryWithObjects:(id*)pvals forKeys:(id*)pkeys count:(int)c;
@end
@implementation AAA
+ (id)numberWithInt:(int)v
{
    return  @"AAAAA as number!!!";
}
+ (id)arrayWithObjects:(id*)pobj count:(int)c
{
    return  @"AAAAA as array!!!";
}
+ (id)dictionaryWithObjects:(id*)pvals forKeys:(id*)pkeys count:(int)c
{
    return  @"AAAAA as dictionary!!!";
}
@end



@compatibility_alias NSDictionary AAA;
@compatibility_alias NSArray AAA;
@compatibility_alias NSNumber AAA;



id test()
{
//  return  @{};
//  return  @[];
    return  @55;
}

結果。

2013-03-23 08:54:42.793 return of test = AAAAA!!!
2013-03-23 08:54:42.796 Hello, World!
于 2013-03-23T00:08:22.500 に答える
11

コメントはすべて正しいですが、要約すると:

  • いいえ。

Apple の@{}@[]、および@""リテラルの意味は、Clang にハードコードされています。ここで確認できます: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/NSAPI.cpp?view=markupすべてかなりモジュール化されているため、 Clang ハッカーは、独自のリテラル構文を追加します... しかし、「モジュラー」は「外部からアクセスできる」という意味ではありません。新しい構文を追加したり、既存の構文を新しいクラスにリダイレクトしたりするには、Clang を自分で再構築する必要があります。

NSURL内部をハッキングして Clang にリテラルを追加する方法に関するブログ記事を次に示します: http://www.stuartcarnie.com/2012/06/llvm-clang-hacking-part-3.html (@Josh Caswell に感謝)


C++11 拡張機能を備えた Objective-C++ を使用する場合は、次のような記述を可能にする「ユーザー定義リテラル」を使用できます。

NSURL *operator ""URL (const char *s) { return [NSURL URLWithString: @(s)]; }

int main() {
    ...
    NSURL *myurl = "ftp://foo"URL;
    ...
}

これは、Mike Ash のブログのコメントで言及されました。http://www.mikeash.com/pyblog/friday-qa-2012-06-22-objective-c-literals.htmlしかし、これはあまり Objective-C っぽい (または非常に C++ っぽい!) とは言えません。であり、Objective-C++11 コンパイラでのみ動作します。一般的にはこれを行わないでください。:)

于 2012-08-24T22:17:22.090 に答える