У меня есть странная проблема с NSInvocation
. Я использую его в качестве обратного обратного вызова при завершении сетевой операции. Позвольте мне пояснить предыдущее предложение более подробно:NSInvocation получить цель вызывает EXC_BAD_ACCESS
Я использую настраиваемый сетевой протокол, который работает через сокет TCP, и у меня есть класс, который использует этот протокол и служит в качестве подключения к моему серверу. Теперь класс имеет метод позволяет сказать performNetworkRequestWithDelegate:
, который реализуется следующим образом:
- (void)performNetworkRequestWithDelegate:(id<MyClassDelegate>)delegate
{
NSString *requestKey = [self randomUniqueString];
id request = [self assembleRequestAndSoOnAndSoForth];
[request setKey:requestKey];
SEL method = @selector(callbackStatusCode:response:error:);
NSMethodSignature *signature = [delegate methodSignatureForSelector:method];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.target = delegate;
invocation.selector = method;
delegateInvocationMap[requestKey] = invocation; //See below for an explanation what the delegateInvocationMap is
[self sendRequest:request];
}
Ладно, так что я знаю, что есть некоторые вещи, которые должны быть объяснены. Во-первых, не беспокойтесь о чем-либо, связанном с запросом, кроме requestKey
. Он работает так: ключ запроса возвращается обратно ко мне, когда я получаю ответ от сервера. Таким образом, это похоже на поле HTTP-заголовка, которое возвращается к вам, когда вы получаете ответ от сервера. Таким образом, я могу определить, какой запрос был сделан. delegateInvocationMap
- это NSMutableDictionary
, который держится за наши призывы, и мы можем получить правильный ответ, когда получим ответ и разобраем requestKey
.
Теперь обработчик для ответа, как это:
- (void)processResponse:(id)response
{
//Check for errors and whatnot
NSString *requestKey = [response requestKey];
if (!requestKey) return; //This never happens and is handled more correctly but keep it like this for the sake of simplicity
NSInvocation *invocation = delegateInvocationMap[requestKey];
if (!invocation) return;
[delegateInvocationMap removeObjectForKey:requestKey];
if (!invocation.target) return; //THIS LINE IS THE PROBLEM
[self setInvocationReturnParams:invocation fromResponse:response];
[invocation invoke]; //This works when everything is fine
}
Эта функция также работает, когда есть успешный возврат ответа или при наличии каких-либо ошибок, я обращаться с ними правильно. За исключением одного:
Когда цель вызова освобождена, я получаю EXC_BAD_ACCESS
при попытке проверить, есть ли цель для моего вызова. Яблоко документы говорят:
The receiver’s target, or nil if the receiver has no target.
Как я могу проверить, если приемник был уже освобождаться? Это огромная боль.
EDIT: В комментариях ниже я обнаружил, что доступ к удаленному объекту всегда неизвестен. Я не знаю, есть ли официальная документация, указывающая это (я еще не проверял), но у меня есть обходная идея. Можно ли будет наблюдать цель вызова для вызова dealloc через KVO?
Я не хочу, чтобы вызов поддерживал сильную ссылку, поскольку эти ссылки чаще всего ссылаются на контроллеры представлений. Я хочу проверить, существует ли объект, на который нацелен призыв, и если я просто хочу «забыть все». – Majster
Вы используете ARC? –
Да, я использую ARC. – Majster