macOS 12.0.1 (Монтерей) XIB не загружается; возникает исключение «Этот кодер ожидает замененный объект … будет возвращен из NSClassSwapper»

#cocoa #xib #class-cluster

Вопрос:

У меня есть XIBS, содержащие пользовательские объекты, один из которых на самом деле является кластером классов, -init метод которого всегда возвращает один и тот же одноэлементный объект.

В основном:

 - (instancetype)init {  self = [super init];  if (HelpLinkHelperSingleton==nil)  {  // This is the first instance of DDHelpLink: make it the immortal singleton  HelpLinkHelperSingleton = self;  }  else  {  // Not the first DDHelpLink object to be created: discard this instance  // and return a reference to the shared singleton  self = HelpLinkHelperSingleton;  }  return self; }  

Начиная с macOS 12.0.1, загрузка XIB вызывает это исключение:

This coder is expecting the replaced object 0x600002a4f680 to be returned from NSClassSwapper.initWithCoder instead of lt;DDHelpLink: 0x600002a487a0gt;

Я пытался реализовать lt;NSSecureCodinggt; и сделать то же самое, но это тоже не работает.

Есть ли еще способ использовать кластеры классов в NIBs?

Ответ №1:

Я решил эту проблему, используя прокси-объект в XIB, который пересылает сообщения в синглтон.

 @interface HelpLinkHelperProxy : NSObject @end  @implementation HelpLinkHelperProxy {  HelpLinkHelper* _singleton; }  - (void) forwardInvocation:(NSInvocation*)invocation {  if (_singleton == nil)  {  _singleton = [HelpLinkHelper new];  }   if ([_singleton respondsToSelector:[invocation selector]])  {  [invocation invokeWithTarget:_singleton];  }  else  {  [super forwardInvocation:invocation];  } }  @end  

Если бы мы были подклассом от NSProxy вместо NSObject , решение выглядело бы так:

 @interface HelpLinkHelperProxy : NSProxy @end  @implementation HelpLinkHelperProxy {  HelpLinkHelper* _singleton; }  - (instancetype) init {  _singleton = [HelpLinkHelper new];  return self; }  - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel {  return [_singleton methodSignatureForSelector:sel]; }  - (void) forwardInvocation:(NSInvocation*)invocation {  if ([_singleton respondsToSelector:[invocation selector]])  {  [invocation invokeWithTarget:_singleton];  }  else  {  [super forwardInvocation:invocation];  } }    (BOOL) respondsToSelector:(SEL)aSelector {  return [HelpLinkHelper respondsToSelector:aSelector]; }  @end   

Комментарии:

1. Решение для колки! Но я бы рекомендовал обобщенное решение, которое является подклассом NSProxy . На самом деле, вам понадобится только одна реализация общего назначения для всех локальных прокси-решений: @interace LocalObject : NSProxy -(instancetype)initWithObject:(id)localObject … Затем, если бы вы хотели быть действительно умными, вы могли бы реализовать конструкторы удобства в виде категорий для конкретных объектов: @implementation LocalObject (HelpLinkProxy) (LocalObject*)helpLinkProxy { return [[LocalObject alloc] initWithObject:[HelpLinkHelper new]]; }

2. Я попробовал это сделать. Можно создать подкласс из NSProxy , и он будет работать в XIB, хотя NSProxy и не является подклассом NSObject . В этом случае _singleton будет инициализирован в init методе NSProxy подкласса, и methodSignatureForSelector: метод также должен быть реализован.