отклонение представленного контроллера представления

<p>у меня есть теоретический вопрос. сейчас я читаю apple <a href="https://developer.apple.com/reference/uikit/uiviewcontroller">viewcontroller</a> руководство.</p><p>они написали: </p><blockquote> <p>когда приходит время отклонить представленный контроллер представления, предпочтительный подход заключается в том, чтобы позволить представителю представления отклонить это. другими словами, когда это возможно, тот же контроллер представления, что представленный контроллер представления также должен взять на себя ответственность за отклоняя это. хотя есть несколько способов уведомления представление контроллера представления, что его представленный контроллер представления должен быть отклоненным, предпочтительный метод - делегирование.</p> </blockquote><p>но я не могу объяснить, почему я должен создать протокол в представленном vc и добавить переменную делегата, создать метод делегата в представлении vc для отклонения представленного vc вместо простого вызова в <strong>present</strong> просмотр метода контроллера </p><p><code>[self dismissviewcontrolleranimated:no completion:nil]</code>? </p><p>почему первый выбор лучше? почему apple рекомендует это?</p>

<p>я думаю, что apple немного прикрывает свои спины ради потенциально грязного api. </p><pre><code> [self dismissviewcontrolleranimated:no completion:nil] </code></pre><p>это на самом деле немного скрипки. хотя вы можете - законно - вызвать это на представленном контроллере представления, все, что он делает, это передает сообщение на представляющий контроллер представления. если вы хотите сделать что-то сверх того, что просто отмените vc, вам нужно это знать, и вам нужно относиться к этому почти так же, как к методу делегата - так как это почти то же, что и запутанный, несколько негибкий метод делегата. </p><p>возможно, они сталкивались с множеством плохого кода людьми, которые не совсем понимают, как все это сложить, и поэтому их осторожность. </p><p>но, конечно, если все, что вам нужно сделать, это отказаться от этой вещи, продолжайте.</p><p>мой собственный подход - это компромисс, по крайней мере, он напоминает мне, что происходит:</p><pre><code> [[self presentingviewcontroller] dismissviewcontrolleranimated:no completion:nil] </code></pre><p><em> [свифт] </em></p><pre><code> self.presentingviewcontroller?.dismiss(animated: false, completion:nil) </code></pre>

<p>это для многократного использования контроллера представления.</p><p>ваш контроллер представления не должен заботиться о том, будет ли он представлен как модальный, помещен в контроллер навигации или как-то еще. если ваш контроллер представления отклоняет сам себя, то вы предполагаете, что он представлен модально. вы не сможете перенести этот контроллер вида на контроллер навигации.</p><p>реализуя протокол, вы позволяете родительскому контроллеру представления решить, как он должен быть представлен/выдвинут и отклонен/вытолкнут.</p>

<p><em>обновлено для swift 3</em></p><p>я пришел сюда просто чтобы уволить текущий (представленный) view controller. я делаю этот ответ для тех, кто приезжает сюда с той же целью.</p><h1>навигационный контроллер</h1><p>если вы используете навигационный контроллер, то это довольно просто.</p><p><strong>вернитесь к предыдущему контроллеру представления:</strong></p><pre><code>// swift self.navigationcontroller?.popviewcontroller(animated: true) // objective-c [self.navigationcontroller popviewcontrolleranimated:yes]; </code></pre><p><strong>вернитесь к контроллеру корневого представления:</strong></p><pre><code>// swift self.navigationcontroller?.poptorootviewcontroller(animated: true) // objective-c [self.navigationcontroller poptorootviewcontrolleranimated:yes]; </code></pre><p>(спасибо <a href="https://stackoverflow.com/a/20120647/3681880">этот ответ</a> за objective-c.)</p><h1>контроллер модального вида</h1><p>когда view controller представлен модально, вы можете удалить его (из второго контроллера view), вызвав</p><pre><code>// swift self.dismiss(animated: true, completion: nil) // objective-c [self dismissviewcontrolleranimated:yes completion:nil]; </code></pre><p> <a href="https://developer.apple.com/library/ios/documentation/uikit/reference/uiviewcontroller\_class/#//apple\_ref/occ/instm/uiviewcontroller/dismissviewcontrolleranimated:completion:">документация</a> говорит,</p><blockquote> <p>контроллер представления представления ответственен за отклонение представления контроллер это представил. если вы вызываете этот метод в представленном представлении сам контроллер, uikit просит текущий контроллер представления обработать увольнение.</p> </blockquote><p>таким образом, это работает для представленного контроллера представления, чтобы вызвать его на себя. <a href="https://stackoverflow.com/a/37274189/3681880">здесь</a> является полным примером.</p><h1>делегаты</h1><p>вопрос оп касался сложности использования делегатов для отклонения представления. </p><ul> <li> <a href="https://stackoverflow.com/a/14910469/3681880">этот ответ objective-c</a> входит в него совсем немного. </li> <li> <a href="https://stackoverflow.com/a/27435406/3681880">здесь</a> это пример swift.</li> </ul><p>до этого момента мне не нужно было использовать делегатов, так как у меня обычно есть контроллер навигации или контроллеры модального представления, но если мне действительно понадобится <a href="https://stackoverflow.com/questions/24099230/delegates-in-swift/33549729#33549729">шаблон делегата</a> в будущем, я добавлю обновление.</p>

<p>по моему опыту, это удобно, когда вам нужно удалить его из<strong> <em>любого</em> </strong>viewcontroller, который вы хотите, и выполнить различные задачи для каждого viewcontroller, который его отклоняет. любой viewcontroller, который принимает протокол, может отклонить представление по-своему. (ipad против iphone или передача разных данных при отклонении из разных представлений, вызов разных методов при отклонении и т. д.)</p><p>правка:</p><p>итак, чтобы уточнить, если все, что вы когда-либо захотите сделать, это отклонить представление, я не вижу необходимости настраивать протокол делегирования. если вам нужно делать разные вещи<strong> <em>после</em> </strong>вы исключаете это из разных контроллеров представления представления, это был бы ваш лучший способ использовать делегат.</p>

<p>попробуй это:</p><pre><code>[self dismissviewcontrolleranimated:true completion:nil]; </code></pre>

<p>один момент заключается в том, что это хороший подход к кодированию. он удовлетворяет многим принципам <code>oop</code>, например, srp, разделение интересов и т.д. </p><p>таким образом, контроллер представления, представляющий представление, должен быть тем, кто его отклоняет. </p><p>например, риэлторская компания, которая сдает дом в аренду, должна иметь право забрать его обратно.</p>

<p><strong> swift 3.0 </strong> // отключить контроллер представления в swift </p><pre><code>self.navigationcontroller?.popviewcontroller(animated: true) dismiss(animated: true, completion: nil) </code></pre>

<p>цитата из view <a href="https://developer.apple.com/library/ios/featuredarticles/viewcontrollerpgforiphoneos/modalviewcontrollers/modalviewcontrollers.html">руководство по программированию контроллеров</a> , "как контроллеры представления представляют другие контроллеры представления".</p><blockquote> <p>каждый контроллер представления в цепочке представленных контроллеров представления имеет указатели на другие объекты, окружающие его в цепочке. в других слова, представленный контроллер представления, который представляет другой вид контроллер имеет действительные объекты как в представлении viewcontroller, так и в представленные свойства viewcontroller. вы можете использовать эти отношения для проследить через цепочку контроллеров представления по мере необходимости. <strong>например, если пользователь отменяет текущую операцию, вы можете удалить все объекты в цепочка путем отклонения первого представленного контроллера представления . отклонение контроллера представления отклоняет не только тот контроллер представления но также любые контроллеры представления это представило.</strong></p> </blockquote><p>так что, с одной стороны, это обеспечивает хороший сбалансированный дизайн, хорошее расцепление и т.д. но с другой стороны, это очень практично, потому что вы можете быстро вернуться к определенной точке навигации. </p><p>хотя я лично предпочел бы использовать <em>разматывание сегментов</em>, чем пытаться пройти назад по дереву <em>представление контроллеров представления</em>, о чем apple говорит в этой главе, откуда взята цитата. </p>

<p>в дополнение к ответу майкла энрикеса, я могу вспомнить еще одну причину, по которой это может быть хорошим способом защитить себя от неопределенного состояния:</p><p>скажем, viewcontrollera представляет viewcontrollerb модально. но, поскольку вы, возможно, не написали код для viewcontrollera, вы не знаете о жизненном цикле viewcontrollera. это может отклонить 5 секунд (скажем) после представления вашего контроллера представления, viewcontrollerb.</p><p>в этом случае, если бы вы просто использовали <code>dismissviewcontroller</code> из viewcontrollerb, чтобы закрыть себя, вы бы оказались в неопределенном состоянии - возможно, не сбоем или черным экраном, а неопределенным состоянием с вашей точки зрения.</p><p>если бы вместо этого вы использовали шаблон делегата, вы были бы осведомлены о состоянии viewcontrollerb, и вы можете программировать для случая, подобного описанному мной.</p>

<p>стриж</p><pre><code>let rootviewcontroller:uiviewcontroller = (uiapplication.shared.keywindow?.rootviewcontroller)! if (rootviewcontroller.presentedviewcontroller != nil) { rootviewcontroller.dismiss(animated: true, completion: { //completion block. }) } </code></pre>

<p>если вы используете модальное использование, используйте view dismiss.</p><pre><code>[self dismissviewcontrolleranimated:no completion:nil]; </code></pre>

<p>вы можете закрыть окно супер просмотра</p><p><code>self.view.superview?.window?.close()</code></p>

<p>это много глупостей. делегирование хорошо, когда это необходимо, но если это делает код более сложным - и это делает - тогда должна быть причина для этого.</p><p>я уверен, что у apple есть свои причины. но более ясно и более кратко просто заставить представленного vc выполнить отставку, если только нет веской причины поступить иначе, и никто здесь на сегодняшний день не представил такую, которую я вижу. </p><p>протоколы превосходны, когда они необходимы, но объектно-ориентированное проектирование никогда не сводилось к тому, чтобы модули без необходимости общались друг с другом. </p><p>том лав (соавтор objective c) однажды заметил, что objective c был «элегантным», «маленьким», «четким» и «четким» (при сравнении с c++). легко ему сказать. делегирование - это полезная функция, которая, кажется, использовалась слишком часто «просто потому, что», и хотя мне нравится работать на языке, я боюсь, что вынужден использовать ненужный синтаксис, чтобы сделать вещи более сложными, чем они должны быть.</p>