Цель-C: блоки против селекторов против протоколов - PullRequest
51 голосов
/ 03 августа 2010

Я часто пишу «служебные» классы, которые можно повторно использовать в моих проектах.

Например, предположим, у меня есть представление «Адресная книга».Возможно, я захочу использовать свою адресную книгу, чтобы выбрать, кому будет отправлено электронное письмо, или, возможно, кто будет добавлен в приглашение на собрание.

Я бы разработал этот контроллер представления, чтобы он мог использоваться как контроллером электронной почты, так и контроллером собраний, с своего рода механизмом обратного вызова, чтобы звонящий знал, что пользователь либо выбрал кого-то из адресной книгиили они отменены.

Похоже, что в этом сценарии можно использовать четыре (разумных) подхода;

  • Создайте протокол "AddressBookDelegate" и соответствующее свойство делегата в AddressBookController.Затем используйте сообщения, определенные в протоколе, для передачи результата (аналогично UIActionSheetDelegate).

  • Создайте "неформальный" протокол "AddressBookDelegate" и соответствующее свойство делегата в AddressBookController, нотипом свойства делегата будет «id», и он будет проверять во время выполнения с помощью «respdsToSelector:», чтобы увидеть, реализует ли делегат методы, которые нам нужны (кажется, что большинство компонентов фреймворка начали идти по этому пути).

  • Передайте AddressBookController идентификатор, представляющий делегата, а также два SEL, которые указывают методы для вызова, когда пользователь выбирает пользователя или отменяет запрос.Преимущество, которое я вижу с этим, является;предположим, что один контроллер поддерживает ОБА отправку электронных писем и организацию собраний (я знаю, что в этом примере это выглядит как плохой дизайн ... но можно представить более общую ситуацию, когда это может показаться совершенно разумным для служебного класса) - в этом случае вы могли быпередать адресному элементу AddressBookController SEL в зависимости от того, добавляете ли вы пользователей в электронное письмо или добавляете пользователей на собрание ... огромное улучшение по сравнению с iVar для указания «состояния» контроллера.

  • передать AddressBookController двумя блоками;один для запуска, когда пользователь выбирает кого-либо из адресной книги, и один для запуска, если пользователь отменяет запрос.

Блоки были так чрезвычайно полезны для меня, и ТАК гораздо элегантнее, что я почти растерялся, когда их НЕ использовать.

Я надеюсь, что более опытные члены сообщества StackOverflow, чем я могу помочь с их мыслями по этой теме.

Ответы [ 2 ]

27 голосов
/ 03 августа 2010

«Традиционный» способ сделать это - с помощью протокола. Неофициальные использовались до того, как @protocol был добавлен к языку, но это было до моего времени и, по крайней мере, в последние несколько лет не приветствовались неофициальные протоколы, особенно с учетом спецификатора @optional. Что касается «делегата», который проходит два SEL, то это выглядит просто уродливее, чем объявление формального протокола, и, как правило, мне не кажется правильным. Блоки очень новые (особенно на iOS), и в то же время, пока мы еще не увидели огромный объем документации / блогов о наилучшем испытанном и истинном стиле, мне нравится идея, и это, кажется, одно из блоки вещей лучше всего подходят для: аккуратных новых структур потока управления.

По сути, я пытаюсь сказать, что каждый из этих методов различается по возрасту, и ни один из них не лучше, чем последний, за исключением стиля, который, очевидно, имеет огромное значение, и в конечном итоге именно поэтому был создан каждый из этих элементов. , По сути, воспользуйтесь новейшей вещью, которая вас устраивает, которая должна быть либо блоками, либо формальным протоколом, и что ваша путаница, скорее всего, связана с чтением противоречивых источников, поскольку они были написаны в разное время, но с точки зрения времени это ясно видно, что вытесняет другие.

[Controller askForSelection:^(id selection){
  //blah blah blah
} canceled:^{
  //blah blah blah
}];

, вероятно, чертовски лаконичнее, чем определение двух дополнительных методов и протокола для них (формально или иным образом) или передача SEL и сохранение их в ivars и т. Д.

17 голосов
/ 03 августа 2010

Я бы просто пошел с твоим первым подходом.Это проверенный и верный шаблон в Какао, и, кажется, он очень хорошо вписывается в то, что вы делаете.

Несколько комментариев о других подходах:

  1. Неформальный протокол - Я не вижу никакого преимущества в этом по сравнению с формальным протоколом.С тех пор как формальные протоколы получили @optional методов, полезность неформальных протоколов намного меньше.
  2. Передача SEL - я не думаю, что это установленный шаблон в Какао.Лично я не считаю это лучше, чем делегатский подход, но если он лучше подходит для вашего мышления, тогда сделайте это.Вы на самом деле не избавляетесь от государства;ты просто превращаешься во что-то другое.Лично я предпочел бы иметь ивар, который я могу устанавливать и проверять, не используя типы селекторов.
  3. Передача блоков - Это своего рода подход нового века, и онимеет некоторые достоинства.Я думаю, что вы должны быть осторожны, потому что, на мой взгляд, это не очень хорошо масштабируется.Например, если бы все методы делегата и источника данных в NSTableView были блоками, я бы лично счел это несколько раздражающим.Представьте, что если вы хотите установить 10 различных блоков, ваш метод -awakeFromNib (или любой другой) будет довольно большим.Индивидуальные методы кажутся более подходящими в этом случае.Однако, если вы уверены, что никогда не собираетесь выходить за рамки, скажем, двух методов, тогда блочный подход представляется более разумным.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...