Objectif C: Blocs vs sélecteurs vs protocoles

Je me trouve souvent en train d’écrire des cours “utilitaires” qui peuvent être réutilisés tout au long de mes projets.

Par exemple, supposons que je dispose d’une vue “Carnet d’adresses”. Je souhaiterais peut-être utiliser mon carnet d’adresses pour sélectionner qui reçoit un courrier électronique, ou peut-être celui qui est ajouté à une demande de réunion.

Je développerais ce contrôleur de vue pour qu’il puisse être utilisé à la fois par le contrôleur de messagerie et le contrôleur de réunions, avec une sorte de mécanisme de rappel permettant à l’appelant de savoir que l’utilisateur a fini de sélectionner quelqu’un dans le carnet d’adresses.

Il semble qu’il y ait fondamentalement quatre approches (raisonnables) dans ce scénario;

  • Créez un protocole “AddressBookDelegate” et une propriété correspondante sur le AddressBookController. Utilisez ensuite les messages définis dans le protocole pour communiquer le résultat (similaire à UIActionSheetDelegate).

  • Créez un protocole “informel” “AddressBookDelegate” et une propriété correspondante sur le AddressBookController, mais le type de la propriété delegate sera “id” et vérifiera à l’exécution avec “respondsToSelector:” pour voir si le délégué implémente les méthodes que nous avons require (semble que la plupart des choses du framework ont ​​commencé de cette façon).

  • Transmettez le AddressBookController un identifiant qui représente un délégué, ainsi que deux SEL qui spécifient les méthodes à appeler lorsque l’utilisateur sélectionne un utilisateur ou annule la demande. L’avantage que je vois avec cela est; Supposons qu’un contrôleur prenne en charge l’envoi d’e-mails ET la création de réunions (je sais dans cet exemple que cela semble une mauvaise conception … mais on peut imaginer une situation plus générique où cela semblerait parfaitement raisonnable pour une classe d’utilitaires) Transmettez les différents SEL AddressBookController selon que vous ajoutez des utilisateurs à un e-mail ou que vous ajoutez des utilisateurs à une réunion … une amélioration considérable par rapport à un iVar pour indiquer “l’état” du contrôleur.

  • Passez le AddressBookController deux blocs; une à exécuter lorsque l’utilisateur sélectionne quelqu’un dans le carnet d’adresses et une à exécuter si l’utilisateur annule la demande.

Les blocs m’ont été tellement utiles et tellement plus élégants que je me retrouve presque confus quand je ne devrais pas les utiliser.

J’espère que les membres plus expérimentés de la communauté StackOverflow pourront vous aider avec leurs idées sur ce sujet.

La manière traditionnelle de le faire est d’utiliser un protocole. Les protocoles informels ont été utilisés avant que @protocol ne soit ajouté à la langue, mais c’était avant mon époque et au moins ces dernières années, les protocoles informels ont été déconseillés, surtout avec le spécificateur @optional. Quant à un «délégué» qui passe deux SEL, cela semble juste plus laid que de déclarer un protocole formel, et ne me semble généralement pas correct. Les blocs sont très récents (en particulier sur iOS), alors que nous n’avons pas encore vu le volume considérable de documentation / blogs sur le style le plus éprouvé et le plus vrai, j’aime bien l’idée, et cela semble être Les éléments les mieux adaptés sont les suivants: nouvelles structures de stream de contrôle.

Essentiellement, ce que je veux dire, c’est que l’âge de chacune de ces méthodes varie, aucune n’est meilleure que la dernière sauf pour le style, ce qui compte évidemment pour beaucoup, et c’est pourquoi chacune de ces choses a été créée. Fondamentalement, optez pour la chose la plus récente avec laquelle vous vous sentez à l’aise, à savoir des blocs ou un protocole formel, et que votre confusion provient probablement de la lecture de sources contradictoires, car elles ont été écrites à des moments différents. clair pour voir qui remplace les autres.

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

est probablement beaucoup plus concis que de définir deux méthodes supplémentaires et un protocole pour eux (formellement ou non) ou de passer les SEL et de les stocker dans des ivars, etc.

Je voudrais juste aller avec votre première approche. C’est un modèle éprouvé dans Cocoa, et semble très bien s’intégrer à ce que vous faites.

Quelques commentaires sur les autres approches:

  1. Protocole informel – Je ne vois aucun avantage à le faire avec un protocole formel. Chaque fois que les protocoles formels ont gagné des méthodes @optional , l’utilité des protocoles informels est bien moindre.
  2. Passer des SEL – Je ne pense pas que ce soit un modèle établi dans Cocoa. Personnellement, je ne le considérerais pas mieux que l’approche des delegates, mais si cela vous convient mieux, alors allez-y. Vous ne vous débarrassez pas vraiment de l’état; vous ne faites que transformer quelque chose. Personnellement, je préférerais avoir un ivar que je peux configurer et vérifier sans avoir à utiliser de types de sélecteurs.
  3. Blocs de passage – Il s’agit en quelque sorte d’une approche de la nouvelle génération, qui a du mérite. Je pense que vous devez faire attention car, à mon avis, cela ne va pas vraiment bien. Par exemple, si les méthodes de délégué et de source de données de NSTableView étaient toutes des blocs, je trouverais cela quelque peu ennuyeux. Imaginez que vous vouliez définir 10 blocs différents, votre -awakeFromNib (ou autre) serait assez grande. Les méthodes individuelles semblent plus appropriées dans ce cas. Cependant, si vous êtes certain de ne jamais aller au-delà, disons, de deux méthodes, l’approche par blocs semble plus raisonnable.