Обсудить реализацию MVC на iPhone - PullRequest
8 голосов
/ 02 октября 2010

Я некоторое время использую паттерн MVC на разных платформах, таких как (swing, android, gwt ...) Сейчас я изучаю фреймворк для iPhone и очень удивлен реализацией MVC. Я задаю вопросы о взаимодействии вида и контроллера.

Прежде всего, так я представляю шаблон MVC:

  • Вид и контроллер взаимодействуют друг с другом через интерфейс (один для вида и другой для контроллера)

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

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

Дело в том, что на iPhone контроллеры (например, ViewController) непосредственно знают элементы пользовательского интерфейса, отсюда и мое непонимание. Моя цель - не критиковать рамки, которые я только изучаю. Но если это действительно работает, как я описал, я не нахожу это действительно чистым ...

Кто-нибудь еще экспериментировал с этой платформой, кто может дать мне детали / объяснения? Или, если вы не согласны с моим подходом MVC, скажите мне;)

Более того, я спрашиваю, не подходит ли мой подход к MVP (описано здесь: http://code.google.com/intl/fr/webtoolkit/articles/testing_methodologies_using_gwt.html), чем MVC.

Ответы [ 4 ]

12 голосов
/ 02 октября 2010

MVC означал разные вещи, так как он был впервые формализован в Smalltalk , и версия MVC NeXTSTEP (Какао) не совсем совпадает с версией Smalltalk. Распад Smalltalk в основном так:

  • Модель содержит данные
  • Представление представляет данные
  • Контроллер управляет взаимодействием с пользователем

Распад NeXTSTEP на практике выглядит примерно так:

  • Модель содержит данные
  • Вид рисует данные
  • Контроллер управляет «логикой» (включая часть «представления» данных чертежа)

Здесь я делаю различие между рисованием и представлением в том смысле, что NSView, как правило, не понимает «смысла» данных. Он просто фокусируется на рисовании пикселей. Таким образом, вы склонны передавать ему реальные строки, а не объект, который представление разрывает на части и «представляет».

Это не огромная разница, но это причина того, с чем вы сталкиваетесь. Основной сдвиг IMO заключается в том, что с Cocoa / NeXTSTEP классы представлений становятся все более и более повторно используемыми. Становясь настолько многократно используемым, больше частей, чувствительных к применению, необходимо было перенести в контроллер. Я полагаю, что это, как правило, является преимуществом, поскольку приводит к меньшему количеству подклассов, более понятному коду и более повторно используемому коду ... в большинстве случаев. В частности, он позволяет вам легче менять представления, которые делают более изобразительное представление (представление, которое анимирует конкретный способ или чередует цвета в строках и т. П.), Не сталкиваясь с какой-либо логикой для конкретного приложения, которая обычно существует в контроллерах. *

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

РЕДАКТИРОВАТЬ: еще одна вещь, чтобы отметить. Пример кода Apple часто ужасен с точки зрения дизайна. Они почти никогда не включают в себя классы моделей и втискивают почти все мыслимые в ViewControllers и, что еще хуже, в AppController (который, на мой взгляд, должен быть очень простым объектом). Обычно это происходит из-за того, что их пример кода пытается продемонстрировать какую-то конкретную точку зрения, и они не хотят включать сложность разбивки (или автор ленится; выбирайте сами). Поэтому, хотя я считаю, что интеллектуальные контроллеры представлений часто работают хорошо, вы не должны воспринимать пример кода как демонстрацию этого. К сожалению, существует не так много канонических примеров хорошего дизайна Какао на уровне приложений, поскольку большинство приложений Какао имеют закрытый исходный код. Один хороший пример для изучения - Adium . Это отличный пример большого, хорошо разработанного приложения Cocoa для нескольких разработчиков.

3 голосов
/ 03 октября 2010

iPhone ViewController предназначен для управления коллекцией представлений, которые объединяются в единый интерфейс. Например, контроллер представления может управлять представлением прокрутки с дюжиной представлений метки, представлением переключателя и двумя представлениями кнопки. Каждый элемент, производный от UIView, обрабатывает экранный чертеж определенного элемента - кнопки, слоя прокрутки, метки - с View Controller, направляющим, куда и куда помещаются данные. Итак, класс, производный от UIViewController, фокусируется на представлении (больше View в смысле MVC) путем маршалинга данных в нужные объекты UIView (например, Controller). Я думаю, что ViewController является подходящим термином для него.

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

UIViewController может и часто имеет делегат (а иногда и источник данных ), который он использует для запроса, какие данные принадлежат представлениям, и для фильтрации пользовательского ввода. На мой взгляд, это делает делегатов ближе к контроллерам MVC, потому что они являются классами, которые управляют всеми моделями и включают любую прикладную (бизнес) логику. AppDelegate является основным, отвечающим за управление общим состоянием приложения. AppDelegate может отслеживать все данные или может раздавать части данных другим делегатам. Я ожидаю, что в приложении Facebook будет один делегат для управления всеми событиями, другой для сообщений на стене и третий для фотографий, каждый из которых будет отчитываться перед AppDelegate для связи с серверами Facebook.

Когда я пишу свои приложения, я склонен использовать CoreData для модели MVC, делегаты для контроллеров MVC и оставлять представления MVC для контроллеров UIViewControllers, которым поручено бороться со стадами UIViews.

2 голосов
/ 02 октября 2010

Это не контроллер, это контроллер представления. Это либо явное в имени класса (UIViewController, UITableViewController), либо неявное (UITabBarController, поскольку UITabBar - это представление; UINavigationController, поскольку навигация - это парадигма, а UINavigationController имеет очень тонкий представление). 1003 *

Единственный неконтролируемый «Контроллер», о котором я могу думать, это NSFetchedResultsContoller.

Но почему странный дизайн?

Частично это связано с парадигмой пользовательского интерфейса iPhone: пользователи взаимодействуют с экранами одновременно. Если «экран» не виден, то большая часть его памяти может быть восстановлена. Контроллеры UIViewControllers представляют собой экран и управляют взаимодействием экранов с другими экранами.

(Конечно, Apple немного расширила это на iPad для реализации всплывающих окон / разделенных представлений, но эти два по-прежнему фактически являются «экранами» вместо общих представлений. Контроллеры представления в некоторой степени аналогичны окнам в настольной ОС, за исключением того, что большинство они не видны большую часть времени.)

Частично это связано с CoreAnimation: UIView обрабатывает рисование / макет и поддерживается CALayers. CALayers эффективно представляют текстурированные полики на GPU; «содержимое слоя» (то есть текстура) не может быть произвольно выгружено в свободную память. (Я не совсем уверен, почему, но это означает, что вы можете один раз установить для содержимого CGImage и оставить его в покое.) Поскольку многие свойства представления поддерживаются свойствами слоя (frame, bounds, center, contentStretch, .. ., немного глупо позволять представлению существовать без слоя. Конечный результат заключается в том, что представления имеют большой вес и иногда должны исчезать при нехватке памяти, поэтому контроллеру представления необходимо отслеживать вещи, которые должны сохраняться при выгрузке / перезагрузке представления (позиция прокрутки, выбранный в данный момент элемент, ...). Да, он может попросить представление сериализовать себя, но сериализация icky и большинство вещей не нуждается в сериализации.

Частично это связано с ленью: вам нужно реализовать контроллер представления, чтобы справиться с тем, как он взаимодействует с другими контроллерами представления. С другой стороны, представления выполняют автоматическое изменение размера & mdash; если вы счастливы установить макет в кончике или в -viewDidLoad, вам часто не нужно писать собственный вид. Лень требует, чтобы вы этого не делали, поэтому в контроллере представления часто выполняется макет.

Лично я реализую «умное» представление, когда оно кажется более логичным. Возьмем, к примеру, приложение «Погода»: когда загружается представление, вы должны отображать погоду в течение нескольких дней в каждой ячейке (которая может быть или не быть ячейкой табличного представления; это не имеет значения). Когда вы получаете обновление, вы должны обновить все ячейки. Вы могли бы реализовать - [WeatherViewController updateCell:], но, кажется, имеет больше смысла просто иметь - [WeatherCell setWeather:] и передать его вашей модели. В контроллере вида намного меньше беспорядка.

Я также виню лень и ремонтопригодность: иногда просто проще иметь все в одном файле, а иногда полудублированный код с небольшими специализациями проще, чем написание универсального представления, поддерживающего все его варианты использования. Это намного лучше, чем Enterprise Java, где принято иметь функцию, которая вызывает функцию, которая вызывает функцию, которая вызывает (единственную функцию, которая создается) -с фабрикой-с-некоторым-классом, который вам нужен для отслеживания) -призывает-функцию-то-вызывает-функцию, чтобы выяснить, что корпоративное программное обеспечение использует алгоритм хеширования пароля, который может быть выражен в 1 строке Python. (Я немного преувеличиваю.)

(Так что же произойдет, если вы решите, что общий макет погодной ячейки подходит, например, для отображения фазы / видимости луны? Переместите универсальный материал в суперкласс и сделайте AstronomerCell или что-то еще.)

Кроме того, если ваши представления не могут работать с фиктивным контроллером, вы делаете это неправильно.Представления не должны знать об их контроллере представления;контроллер представления должен зарегистрировать себя как цель действия (addAction: target: forControlEvents :, я думаю) или соответствующий делегат.Никто из них не ожидает, что целью будет контроллер представления.

1 голос
/ 03 октября 2010

Это всего лишь предположение. Но я предполагаю, что одна из причин, по которой View и Controller оказываются более тесно связанными в реализациях Mac / iPhone, заключается в том, что если вы слишком сильно отсоедините элемент управления взаимодействием и презентацию, вероятность того, что у вас возникнет уродливое и менее интуитивное чувство Интерфейс увеличивается. Принимая во внимание, что более тесная связь побуждает разработчика к тому, чтобы контроль модели более точно соответствовал тонким различиям в поведении пользователей, учитывая их воспринимаемый ответ на представление представления. В итоге вы получаете более оптимальный для UI, но менее переносимый код. Требуются оценочные суждения.

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