1. 3
  1.  

  2. 1

    This has been needed since the non-fragile ABI was introduced. With classic Objective-C, you’d get the same thing by using a static C function and @defs. For example, with this in the header:

    @interface SomeClass : ... 
    {
    @private
      int boringIntValue;
    }
    @end
    

    You’d do something like this:

    typedef struct { @defs(SomeClass) } SomeClassFields ;
    static void incrementField(SomeClassFields *self)
    {
      self->boringIntValue++;
    }
    
    @implementation SomeClass
    - (void)exampleMethod
    {
      incrementField((SomeClassFields*)self);
    }
    @end
    

    The C function got access to all of the ivars of the object by using a struct with the same layout. This was trivial to support in the original StepStone compiler because Objective-C classes were lowered to C structured and @defs was just a text substitution thing dropping the fields into another structure. With the non-fragile ABI, classes no longer had a fixed compile-time-defined structure and so @defs was impossible to implement. If you wrote a C function and passed it the object pointer, you were stuck with the access permissions, so you couldn’t touch a @private ivar. A bunch of helper functions became private helper methods. With direct methods, they can go back to effectively being C functions but with the same syntax and access control checks as if they were Objective-C methods (so you can access @private or @package methods, but not across an ABI boundary).

    The slightly interesting twist is that the linkage model for this effectively makes them package-local (not private) methods and, with LTO, LLVM will happily inline them anywhere in the same module. This lets you do fun things like define direct property accessors when compiling a particular framework, but not make them direct in the public headers that you expose. Closely related classes can access each others’ instance variables directly fi you do this, but you retain a stable ABI at the framework level.