Каким должен быть тип возвращаемого значения, когда метод может возвращать подклассы? - PullRequest
4 голосов
/ 06 января 2011

Вот несколько методов из некоторых классов Apple:

- (NSManagedObject *)objectWithID:(NSManagedObjectID *)objectID;
- (UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier;

+ (id)insertNewObjectForEntityForName:(NSString *)entityName inManagedObjectContext:(NSManagedObjectContext *)context

Разумно ожидать, что все эти методы будут возвращать подклассы возвращаемого типа.Из-за этого возвращаемый объект часто присваивается переменной ожидаемого типа, например:

BCCustomTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[BCCustomTableViewCell cellIdentifier]];

Это делает компилятор несчастным;бросок решает это, но приведение как это грязно:

BCCustomTableViewCell *cell = (id)[tableView dequeueReusableCellWithIdentifier:[BCCustomTableViewCell cellIdentifier]];

Однако, когда тип возвращаемого значения id, это приведение может быть удалено, хотя и за счет некоторой безопасности типа, что приводит ккод чище:

BCPerson *person = [NSEntityDescription insertNewObjectForEntityForName:BCPersonEntityName inManagedObjectContext:context];

Лично я предпочитаю, чтобы тип возвращаемого значения был id.Есть ли какое-либо обоснование, которое Apple использовала для выбора одного подхода над другим, или это просто из-за предпочтения разработчика, который написал методы?

Ответы [ 4 ]

4 голосов
/ 06 января 2011

В трех описанных вами примерах действуют два разных принципа:

В двух первых, Apple хочет, чтобы вы использовали приведение в качестве вещи типа «Я знаю, что я делаю»: когда вы получаете доступ к универсальному объекту через идентификатор, вы можете быть удивлены классом. возвращаемого значения, если вы не знаете, что делаете.

В последнем примере метод по сути является фабричным методом, эквивалентным alloc init, и в большинстве случаев вам лучше знать, что вы делаете.

Другими словами, чтобы ответить на ваш вопрос:

Для заводского метода, id, для геттера, такого же, как и для сеттера.

2 голосов
/ 06 января 2011

Я действительно предпочитаю кастинг. Если вы вернете id из этих методов, компилятор вообще не предупредит вас, так как не может знать, что там будет возвращено. Если вы приведете возвращаемое значение правильно (а не приведете к id), то вы можете быть уверены, что сделали все правильно, если не получите предупреждение. Все, что нужно, это написать еще одно имя класса.

BCCustomTableViewCell *cell = (BCCustomTableViewCell *)[tableView dequeue...];

Смысл не возврата id заключается в том, что вы не возвращаете ничего, кроме данного класса и его подклассов. Из этого примера метода вы всегда получаете ячейку табличного представления, на которую вы можете положиться, реагируя на определенные методы (если, конечно, вы не испортили свой подкласс). Если вы вернете id, вы не сможете рассчитывать ни на что, плюс компилятор не предупредит вас.

Изменить: Я имею в виду только методы экземпляра, а не методы класса. Виллихам объясняет эту разницу.

1 голос
/ 06 января 2011

Приведение грязное, но метод return id более грязный, поскольку под ним может скрываться скрытая опасность, о которой компилятор не может вас предупредить.Выполнение приведения означает просто сказать компилятору: «Вы предупредили меня, теперь позвольте мне столкнуться с опасностью».

1 голос
/ 06 января 2011

Если тип возвращаемого значения id, то, конечно, определение метода менее полезно? Вы можете получить любой тип объекта, и не будет никакой проверки типов во время компиляции.

В конце, установка объекта подкласса просто вызывает предупреждение компилятора, что является предпочтительной ситуацией для потенциальной ошибки, вызванной опечаткой, или неправильным чтением документации по этому вопросу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...