【问题标题】:Can the new Clang Objective-C literals be redirected to custom classes?新的 Clang Objective-C 文字可以重定向到自定义类吗?
【发布时间】:2012-06-30 10:20:07
【问题描述】:

尽管@ 的重载开始涉足危险领域,但我喜欢在 Clang 3.1 中添加新的 Objective-C 文字。不幸的是,新文字对我的用处有限。除了代码需要与 AppKit 交互的情况外,我大多放弃使用 Foundation 类,转而使用我自己的自定义框架(出于各种原因;其中大部分是我需要直接控制所使用的内存分配模式按对象)。

我总是可以使用一些运行时技巧来将新创建的对象作为我的自定义类传递(这是我已经对字符串对象文字所做的事情,因为只有非 Apple GCC 运行时支持 -fconstantstring=class 标志) , 但这充其量只是一个 hack,并且会抛弃我通过替换等效的 Foundation 类而获得的所有好处。

与字符串对象字面量不同,Clang 实现的新字面量实际上不是常量类(内存布局是硬编码的);相反,适当的消息被发送到它们各自的类,以在运行时创建和初始化一个新对象。效果与您自己创建对象没有什么不同。从理论上讲,这意味着新文字所使用的类和调用的方法不是硬编码的。在实践中,我找不到任何方法将它们更改为指向我自己的自定义类和方法(事实上,我很乐意指向自定义类;在运行时将虚拟方法指向实际方法并不难)。

当我第一次研究这个时,我真的希望找到一组可以用来做我所要求的标志,但由于我没有找到任何标志,我希望有人有一个解决方案。

【问题讨论】:

  • 可以使用新语法:mikeash.com/pyblog/…,但是让编译器创建您自己的类的实例可能需要对您的编译器进行破解:aussiebloke.blogspot.com/2012/06/llvm-clang-hacking-part-3.html
  • 与其求助于编译器黑客,现在使用宏可能更容易:例如将MO(@{@"foo":@1}) 扩展为[MyObject myObjectWithDictionary: @{@"foo":@1} ]。它有点难看,并且会自动释放一个临时对象,但它仍然比旧语法更简洁(也更安全)。
  • @rickster 这可能是我最终要做的;不理想但不是一个糟糕的解决方案。尽管如果预处理器可以处理更广泛的字符集,那将是一个更好的解决方案。然后可以使用@I(45)@U(16) 或其他同样引人注目的东西。相反,我可能不得不为宏命名,因此很明显它们是文字替换,例如 LitInt(45)LitUInt(16)
  • 这就是为什么将 API/函数/类名称硬编码为一种语言是一种糟糕的做法。 Apple/NeXT/Objective-C 的设计者史诗般的概念、设计和工程失败。
  • @H2CO3 问题是,只有字符串文字被硬编码到 ObjC 中,这是为了在创建它时处理限制。新的硬编码文字得益于 Apple 的推动,我完全同意这是一种糟糕的做法,并将我最​​喜欢的语言带入了黑暗的领域。我真的希望 Apple 停止尝试隔离开发管道;他们应该尝试让 ObjC 及其框架更加开放,以促进跨平台开发。如果开发人员知道他们可以使用 ObjC 和 Cocoa 并支持所有 PC 平台,那将会带来很多新鲜血液。

标签: objective-c clang objective-c-literals


【解决方案1】:

cmets 说的都对,但只是总结一下:

  • 没有。

Apple 的 @{}@[]@"" 文字的含义被硬编码到 Clang 中。你可以在这里看到它:http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/NSAPI.cpp?view=markup 这都是相当模块化的,这意味着 Clang 黑客添加自己的文字语法并不难……但“模块化”并不意味着“可从外部访问”。添加新语法甚至将现有语法重定向到新类肯定需要自己重建 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 博客上的 cmets 中有所提及。 http://www.mikeash.com/pyblog/friday-qa-2012-06-22-objective-c-literals.html 但这看起来不太像 Objective-C-ish(或非常 C++ish!),它只适用于 Objective-C++11 编译器,一般请不要这样做。 :)

【讨论】:

  • 因为你是唯一一个真正提交作为答案的人,我会接受你的。
  • 万岁! :) 我已经开始浏览“未回答的问题”列表,看看我可以在哪里提供帮助,我发现 StackOverflow 上大多数的“未回答”问题实际上已经得到了令人满意的回答,就在cmets 而不是真正的答案。这是其中之一。 :)
【解决方案2】:

您可以使用 @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关键字的更多信息,see here

注意

因为@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;
}

测试.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!

【讨论】:

  • 这有点像 hack,但我认为这是任何人在不直接修改编译器的情况下可以获得的最接近的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-05
  • 1970-01-01
  • 2011-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多