#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:
метод также должен быть реализован.