Цель C: блоки против селекторов против протоколов


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

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

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

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

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

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

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

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

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

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

2   51   2010-08-03 05:38:45

2 ответа:

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

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

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

вероятно, это намного более лаконично, чем определение двух дополнительных методов и протокола для них (формально или иначе) или передача SELs и хранение их в ivars и т. д.

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

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

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