Вызов супер в реализации блока Objective-C
Вызывается метод супер, поддерживаемый в реализации блока Objective-C?
Когда я вызывал метод на супер, была бы выбрана ошибка EXC_BAD_ACCESS, но как только я изменил эти вызовы с [super methodToCall]
на [self methodToCall]
, и пусть сообщение движется вверх по цепочке ответчиков, в которой он работал нормально.
В экземпляре класса, в котором существует блок, нет реализации -methodToCall
, но в суперклассе (то есть классе, на который он наследуется) есть один.
Мне просто интересно узнать подробности о том, почему вызов метода супер в реализации блока был проблемой в первую очередь (технически), поэтому я могу избежать этого в будущем. У меня есть подозрение, что это связано с тем, как переменные захватываются в блоке и что-то о стеке и куче, но у меня нет конкретной идеи.
Примечание: код реализации блока вызывается до нескольких секунд после того, как блок хранится в свойстве, свойство использует copy, поэтому я не думаю, что это проблема с жизненным циклом блока, что все выглядит хорошо. Кроме того, это было только сбой на устройстве iPhone (3G), но он работал без сбоев в iPhone Simulator.
Результаты в EXC_BAD_ACCESS
:
[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
if (!error) {
[super didRetrieveItems];
} else {
[super errorRetrievingItems];
}
}];
Работает отлично, реализации -didRetrieveItems
и -errorRetrievingItems
находятся в суперклассе.
[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
if (!error) {
[self didRetrieveItems];
} else {
[self errorRetrievingItems];
}
}];
Ответы
Ответ 1
Технически это проблема с временем выполнения Objective-C, и основная механика того, как работают вызовы super
. В основном они захватывают как объект, который является получателем сообщения (self
во всех случаях), так и класс, который реализует конкретную версию метода (суперкласс класса, в котором реализуется реализация метода). Потому что большая часть подготовки к такому сообщению отправляется во время компиляции, а не во время выполнения, я не удивлюсь, если он плохо взаимодействует с блоками.
Я бы посмотрел, остается ли self
, когда сообщение будет отправлено. Обычно любые объекты, на которые делается ссылка в блоке, автоматически сохраняются. Так как super
работает несколько иначе, это может означать, что self
не сохраняется, как и следовало ожидать. Один простой способ проверить это - использовать вызовы на super
, как изначально написанные, и просто пропустить объект, называемый self
, и посмотреть, работает ли он. Если это окажется проблемой, вам может потребоваться вставить фиктивную ссылку на self
в блоке, чтобы получить автоматическое управление памятью.
В самом строгом смысле, однако, я не уверен, что вы можете зависеть от этого, работая вечно и всегда. Хотя блоки могут захватывать текущее состояние времени выполнения, на самом деле не имеет смысла (с точки зрения ООП), чтобы они могли разбить инкапсуляцию и вызывать реализацию суперкласса, поскольку иерархический уровень, на котором реализуются методы, должен быть непрозрачным для любого внешнего кода вызова. Я попытался бы найти другое решение, которое не зависит от иерархии наследования.
Ответ 2
Результаты в EXC_BAD_ACCESS:
[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
if (!error) {
[super didRetrieveItems];
} else {
[super errorRetrievingItems];
}
}];
Вероятно, из-за ошибки в компиляторе; попробуйте добавить [self class];
или любой другой вызов метода в себя в этом блоке, и это, вероятно, сработает.
Работает отлично, реализации -didRetrieveItems и -errorRetrievingItems находятся в суперклассе.
[self retrieveItemsForId:idString completionHandler:^(NSError *error) {
if (!error) {
[self didRetrieveItems];
} else {
[self errorRetrievingItems];
}
}];
Думаю, вас может смутить один из фундаментальных аспектов объектно-ориентированного программирования. Вы говорите, что реализаций этих методов в вашем классе нет, они существуют только в суперклассе.
Из-за наследования ваш класс также эффективно реагирует на вызовы методов. Просто позвоните им, как вы делаете выше, используя self
. Это будет работать, и именно так вы должны это делать!