10 сентября 2010 в 10:55

Кроссплатформенный код для приложений под iPhone и iPad

Учимся парадигме Model-View-Presenter и выкидываем в AppStore кучу вкусностей для iPhone и iPad сразу

Как наиболее оптимальным образом портировать приложение, написанное под iPhone для iPad, можите решить только вы сами. Могу лишь предложить несколько рецептов, которые будут удобны в использовании на данном конкретном примере Web-приложений.

Далее будет предложена парадигма организации кода, рассмотрены компоненты, доступные в SDK 3.2. А паттерны проектирования вы изучите сами :-)

Начинается все с дизайна. Как правило, несколько экранов iPhone пытаются уложить на одном экране iPad.
image

При написании пользовательских интерфейсов для программ под платформу iOS используется парадигма Model-View-Controller. При этом она достаточно неудобна при портировании и поддержки приложений под iPhone и iPad. О ней вы можете узнать в Википедии.

image

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

Взамен я предлагаю использовать, активно продвигаемую на платформе .Net парадигму, представленную впервые компанией Microsoft. Она произошла из предыдущей путем замены Controller на Presenter, который все взаимодействие модели и представления берет на себя, разрывая связь представления с моделью. В итоге модель становится более универсальной и уменьшается код Controller.
image

Как сократить объем написанного кода и, соответственно, уменьшить число ошибок под iOS
Следует начать проект со стратегии организации кода. В приведенных ниже примерах используются настройки проекта и создание представления кнопки btContinue в коде. Эти представления для iPhone и iPad различаются. Когда мы компилируем два приложения под оба устройства изменения должны контролироваться макросами, которые изменяют поведение на этапе компиляции. Изменения компилируются и жестко прошиваются в приложение. Используем #define IPAD. Получаем два приложения: одно для iPhone, другое для iPad
image

Изменения контролируются во время выполнения приложения. Используем UIDevice. Получаем одно приложение: которое запускается и под iPhone и под iPad
image

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

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

Из личного опыта
Люди очень активно пользуются юридическим софтом. Например, проект «Картотека» (картотека арбитражных дел) в AppStore набирает более 100 скачиваний в день
image

При написании картотеки арбитражных дел нельзя было использовать стандартные компоненты, доступные в SDK 3.2, такие как UISplitViewController и UIPopoverController. Например, первый не поддерживает работу UINavigationController и должен быть главным экраном. У второго компонента отсутствует обратная совместимость с iPhone. Выход: писать свои компоненты. Кстати сторонние разработчики уже делали свои варианты. Об этом есть, например, статья на Хабре

При желание можно больше и еще больше и гораздо больше поместить на экране iPad информации, заимствованной с экранов iPhone. В проекте картотека присутствовала обратная совместимость, то есть для удобства использования перехода от дела к инстанциям дела использовался выпадающий список UIPopoverController, который по непонятным причинам имеет запрет на использование на iPhone, причем выясняется это на этапе исполнения кода. Выход: ПИШИТЕ СВОИ КОМПОНЕНТЫ.

Немного практики
Обычно на практике представление формируется прямо в Presenter.
В парадигме Apple экраны (представления) должны храниться в ресурсах, но это очень неудобно. Нужно постоянно поддерживать связи с Controller, не говоря уже о модели. Было принято решение, что формировать представление прямо в Presenter будет наиболее эффективно. При этом код самого презентора увеличивать совсем не обязательно, даже напротив — его можно выделять в классы и даже подклассы, как показано в данном примере для элемента списка.
image

Необходимо помнить о том что мы имеем дело со слабым аппаратным обеспечением, для которого процессорное время и тем более память становятся очень критичными ресурсами. Соответственно, бывают ситуации в которых хранение представления в ресурсах оправданно. Тем более, что именно для данного примера кода это совершенно оправданно, т.к. лишних связей и обслуживающего эти связи кода просто нет. Все-таки в xib (nib) можно хранить UIView, например такой как UITableViewCell:
image

Но это совершенно не означает, что для разных реализаций iPhone/iPad этот ресурс xib (nib) не может быть единым!
Люди часто боятся нового. Они не хотят реанимировать макросы и давать им новую жизнь даже там, где они становятся актуальными. Дело в том, что мы их просто не умеем готовить. Это не только полезная снедь, как овсянка, но и очень вкусная, если ее приправить бабушкиным варением, например. Обратите внимание на два примера объявления полей одного интерфейса (класса). В последнем, кстати говоря, исправлена ошибка первого. Но какой эффект: не нужно переправлять там где что то забыл подобное и компактность, а самое главное понятность кода!

Неизбежное использование макросов (отвратительно!)
image

Желательное использование макросов (так-то лучше!)
image

Итоги
Во-первых, нужно определить настройки проекта(ов) для определения представления (View) на этапе компиляции или выполнения. Затем необходимо избавиться от связей Model-View путем переноса логики их взаимодействия в Presenter.
Максимально эффективно отвязываемся от представлений, формируемых посредством xib, оставляя в них только атомарные полотна (например, такие как UIViewTableCell).
Потом определяем макросы, ограничивающие представление под устройство iPhone/iPad. И не забудьте, что Objective-C является «Message Oriented Program» языком (пишем свою VCL).
Автор: @glazkova
Pravo.ru
рейтинг 71,83
Похожие публикации

Комментарии (105)

  • +12
    Даже не будучи разработчиком iOS-приложений, считаю очевидным, что тактика if(device == 'iPhone') (или ifdef, не важно) — это полное говно, запутывающее и утяжеляющее код.
    • –4
      а что вы предлагаете? У вас наверное особая тактика?
      • +9
        Я согласен с Ueasley

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

        Когда приложение запускается, оно в зависимости от девайса создает экземпляр нужного класса.

        Как-то так.
        • –1
          Вы предлагаете использовать паттерн Adapter, есть еще куча паттернов, которые помогают объектную модель сделать проще и отказавшись от линейной модели программирования сделать код более понятной. В статье кстати написано, кстати, что вы их сами изучите, и соответственно сами будете их использовать. Здесь уклон в другую сторону: в сторону быстродействия (НУ ОЧЕНЬ КРИТИЧНО) и минимизации кода. Представте что вы своим насследованием потяните кучу изменений классов. В Картотеке например присутствует 6-уровневое наследование виджетов, что каждую ветвь перенаследовать? Кстати паттерны учат нас избегать наследования в пользу композиции, это так — к слову.
          • +1
            Не смешно.

            Это не обработка изображений или звука, а простое GUI приложение.

            > Представте что вы своим насследованием потяните кучу изменений классов
            Когда у вас ifdef-ов будет более 100 — расскажете как вам весело. Это из практики.

            • 0
              ну что вам так не нравятся ifdef, сравните количество символов ifdef и количество строк новых классов, мне кажется числа будут сопостовимы, это вам не JAVA а Objective-C. Язык на котором писалась NEXT Step, помните в 80-х как там все в 3D крутилось? Технологиие обогнавшие десятилетия. Думаете не было тогда макросов? Кстати сейчас картотеку портируют под Android и есть проблемы с памятью… нет, это конечно же не из-за того что там нет макросов
              • 0
                Вы когда нибудь искали ошибку, которая находится в кода макроса? :-)
                • 0
                  практика поиска ошибок с макрасами элементарная — во первых умные IDE затеняют ветви препроцесоров, которые не будут исполнятся, во вторых есть дебагер, который пошагово проходит нужные строки.

                  Я просто сталкивался с С/С++ многоплатформенными библиотеками такими как OpenCV, BOOST и не боюсь макросов, и вам рекомендую не переживать, они бывают неизбежны и очень полезны.
                  • –1
                    Макросы это неизбежное зло. Но это зло! Поэтому там где это возможно их стоит избегать. Ну и конечно макросы вида #iphone, #ipad и т.д. вообще только гвозди вбивают в гроб. Какая тут кроссплатформенность? Появится еще устройство и опять все макросы перебивать? Лучше уж тогда #handset_ui #mobile_ui #desktop_ui и т.д.
                    • 0
                      обоснуйте, это может оказаться забавным :-)

                      Был спор по GOTO, зло ли это? Нужно ли его использовать? Кароче спор никто не выйграл, но языки программирования начали от него избавлятся. Типо чтобы народ не шубуршил и фигней не страдал с обсуждениями. :-)

                      Как вы думаете насчет перспектив макросов?
                      • 0
                        Они были нужны на заре эволюции языков программирования. Сейчас многое изменилось, и макросы можно и нужно избегать.
                        • 0
                          еще раз повторюсь — это неизбежно, и актуально для продуктов с требованиями к ресурсам. Радуйтесь что вам не предлагают на асемблере писать как альтернативу
                      • 0
                        Макросы выкинуты почти из всех современных языков, а если они и есть, то куда более мощные и безопасные, чем примитивный макроязык Си.
                        • 0
                          Это Java современный? а дотнет?
                          • 0
                            И где там макросы? А в дотнетовских языках, в каком-то из них был свой макроязык, но не такой убогий, как в Си.
                            Макросы вообще костыль в принципе
                            • 0
                              в C# точно есть макросы, в Java нет, потому что это чистый ООП. У меня другое виденье макросов, мне кажется это не костыль а хадулька, благодаря которой можно быть ваше и ходить быстрее, уж последнее вы не будуту отрицать?

                              Кстати думаю могу привести пример кода, изрезанного макросами, которой в объектной модели даст жуткий полиморвизм, который будет очень тяжело поддерживать с учетом виртуализации Obj-C
                              • 0
                                Костыль это прямо по определению этого термина. А всё от того, что проблема решается не средствами самого языка, а не пойми каким образом. Фактически мы имеем второй язык поверх со своим собственным синтаксисом.
                                • НЛО прилетело и опубликовало эту надпись здесь
                      • +1
                        Ха, зато народ теперь другую ерунду придумал
                        do
                        {
                        //…
                        if (cond) break;
                        //…
                        }
                        while (false);

                        • 0
                          и ей я пользуюсь и return вместо break я пользуюсь, что в этом плохого? Если оно есть, значит гдето его можно использовать. Вы писали когда нибудь на ассамблере?
                          • –3
                            Плохого? Это идет в рознь с принципами структурного программирования. На ассемблере писал (i386), но слава Богу не в продакшн:)
                    • +1
                      Зло-зло.

                      Задать константы макросами — да пожалуйста, но писать большой код — оч. плохо.
                      • +2
                        Константы макросами? Ну уж увольте, а потом будут косяки при сложении двух таких констант.
                        static const int удобнее и лучше компилятором проверяется.
                        • 0
                          согласен, константы есть константы)
                        • 0
                          Заголовочные файлы windows видели?
                          • 0
                            Видел, долго плевался
                            • НЛО прилетело и опубликовало эту надпись здесь
                              • 0
                                Которого из них? И что? На Си без макросов таки уже не обойтись — средства языка весьма ограниченные. Но зачем же их тащить в те языки, в которых можно обойтись в большинстве своем без них?
                                • НЛО прилетело и опубликовало эту надпись здесь
                            • 0
                              Тогда напишите им и скажите, мол так делать нельзя :-)
                              • 0
                                Делать мне будто нечего, я просто не пользуюсь подобными вещами :) Особенно, на мой взгляд, отжигает MFC, это вообще лютый полярный зверь, а не фреймворк.
                  • +2
                    Вы поройтесь в коде того же STL, Boost' и быстро поймете, какой это ад постоянно поддерживать гору кода с огромными кол-вом ifdef и прочих кривостей. Написать один раз и забыть — ОК, но если это Long Term Support — другое дело.
                    • –4
                      STL, Boost' это С++, это дырявый ООП в котором куда страшнее не макросы, а template.

                      Однако согласен частично, но это не означает что ifdef надо полностью избегать, иногда они даже упрощают логику и понимание программы. Полиморфизм на ваш взгляд чем проще? Виртуализация чем по вашему упрощает в месадж-ориентированных языках жизнь команды разработчиков?
                      • 0
                        Ориентированностью IDE и других средств разработки на ООП: легче и навигация, и рефакторинг. Плюс это банально легче поддерживать, с точки зрения расширения функциональности или кол-ва поддерживаемых платформ, как в нашем случае.
                        • 0
                          а что у вас за случай?
                      • +3
                        > STL, Boost' это С++, это дырявый ООП в котором куда страшнее не макросы, а template.

                        «Если вы такие умные, то почему строевым шагом не ходите?»

                        Как-то так… Грустно…
                    • 0
                      DaemonI — плюсанул
              • 0
                > ну что вам так не нравятся ifdef, сравните количество символов ifdef и количество строк новых классов

                C классами порядка больше.

                > Кстати сейчас картотеку портируют под Android и есть проблемы с памятью…
                * Создавать объекты по мере необходимости
                * Обращаться за нужной порцией данных в БД (Apple такое решение для афйоном сама советовала)
                • 0
                  Web-сервис выплевывает json громадный, его разумеется вместо того чтобы держать в памяти парсят в sqlLite и потом как вы пишете — все верно, но этож както черезчур много делать. Много операций.
                  • 0
                    core data?
                  • 0
                    Прооцессор — трудолюбивый дурак, ему пофигу. Нет там столько работы, чтобы её боятся.
                  • 0
                    Во-во. И все етксты статей, тоже в БД и получаются только по мере необходимости.
      • 0
        Вы же сами предложили использовать MVP и MVC. Для каждой платформы — свой V.
        • 0
          это концептуально, а на практике связи M и С мешают и сответственно их тоже приходится переписывать
          • 0
            Есть такое.
            Для каждой платформы свой View, часто бывает что и свой Controller.
            Но если приходится переписывать Model — значит у вас плохо разделена логика и представление.
            • 0
              согласен, в MVP по сути предлагается контроллер как то так упрознить, чтобы его функцию связывания урезать, чтобы этот код связывания уменьшить и чтобы его не нужно было поддерживать-тестировать каждый раз
      • +1
        расскажу про свою собственную «особую» тактику.

        1) замечу, что почему-то многие программисты стремятся к сокращению объемов кода/уменьшению количества файлов. На первый взгляд, стремление здравое, но оно обычно порождает вот такие вот ifdef'ы и прочая.

        2) смысл моего подхода — максимально разорвать связи между стандартными компонентами и отделить логику работы программы от ее представления. Для этого я использую мааленькую библиотечку PureMVC (http://www.puremvc.org). Для нее имеется порт под Obj-C, но я предпочитаю свой собственный кастомный вариант.

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

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

        P.S.: на первый взгляд может показаться, что этот подход мало чем отличаеся от описанного в статье, но, поверьте, это немного не так. Смысл в том, что разрыв между сущностями происходит на более высоком уровне, чем предлагает стандартный подход конкретной платформы. Поэтому, после некоторой тренировки, его можно использовать единообразно на любой платформе — например, я использую эту библиотеку для написания программ на C++, Javascript, Actionscript, Obj-C. Дополнительный бонус — облегченное портирование между платформами.
        • 0
          Да, стремление сокращение кода есть: меньше кода — меньше ошибок.

          ну про C++ понятно, а как с другими языками то?
          Вот интересно на Obj-C вы под какие платформы пишите? Поделитесь опытом. Был ли опыт именно кросплатформеного написаниея и какие платформы?

          Javascript, Actionscript вообще непонятно, зачем это было необходимо? Кросбраузерность что ли какая?
          • 0
            тут понимаете в чем дело, очень часто стремление к «меньше кода» выливается в бурный рост этого самого кода начиная с какого-нибудь среднего этапа разработки, когда переделывать архитектуру уже поздно. Поэтому зачастую выгоднее выбрать такой подход, который дает «меньше кода» в среднесрочной перспективе, а не сиюминутно. А так, конечно, само понятие «меньше» — весьма субъективно :-)

            «javascript, actionscript & etc» — это способ портировать _логику_ работы программы, т.е. то, как там данные гуляют внутри программы и к каким изменениям состояний отдельных компонентов они приводят. Как пример, один наш проект, около 150к строчек исходных текстов пережил трансформацию С++ -> Actionscript -> C++. Первое портирование было весьма трудоемким и сложным, по-сути пришлось написать программу заново. Второе портирование было сделано за пару недель времени, благодаря тому, что в обоих случаях система строилась вокруг PureMVC. В придачу код «усох» раза в два, по сравнению с первоначальной версией, хотя чего-либо лишнего в исходной программе естественно не наблюдалось и вся архитектура в целом считалась удачной… Этот же проект сейчас портируется на Javascript.

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

            ObjC — iphone/ipad, под мак, увы не делал ничего.
            • 0
              я думаю информация тут изложенная очень полезна и для меня будет и пусть будет стыдно тому кто минусовал.
              • 0
                Я думаю, что вы чисто «академический» программист, или я не знаю, как это назвать. Я таких встречал: они шарят в матане, физике, еще чем-то, плюясь слюной сражаются за быстродействие, любят быстрые велосипеды. А еще они пишут говнокод.
                • +2
                  для Ueasley81 или Ueasley71 комментарий возможно и был бы уместен, а вот для Ueasley91 пока что рановато делать такие далеко идущие выводы на основании нескольких комментариев незнакомого человека…
                  • 0
                    Uealsey видел много людей и поработал во многих местах, так что он считает, что может высказывать свое мнение сколько и как хочет.
                    • 0
                      Ueasley, скорее всего, молод и глуп.
                      • +1
                        Забавно :-), но на самом деле Uealsey бессмертный троль, удивительно что администрация его не высечет по попе, поэтому лучше его не трогать.
                      • 0
                        Ueasley просто посмотрел сайт комментатора.
    • 0
      #if (TARGET_IPHONE_SIMULATOR)
      	MPMusicPlayerController *mpPlayer = nil; // Иначе очень сильно тупит, 
      						  // так как MPMusicPlayerController 
      						  // в симуляторе не реализован
      #else
      	MPMusicPlayerController *mpPlayer = [MPMusicPlayerController iPodMusicPlayer];
      #endif


      Какие ваши действия по исправлению кода?
      • +2
        а если через два месяца реализуют в симуляторе, то искать все места где он используется????

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

        Но это правильный путь, а если нужно просто забить гвоздь, чтоб одна строчка кода не мешала — то Ваш метод годится.
        • 0
          хорошее предложение, поскольку Proxy не сильно утежелит MPMusicPlayerController, я думаю. Но в местах, где быстродействие критично — определите свой макрос в проекте и пользуйтесь им. Кстати метод Krypt рекомендован Apple
        • 0
          В данном случае — единственная строка в инициализации приложения, реализация одной из дополнительных «фич»
        • +1
          А я бы написал например так (это вовсе не означает, что я критикую ваш метод, я наоборот за него):
          <code class="cpp"><span class="preprocessor">#if (MPMPC_NOT_SUPPORTED)</span>
          	MPMusicPlayerController *mpPlayer = nil; <span class="comment">// Иначе очень сильно тупит, </span>
          						  <span class="comment">// так как MPMusicPlayerController </span>
          						  <span class="comment">// в симуляторе не реализован</span>
          <span class="preprocessor">#else</span>
          	MPMusicPlayerController *mpPlayer = [MPMusicPlayerController iPodMusicPlayer];
          <span class="preprocessor">#endif</span></code>

          В таком случае при добавлении поддержки в симуляторе достаточно было бы изменить MPMPC_NOT_SUPPORTED на true (и это изменение не затронуло бы других мест, где идет проверка на симулятор)
  • +4
    Статья тяжеловато написана, особенно сломало мозг предложение
    Люди часто боятся нового, и устаревший механизм прекомпиляции кода (такой как макросы) не переваривают.

    Смахивает на некачественный перевод.

    По тому, что смог понять, ситуация, к которой приходишь с опытом разработки, описана довольно точно.
    • –1
      мне тоже мозг сломала эта фраза, давайте автора попросим исправить? Мне кажется автор имел в виду тот факт, что устаревшие макросы не хотят реанимировать и давать им НОВУЮ жизнь, даже там где они становятся актуальными
      • 0
        Уточнить, думаю, стоит. Правда, кажется, имелось в виду то, что макросы настолько устарели, что для кого-то они являются чем-то новым, все же речь идет про механизм а не конкретные макросы.
        Или у вас есть «мифический» оригинал? ;)
        • +2
          Да, я участвовал в конференции где на эту тему был доклад
          summer2010.etalks.ru/

          Немного рекламы: материал (в том числе и видеосъемку) можно преобрести тут
          www.stepinsoft.com/shop/etalks-summer-2010/
      • +1
        автор вас услышал:)
  • +2
    Статья человека, который первый раз столкнулся с кроссплатформенной разработкой. В данном случае нужно поддерживать одновременно две платформа — айфон и айпад (да железо одно, да ОС одна, но пратформы разные).

    По поводу макросов для каждой платформы, когда платформы 2 — это еще приемлемо. Когда 3 — это терпимо. Но если больше — это уже невыносимо. Таким образом использование макросов для разделения кода приводит к заведомому забиванию гвоздя в масштабируемость и расширяемость. Я согласен что этот метод применим, если горят сроки и четко ограничего количество платформ. Но если позволяет время, лучше сделать все правильно.

    Спавиться с кроссплатформенностью помогают паттерны, например фабрика и фабрика классов. Стратеги и визитер тоже часто помогают. Ну и естественно не брезговать стандартной в iOS моделью MVC. Так что рекомендую ознакоится с технологиями кросплатформенного программирования и не считать себя Колумбом в этой области.

    А если Вы захотите еще настольную MAC версию сделать ??? еще одна ветка ??? или заново все писать ???

    По поводу «пишите свои компоненты» могу долго и нудно спорить. Но дело ваши, грабли будут бить Вам по голове.
    • 0
      1. Вы все таки не согласны что макросы это правилно в данном контексте, когда критична память и процессор?

      2. Паттерны в статье предлагается открыть для себя самостоятельно, это значит что в данном контексте они не используются, у вас не возникает вопроса почему?

      3. «А если Вы захотите еще настольную MAC версию сделать ??? еще одна ветка ??? или заново все писать ???» Вот тут вы себе противоречите, как раз будет куча веток классов наследования, каждый композитор будет перенаследован, кроме того будет написано куча обслуживающего кода: адапторы, фабрики. Кроме того поедит производительность. Кроме того стоит учитывать тот факт что iPhone/iPad — почти идентичные платформы, следовательно код у них почти одинаков, меняется представление и чаще всего оно всего лишь расширяется для iPad. А под Mac используются совершенно другие компоненты и поведение, для него можно портировать только МОДЕЛЬ. Впринципе модель можно портировать под любую платформу.

      4. Свои компоненты чаще всего неизбежны за счет ограничений стандартных. Чего тут спорить? Ну никак нельзя UISplitViewController посадить на навигатор, что вы предложите в замен?
      • 0
        Вам жалко несколько килобайт памяти? Не на том вы экономите.
        • 0
          это вы к чему? А процессорное время мне тоже жалко. :-)
          • 0
            Хотите сказать, что много процессорного времени будет тратится? Да при использовании промежуточного класса в виде фабрики вместо этого спагетти с макросами почти не будет оверхеда.
            • –1
              я хочу сказать что там где платформы почти идентичны, код почти один, писать кучу классов для того чтобы блюсти все почести ООП не разумно, нужно пользоваться уметь не только ООП, но и макросами. goto кстати еще жив в objective-c :-)

              По соотношениям Количество кода/Ошибки, Время разработки/читаемость кода, Масштабиремость / Быстрота исполнения в конкретном продукте я посчитал макросы идеальным решением
              • 0
                Вот ничего они не почти идентичны. Вы размеры экрана смотрели, а предполагаемую модель управления приложением? Вот как раз в этом смысле айфон и айпад далеко не идентичные.
              • 0
                «goto кстати еще жив в objective-c „
                он жив только благодаря тому, что objective-c — это в первую очередь C.

                “По соотношениям Количество кода/Ошибки, Время разработки/читаемость кода, Масштабиремость / Быстрота исполнения в конкретном продукте я посчитал макросы идеальным решением»

                Странно, а я именно по этим критерям считаю его самым худшим решением. Так как поддержка кода, содержащего такой подход, — это просто ад.
                • –1
                  да, полная поддержка С.

                  Вы же не писали для Картотеки код, откуда вам знать что это для нее наихудшее решение?

                  Вы видимо предположили из своего опыта, очевидно негативного, а я пытался донести до вас свой позитивный опыт. Это рецепт, одного из блюд, которое может быть использовано совместно с другими.
                  • +1
                    «да, полная поддержка С.» Не совсем так. В objective-C нет поддержки С, это и есть С.

                    извините, в моем утверждение нужно выкинуть «в конкретном продукте», так как я не понял что Вы имеете ввиду эменно этот продукт.

              • 0
                Ничего, пройдут годы и прийдет опыт :-)
      • 0
        1. Макросы неизбежны. Но исользовать их для разделения кода платформ плохое решение. Практически идеальным примером кросс-платформенного кода является ядро Linux, там есть макросы, но посмотрите как они используются.

        2. Треть статьи описывает модификацию паттерна MVC. Почему бы не описать простые паттерны для написания кросс-платформенного кода, мне не понятно.
        Я не говорю что нужно тут описывать паттерны, наоботор. Просто нужно упомянуть хотя-бы названия (а лучше со ссылками) те паттерны, которые будут полезны.

        3.Нисколько не противоречю. Код и проект долежн быть один. Разделение платформ должно происходить за счет паттернов и архитектуры а не за счет ветвлений кода макросами. Иначе прийдется портировать кусками, как Вы и предложили, например портировать Модель. Но портировать код — это значит сделать отдельную ветку, и поддерживать теперь прийдется две модели, хоть вышли они из одной точки. Плюс появится еще один код.
        Мод Мак как раз испольузется тоже Cocoa. Они немного различаются, но это один фреймворк и один код. Просто для разных целевых платформ у него различное поведение заложеное как раз паттернами, а не ветвлениями макросов.

        4. Расширение стандартных компонент — это не написание собственных. Это расширение стандартных.
        • 0
          2. Хорошее предложение, на самом деле в Картотеке использовались паттерны и очень активно, но в разделении кода почти не было необходимости, то есть там где код отличался координально было удобнее разделить на подклассы, а если разница всего в две строки неохото было наследовать, и фабричными методами переопределять поведение, согласитесь?

          3. я бы сказал парадигма одна, контролы и суп из них отличаются. Суть в том что кода надо будет настолько больше переписывать, что я лично не вижу делать его единым. Но не об этом статья, и не будет под Mac Картотеки, уверяю вас. Статья про iOS.

          4. Вы уверены что UISplitViewController можно для этого расширить? Дело в том что ограничения стоят на уровне архитектуры. Я читал много статей о нем и все писали свои варианты, ни видел я даже попыток его расширить. Многие компоненты Apple не поддаются дресировки, именно потому что написаны на месадж-ореентированном языке, как это не звучит странно

          4.
          • 0
            2. Соглашаюсь, паттерны не панацея и все хорошо в меру.

            3. Статья как раз больше чем об iOS, статья о кроссплатформенности. А это тернистый путь :-)

            4. С UISplitViewController знаком вскольз. Ограничение я это видел. Оно мне кажется странным и я уверен что в будущем оно исчезнет. Именно поэтому Ваш подход написания собственного аналога — это workaround (или «гвоздь» по русски), чтоб обойти это ограничение. Его нельзя считать правильным подходом. Это не значит, что так делать нельзя. Более того я практически уверен, что Ваше решение обойти проблемму самое логичное и оптимальное. НО!!! я в корне не согласен с утверждением «ПИШИТЕ СВОИ КОМПОНЕНТЫ». Я уверен что нужно писать свои компоненты только в крайнем случае имея очень везкие аргументы, а лучше и факты R&D работы.
            • 0
              iOS пока включает в себя поддержку iPad и iPhone, так что о них пока речь.

              Вы победили, насчет компонентов. Мне тоже надоело их писать.
  • 0
    А зачем делать два приложения при помощи макросов, если можно сделать это при помощи обычных if-ов? Мне кажется так будет удобней всем, и автору приложения, и его пользователями.

    Model-View-Presenter, кстати впервые был замечен вовсе на в .NET: en.wikipedia.org/wiki/Model-view-presenter
    • 0
      разницы в написании кода практически нет, но вот в продукте конечном…

      макросы позволяют на этапе копиляции убрать ненужный код в конечном приложении, ну например объявили вы массив в iPad для класса и где небудь держите миллион экземпляров этого класса, оно надо iPhone?, память нужно экономить у мобилок

      Или метод вызывается в цикле миллион итераций, а в методе надо делать проверку? Насколько все замедлится?

      А где был замечен впервые MVP?
      • 0
        в википедии…

        The model-view-presenter software pattern originated in the early 1990s at Taligent, a joint venture of Apple, IBM, and HP, and was the underlying programming model for application development in Taligent's C++-based CommonPoint environment.
      • 0
        >макросы позволяют на этапе копиляции убрать ненужный код в конечном приложении, ну например объявили вы массив в iPad для класса и где небудь держите миллион экземпляров этого класса, оно надо iPhone?, память нужно экономить у мобилок
        Это в теории. На практике, у всех девайсов на iOS достаточно много памяти, чтобы плевать на это.

        Где впервые был замечен MVP, можно прочитать в статье по ссылке в разделе history.
        • 0
          > Это в теории. На практике, у всех девайсов на iOS достаточно много памяти, чтобы плевать на это.

          в сравнении с Android да, но я на практике встречал задачи для iOS, в которых памяти нехватает и постоянно происходят Memory Warnings, соответственно виджеты перезагружаются и это сказывается на быстродействии
    • 0
      Не совсем понимаю отличия presenter от controller, или же presenter — это тот самый skinny controller?
      • 0
        презентер это модель слитая с контроллером
    • 0
      Плохое решение. Представьте себе код с _ифами_ для проекта большего чем Hello, World

      А теперь — более-менее правильное решение с макросами :-)

      MyUiControlBase {}
      MyUiControlForIPhone: MyUiControlBase {}
      MyUiControlForIPad: MyUiControlBase {}

      #ifdef _IPAD_
      #define MyUiControl MyUiControlForIPad
      #else
      #define MyUiControl MyUiControlForIPhone
      #endif

      MyUiControlBase *pControl = new MyUiControl();

  • 0
    а мой MVC последние года 3 это оказывается MVP, спасибо, что открыли глаза :)
    • 0
      мне кажется четких граний нет, эти границы начинаешь ощущать когда у тебя неожиданно вырастает код UIViewController и сыпятся warnings со словами типо вы забыли объявленные классы связать с визуальным представлением в контроллере, при добавлении новых компонентов. А впринципе как не назови все одно — меньше связанностей — больше свободы :-)
  • 0
    getButtonWithTitle @«Зарегистрироваться» позабавило. Да и комментарии в коде на русском. Неужели у них нет нормальной системы интернационализации для приложений?
    • 0
      контент с Web-сервиса приходит на русском, соответственно приложение не может быть никаким кроме русского. Кстати интересно, что xCode 4 насильно заставляет использовать механизм интернационализации, генеря подпапку en по умолчанию
    • 0
      Нет — просто некоторые разработчики любят хардкодить :-)
  • +1
    if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad)



    Не учите плохому :) Данный код упадет на iOS с версией меньше 3.2.

    Нужно использоать макрос UI_USER_INTERFACE_IDIOM()
    который проверяет или объект обрабатывает сообщение userInterfaceIdiom

    Как-то так:

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)

    • –2
      мне кажется этот код просто не будет компилироваться под iOS с версией меньше 3.2, но с тем что нужно использовать макрос UI_USER_INTERFACE_IDIOM() с вам не согласятся разве что противники макросов :-) сам я не пробовал этой кухни, потому что у нас все проекты идут отдельно на iPhone и iPad приложения и я пользовался только макросами
      • +1
        Сейчас весь код собирается в SDK 4.x, по-этому все скомпилируется без проблем но не будет работать.
        • 0
          Я не смог скомпилировать приложение для устройства iOS с версией ниже 3.2 из xCode 3.X и дырявого xCode 4 тоже не смог с установленной SDK 4.0, вообще при выборе устройства было написано четко «missing». Расскажите, как вам удалось собрать код под устройство ниже 3.2
          • +2
            1. Надо все собирать в SDK 4, старые более не поддерживаются.
            2. Как устройство выбираете iPhone 4. Потом можно в свойствах проекта / таргета задать deployment target. Там может быть меньшая версия. Еще скорее всего надо использовать weak linking для UIKit.
            Тут расписано поподробнее — blog.federicomestrone.com/2010/07/18/base-sdk-deployment-target-weak-linking-and-import/
  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      угу, препроцессинг неплох, но когда в самих макросах нет логики ).

      А вообще похожесь платформ смущать не должна — либо делать приложение которое само собой масштабируется под размеры экрана, либо уж делать приложение с отдельной специально заточенной для другого устройства мордой.
    • 0
      для iPhone/iPad в описанном вами случае все куда проще. Пишется два разных ipadiphone.m и линковщику через проект указывается нужная реализация и все, никаких макросов даже не нужно.

      «Макросы штука хорошая, но они плохо масштабируются.» фраза не о чем, подкрепите фактами.
      • НЛО прилетело и опубликовало эту надпись здесь
        • 0
          Да, я тоже видел кстати изящные решения, в библиотеке OpenCV исключения как раз такие: автоматом указывают файл и строку происхождения, как в самых современных ООП языках. Еще говорят удачный пример хорошего использования макросов в движке халвы.

          Через строку #ifdef достаточно весело, но за счет подсветок IDE в принципе уваривать можно.
  • 0
    Простите, немного не по теме.
    Можно немного об UIUtils sizedButtonFromImageNamed? Если я правильно понял, то создается красивая кнопка, которая, ко всему прочему, может еще и растягиваться. Каков принцип работы?

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

Самое читаемое Разное