GNU Objective-C 运行时技巧

发布于 2024-09-06 12:13:55 字数 1696 浏览 6 评论 0原文

在 GNU Objective-C 运行时中,我可以将半任意数据片段附加到实例变量吗?

挑战:

我目前正在开发一种类似于 Linux 的 Cocoa 工作,作为一种宠物项目。 (拜托,我们不要被所有“使用 GNUStep”的东西所左右。我知道这一点,但它不适合我的需要。继续……)为此,我试图拼凑一个简单的 ORM 系统,让人想起Perl 的 DBIx::Class。总体思路是使声明尽可能简单(读作:短),并且如果可能的话,不需要提供用于重写的 +(id)constantClassAttribute 方法。

总体思路是按如下方式声明我的结果类:

@interface SomeTable : ORMResult {
  unsigned long long id;
  ORMResult *toOneRelation;
  ORMResultSet *toManyRelation;
}

@end

到目前为止,一切都很顺利。我现在可以使用 [ORMResult self]->ivars 访问这些字段,并执行各种令人讨厌的操作,例如自动生成 -[toManyRelation]等访问器>-[setToOneRelation]。小菜一碟。不幸的是,我无法使用此设置添加两条信息;一个很容易解决,另一个则不太容易解决:

  1. 实际结果类是什么?

    这是通过子类化 ORMResult (如 SomeTable)并将其插入来解决的 在那里,使用运行时动态(ag)ics 来确定它的 to-ness(toMany、toOne)。

  2. (这是一个棘手的问题!)关系可以为空吗?

    这个问题不太容易解决。我最初的想法是

    1. (ab)使用协议,如下所示:

      @interface SomeTable : ORMResult {
        无符号长长ID;
        ORMResult  *到一个关系;
      }
      
      @结尾
      

      这可以编译,但不幸的是,当我尝试使用 GDB 来检查 ivars->ivar_list 条目我发现协议信息实际上并未保留 供运行时使用。我想这会产生某种扭曲的感觉, 因为协议声明主要是供编译器使用的。

    2. 滥用协议标识符(byrefbycopy 等,使用定义:

      @interface SomeTable : ORMResult {
        无符号长长ID;
        可为空 OMRResult *toOneRelation;
      }
      
      @结尾
      

      这有一个相当明显的缺点,即实际上不起作用,因为这些 说明符显然只在协议方法声明中起作用。

那么,问题是如何在实践中实现将信息附加到 ivars 上呢?

注意: 正如最初提到的,我使用的是 Linux 上的 GCC 提供的 GNU Objective-C 运行时;并且不是Apple 提供的!

编辑:星痘!我忘记了一个中心点:当然,另一种选择是简单地使所有关系都可以为空。我真的不想要这样,但如果没有其他选择,我想这就是我最终会走的路。

Can I, in the GNU Objective-C runtime, attach semi-arbitrary pieces of data to instance variables?

Challenge:

I'm currently working on a kind of Cocoa workalike for Linux, as a sort of pet project. (Please, let's not get sidetracked by all the "use GNUStep" stuff. I know about it, but it doesn't suit my needs. Moving on…) For this purpose I'm trying to cobble together a simple ORM system, reminiscent of DBIx::Class for Perl. The general idea is to make the declaration as simple (read: short) as possible, and if at all possible, without the need to provide +(id)constantClassAttribute methods for overriding.

The general idea is to declare my result classes as follows:

@interface SomeTable : ORMResult {
  unsigned long long id;
  ORMResult *toOneRelation;
  ORMResultSet *toManyRelation;
}

@end

So far, so hoopy. I can now access these fields using [ORMResult self]->ivars, and do all manner of nasty stuff, like automagically generating accessors like -[toManyRelation] or -[setToOneRelation]. Piece of cake. Unfortunately, there are two pieces of information I cannot add using this setup; one is simple enough to solve, the other not so much:

  1. What is the actual result class?

    This is solved by subclassing ORMResult (like SomeTable), and plugging that in
    there, using runtime dynam(ag)ics to figure out it's to-ness (toMany, toOne).

  2. (And this is the tricky one!) Is the relationship nullable?

    This is less easily solved. My initial ideas were

    1. (ab)using protocols, like so:

      @interface SomeTable : ORMResult {
        unsigned long long id;
        ORMResult <ORMNullable> *toOneRelation;
      }
      
      @end
      

      This compiles, but unfortunately, when I try to use GDB to inspect the
      ivars->ivar_list entries I find that the protocol information isn't actually kept
      for the runtime to toy with. This makes, I suppose, some kind of twisted sense,
      as protocol declarations are mostly for the compiler.

    2. Abusing the protocol identifiers (byref, bycopy and friends, using defines:

      @interface SomeTable : ORMResult {
        unsigned long long id;
        nullable OMRResult *toOneRelation;
      }
      
      @end
      

      This has the rather obvious drawback of not actually working, as these
      specifiers apparently only work in protocol method declarations.

The question, then, is how can this attachment of information to the ivars be pulled off in practice?

Note: As mentioned initially, I'm using the GNU Objective-C runtime, as supplied by GCC on Linux; and not the one supplied by Apple!

Edit: Starpox! I forgot a central point: An alternative, of course, is to simply make all relations nullable. This I don't really want, but if no other alternative exists, I guess that's the path I'll end up going down.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

云仙小弟 2024-09-13 12:13:55

好吧,过去我们在 Mac 上这样做的方法是创建一个保存 NSMutableDictionary 的全局变量,我们将要附加到对象的数据放入其中。只需使用指针的字符串表示形式作为键即可。

唯一的困难是弄清楚一个对象何时消失并确保它在字典中的条目也被删除。您可能必须求助于像方法 swizzling -dealloc 这样的黑客技术才能实现这一点。

Well, how we used to do this in ye olde days on the Mac was to create a global variable holding an NSMutableDictionary into which we put the data we want to attach to an object. Simply use a string representation of the pointer as the key.

The only difficulty becomes figuring out when an object has gone away and making sure that its entry in the dictionary is removed as well. You may have to resort to hackery like method swizzling -dealloc to achieve that.

零時差 2024-09-13 12:13:55

您可以查看 objc_setAssociatedObject 和朋友,它们允许您将任意数据附加到对象。但是,我不确定您运行的 libobjc 版本是否支持它们。

You might look at objc_setAssociatedObject and friends, which allow you to attach arbitrary data to an object. However, I'm not sure if they're supported in the version of libobjc that you're running.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文