开发者

GNU Objective-C runtime trickery

开发者 https://www.devze.com 2023-01-03 22:09 出处:网络
Can I, in the GNU Objective-C runtime, attach semi开发者_Go百科-arbitrary pieces of data to instance variables?

Can I, in the GNU Objective-C runtime, attach semi开发者_Go百科-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.


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消