Вызов первоначальной реализации метода в категории [дубликат]

Ответственность за загрузку файлов класса несет ClassLoader. Давайте посмотрим, что произойдет, когда мы напишем наши собственные классы.

Пример 1:

class StaticTest {

      static int a;
      int b;
      int c;
}

Теперь мы можем видеть, что класс «StaticTest» имеет 3 поля. Но на самом деле нет существования переменной b, c. Но почему ???. Ладно, посмотрим. Здесь b, c - переменная экземпляра. Поскольку переменная экземпляра получает память во время создания объекта. Итак, здесь b, c пока не получают никакой памяти. Вот почему не существует b, c. Итак, существует только существование a. Для ClassLoader у него есть только одна информация о. ClassLoader еще не распознает b, c, потому что объект еще не создан.

Давайте посмотрим другой пример: Пример 2:

class StaticTest {

      public void display() {
          System.out.println("Static Test");
      }


      public static void main(String []cmd) {

             display();       
      }

}

Теперь, если мы попытаемся скомпилировать этот код, компилятор даст Ошибка CE. CE: отображение нестатического метода () не может ссылаться на статический контекст.

Теперь для ClassLoader это выглядит так:

class StaticTest {

      public static void main(String []cmd) {

             display();       
      }

}

В примере 2 Ошибка CE - это потому, что мы вызываем нестационарный метод из статического контекста. Таким образом, ClassLoader не может распознавать метод display () во время компиляции. Так возникает ошибка компиляции.

47
задан Kendall Helmstetter Gelner 6 July 2009 в 05:53
поделиться

4 ответа

Если вам нужен хакерский способ сделать это, что включает в себя выключение с целью выполнения-c, вы всегда можете использовать метод swizzling (вставьте здесь стандартные отказы). Это позволит вам хранить разные методы как арбитраж назвал селекторов, а затем поменяйте их во время выполнения, сколько вам нужно.

37
ответ дан Michael Dautermann 27 August 2018 в 16:15
поделиться
  • 1
    Это не обязательно «хакерский» способ. Сценарий Objective-C существует по какой-то причине. Это то, что делает Objective-C выше других скомпилированных языков. – Alexei Sholik 1 June 2011 в 12:10
  • 2
    Основываясь на моем опыте, разрезая на погоню, вы хотите использовать JRSwizzle, как указано в приведенной выше ссылке. Для меня это было пуленепробиваемо. – Clay Bridges 12 July 2011 в 15:48
  • 3
    Ссылка на код JRSwizzle: github.com/rentzsch/jrswizzle ... Я полюбил это, метод swizzling ОЧЕНЬ мощный, когда вы хотите настроить стороннюю библиотеку, чтобы сделать, как вам заблагорассудится! – LearnCocos2D 11 December 2011 в 17:58

С помощью swizzling «helper» методов, включенных в ConciseKit , вы фактически вызываете реализацию по умолчанию ... достаточно странно .. путем вызова вашей реализации SWIZZLED ..

Вы установили его в + (void) load, вызвав + (BOOL)swizzleMethod:(SEL)originalSelector with:(SEL)anotherSelector in:(Class)klass;, то есть

[$ swizzleMethod:@selector(oldTired:) 
            with:@selector(swizzledHotness:) in:self.class];

, а затем в swizzled method .. давайте предположим, что он возвращает -(id) .. вы можете сделать свое зло , или по какой-либо причине вы в первую очередь задираете ... а затем вместо возвращения объекта или self или еще чего ...

return [self swizzledHotness:yourSwizzledMethodsArgument];

Как объясняется здесь ...

В этом методе похоже, что мы снова вызываем тот же метод, вызываем и бесконечную рекурсию. Но к тому времени, когда эта линия будет достигнута, оба метода были заменены. Поэтому, когда мы вызываем swizzled_synchronize, мы на самом деле вызываем оригинальный метод.

Он чувствует и выглядит странно, но .. он работает. Это позволяет добавлять бесконечные приукрашивания к существующим методам и по-прежнему «называть супер» (фактически «я») и использовать преимущества ручной работы оригинального метода ... даже без доступа к исходному источнику.

1
ответ дан Alex Gray 27 August 2018 в 16:15
поделиться

Ознакомьтесь с моей статьей о решении, найденном в библиотеке разработчиков Mac: http://codeshaker.blogspot.com/2012/01/calling-original-overridden-method-from.html

В принципе, это то же самое, что и описанный выше метод Swizzling с кратким примером:

#import <objc/runtime.h>

@implementation Test (Logging)

- (NSUInteger)logLength {
    NSUInteger length = [self logLength];
    NSLog(@"Logging: %d", length);
    return length;
}

+ (void)load {
    method_exchangeImplementations(class_getInstanceMethod(self, @selector(length)), class_getInstanceMethod(self, @selector(logLength)));
}

@end
12
ответ дан Andras 27 August 2018 в 16:15
поделиться

Из comp.lang.objective-C FAQ listing : «Что, если несколько категорий реализуют один и тот же метод? Тогда ткань Вселенной, как мы ее знаем, перестает существовать. Собственно, это не совсем true, но, безусловно, будут возникать некоторые проблемы. Когда категория реализует метод, который уже появился в классе (будь то через другую категорию или в качестве первичного @implementation класса), определение этой категории перезаписывает ранее существующее определение. Обратите внимание, что если две категории переписывают один и тот же метод, то в зависимости от того, что было загружено последними «выигрышами», которые невозможно предсказать до запуска кода. »

Из developer.apple.com : «Когда категория переопределяет унаследованный метод, метод в категории может, как обычно, вызывать унаследованную реализацию через сообщение супер. Однако, если категория переопределяет метод, который уже существовал в классе категории, re не может ссылаться на исходную реализацию "

19
ответ дан Oren Trutner 27 August 2018 в 16:15
поделиться
  • 1
    Да, это действительно не поддерживается языком. – Chuck 6 July 2009 в 06:11
  • 2
    Я благодарю вас за комментарий, но я ищу, как это можно сделать (потому что я знаю, что это может быть, просто не легко), а не как это невозможно ... – Kendall Helmstetter Gelner 6 July 2009 в 15:24
  • 3
    Я думаю, что super должен решить исходный объект. В конце концов, категория очень похожа на подкласс (например, вы можете переопределить методы). – Raffi Khatchadourian 2 February 2012 в 11:14
  • 4
    Правильно ли переопределять в классе метод, объявленный и реализованный в категории суперкласса? – BergP 19 March 2013 в 16:05
  • 5
    Мне, вероятно, не нужно говорить, но на всякий случай, для будущих читателей: категория действительно совсем не похожа на подкласс. super не будет разрешать «исходный объект». – tooluser 9 May 2013 в 22:48