Кроссплатформенный код для приложений под iPhone и iPad
Учимся парадигме Model-View-Presenter и выкидываем в AppStore кучу вкусностей для iPhone и iPad сразу
Как наиболее оптимальным образом портировать приложение, написанное под iPhone для iPad, можите решить только вы сами. Могу лишь предложить несколько рецептов, которые будут удобны в использовании на данном конкретном примере Web-приложений.
Далее будет предложена парадигма организации кода, рассмотрены компоненты, доступные в SDK 3.2. А паттерны проектирования вы изучите сами :-)
Начинается все с дизайна. Как правило, несколько экранов iPhone пытаются уложить на одном экране iPad.

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

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

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

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

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

При написании картотеки арбитражных дел нельзя было использовать стандартные компоненты, доступные в SDK 3.2, такие как UISplitViewController и UIPopoverController. Например, первый не поддерживает работу UINavigationController и должен быть главным экраном. У второго компонента отсутствует обратная совместимость с iPhone. Выход: писать свои компоненты. Кстати сторонние разработчики уже делали свои варианты. Об этом есть, например, статья на Хабре
При желание можно больше и еще больше и гораздо больше поместить на экране iPad информации, заимствованной с экранов iPhone. В проекте картотека присутствовала обратная совместимость, то есть для удобства использования перехода от дела к инстанциям дела использовался выпадающий список UIPopoverController, который по непонятным причинам имеет запрет на использование на iPhone, причем выясняется это на этапе исполнения кода. Выход: ПИШИТЕ СВОИ КОМПОНЕНТЫ.
Немного практики
Обычно на практике представление формируется прямо в Presenter.
В парадигме Apple экраны (представления) должны храниться в ресурсах, но это очень неудобно. Нужно постоянно поддерживать связи с Controller, не говоря уже о модели. Было принято решение, что формировать представление прямо в Presenter будет наиболее эффективно. При этом код самого презентора увеличивать совсем не обязательно, даже напротив — его можно выделять в классы и даже подклассы, как показано в данном примере для элемента списка.

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

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

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

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

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

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

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

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

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

При написании картотеки арбитражных дел нельзя было использовать стандартные компоненты, доступные в SDK 3.2, такие как UISplitViewController и UIPopoverController. Например, первый не поддерживает работу UINavigationController и должен быть главным экраном. У второго компонента отсутствует обратная совместимость с iPhone. Выход: писать свои компоненты. Кстати сторонние разработчики уже делали свои варианты. Об этом есть, например, статья на Хабре
При желание можно больше и еще больше и гораздо больше поместить на экране iPad информации, заимствованной с экранов iPhone. В проекте картотека присутствовала обратная совместимость, то есть для удобства использования перехода от дела к инстанциям дела использовался выпадающий список UIPopoverController, который по непонятным причинам имеет запрет на использование на iPhone, причем выясняется это на этапе исполнения кода. Выход: ПИШИТЕ СВОИ КОМПОНЕНТЫ.
Немного практики
Обычно на практике представление формируется прямо в Presenter.
В парадигме Apple экраны (представления) должны храниться в ресурсах, но это очень неудобно. Нужно постоянно поддерживать связи с Controller, не говоря уже о модели. Было принято решение, что формировать представление прямо в Presenter будет наиболее эффективно. При этом код самого презентора увеличивать совсем не обязательно, даже напротив — его можно выделять в классы и даже подклассы, как показано в данном примере для элемента списка.

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

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

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

Итоги
Во-первых, нужно определить настройки проекта(ов) для определения представления (View) на этапе компиляции или выполнения. Затем необходимо избавиться от связей Model-View путем переноса логики их взаимодействия в Presenter.
Максимально эффективно отвязываемся от представлений, формируемых посредством xib, оставляя в них только атомарные полотна (например, такие как UIViewTableCell).
Потом определяем макросы, ограничивающие представление под устройство iPhone/iPad. И не забудьте, что Objective-C является «Message Oriented Program» языком (пишем свою VCL).
комментарии (105)
Можно написать базовый класс для отрисовки чего либо, затем сделать два наследника — один рисует для айпад, другой для айфона.
Когда приложение запускается, оно в зависимости от девайса создает экземпляр нужного класса.
Как-то так.
Это не обработка изображений или звука, а простое GUI приложение.
> Представте что вы своим насследованием потяните кучу изменений классов
Когда у вас ifdef-ов будет более 100 — расскажете как вам весело. Это из практики.
Я просто сталкивался с С/С++ многоплатформенными библиотеками такими как OpenCV, BOOST и не боюсь макросов, и вам рекомендую не переживать, они бывают неизбежны и очень полезны.
Был спор по GOTO, зло ли это? Нужно ли его использовать? Кароче спор никто не выйграл, но языки программирования начали от него избавлятся. Типо чтобы народ не шубуршил и фигней не страдал с обсуждениями. :-)
Как вы думаете насчет перспектив макросов?
Макросы вообще костыль в принципе
Кстати думаю могу привести пример кода, изрезанного макросами, которой в объектной модели даст жуткий полиморвизм, который будет очень тяжело поддерживать с учетом виртуализации Obj-C
do
{
//…
if (cond) break;
//…
}
while (false);
Задать константы макросами — да пожалуйста, но писать большой код — оч. плохо.
static const int удобнее и лучше компилятором проверяется.
PyObject_Newнапример.Я как бы не согласен в принципе, что макросы — это что-то плохое. Какой бы язык не был, иногда приходится часто выписывать одну и ту же конструкцию — поэтому возникает естественное желание как-то это автоматизировать. Потом появляется желание сделать макросы с параметрами, и т. д. Это совершенно естественный инструмент для облегчения писанины и, кстати, для экспериментов с новыми языковыми идеями, что и показывает нам пример Objective-C, выросшего из макросов.
Однако согласен частично, но это не означает что ifdef надо полностью избегать, иногда они даже упрощают логику и понимание программы. Полиморфизм на ваш взгляд чем проще? Виртуализация чем по вашему упрощает в месадж-ориентированных языках жизнь команды разработчиков?
«Если вы такие умные, то почему строевым шагом не ходите?»
Как-то так… Грустно…
C классами порядка больше.
> Кстати сейчас картотеку портируют под Android и есть проблемы с памятью…
* Создавать объекты по мере необходимости
* Обращаться за нужной порцией данных в БД (Apple такое решение для афйоном сама советовала)
Для каждой платформы свой View, часто бывает что и свой Controller.
Но если приходится переписывать Model — значит у вас плохо разделена логика и представление.
1) замечу, что почему-то многие программисты стремятся к сокращению объемов кода/уменьшению количества файлов. На первый взгляд, стремление здравое, но оно обычно порождает вот такие вот ifdef'ы и прочая.
2) смысл моего подхода — максимально разорвать связи между стандартными компонентами и отделить логику работы программы от ее представления. Для этого я использую мааленькую библиотечку PureMVC (http://www.puremvc.org). Для нее имеется порт под Obj-C, но я предпочитаю свой собственный кастомный вариант.
3) использование данной библиотеки однозначно увеличивает количество файлов в проекте (каждому визуальному компоненту надо сделать свой медиатор и т.п.), НО, помимо остальных преимуществ, весь проект оказывается весьма приятно структурированным, что положительно сказывается на дальнейшей поддержке. Например, я могу открыть какой-то старый проект и всегда буду знать, что где находится и за что отвечает — для больших проектов во много десятоков и сотен тысяч строк это очень большой плюс.
4) В итоге, внешний вид программы получается полностью оторванным от логики ее работы, эти две сущности живут параллельно и друг от друга никак не зависят. При загрузке мы инстанцируем соответствующие платформе визуальные компоненты, и не более того.
P.S.: на первый взгляд может показаться, что этот подход мало чем отличаеся от описанного в статье, но, поверьте, это немного не так. Смысл в том, что разрыв между сущностями происходит на более высоком уровне, чем предлагает стандартный подход конкретной платформы. Поэтому, после некоторой тренировки, его можно использовать единообразно на любой платформе — например, я использую эту библиотеку для написания программ на C++, Javascript, Actionscript, Obj-C. Дополнительный бонус — облегченное портирование между платформами.
ну про C++ понятно, а как с другими языками то?
Вот интересно на Obj-C вы под какие платформы пишите? Поделитесь опытом. Был ли опыт именно кросплатформеного написаниея и какие платформы?
Javascript, Actionscript вообще непонятно, зачем это было необходимо? Кросбраузерность что ли какая?
«javascript, actionscript & etc» — это способ портировать _логику_ работы программы, т.е. то, как там данные гуляют внутри программы и к каким изменениям состояний отдельных компонентов они приводят. Как пример, один наш проект, около 150к строчек исходных текстов пережил трансформацию С++ -> Actionscript -> C++. Первое портирование было весьма трудоемким и сложным, по-сути пришлось написать программу заново. Второе портирование было сделано за пару недель времени, благодаря тому, что в обоих случаях система строилась вокруг PureMVC. В придачу код «усох» раза в два, по сравнению с первоначальной версией, хотя чего-либо лишнего в исходной программе естественно не наблюдалось и вся архитектура в целом считалась удачной… Этот же проект сейчас портируется на Javascript.
Я не рекламирую данный подход как панацею от всех бед, более того, все плюсы и минусы MVC известны давно. Но, как показывает моя практика, большинство программистов почему-то не задумываются о том, что использовать данный подход можно не только тем способом, который предлагает целевая платформа, но и полностью абстрагируясь от платформы.
ObjC — iphone/ipad, под мак, увы не делал ничего.
Какие ваши действия по исправлению кода?
я бы завернул MPMusicPlayerController в прокси-класс и сделал бы реализацию этого прокси-класса для каждой платформы свою. В симуляторе она бы писала бы в лог, что типа вот дела то-то. А на айфоне бы перенаправлялись бы все вызовы оригинальному MPMusicPlayerController. При добавлении новой платформы достаточно было бы добавить новый прокси-класс для реализации функционала для новой платформы.
Но это правильный путь, а если нужно просто забить гвоздь, чтоб одна строчка кода не мешала — то Ваш метод годится.
В таком случае при добавлении поддержки в симуляторе достаточно было бы изменить MPMPC_NOT_SUPPORTED на true (и это изменение не затронуло бы других мест, где идет проверка на симулятор)
Смахивает на некачественный перевод.
По тому, что смог понять, ситуация, к которой приходишь с опытом разработки, описана довольно точно.
Или у вас есть «мифический» оригинал? ;)
summer2010.etalks.ru/
Немного рекламы: материал (в том числе и видеосъемку) можно преобрести тут
www.stepinsoft.com/shop/etalks-summer-2010/
По поводу макросов для каждой платформы, когда платформы 2 — это еще приемлемо. Когда 3 — это терпимо. Но если больше — это уже невыносимо. Таким образом использование макросов для разделения кода приводит к заведомому забиванию гвоздя в масштабируемость и расширяемость. Я согласен что этот метод применим, если горят сроки и четко ограничего количество платформ. Но если позволяет время, лучше сделать все правильно.
Спавиться с кроссплатформенностью помогают паттерны, например фабрика и фабрика классов. Стратеги и визитер тоже часто помогают. Ну и естественно не брезговать стандартной в iOS моделью MVC. Так что рекомендую ознакоится с технологиями кросплатформенного программирования и не считать себя Колумбом в этой области.
А если Вы захотите еще настольную MAC версию сделать ??? еще одна ветка ??? или заново все писать ???
По поводу «пишите свои компоненты» могу долго и нудно спорить. Но дело ваши, грабли будут бить Вам по голове.
2. Паттерны в статье предлагается открыть для себя самостоятельно, это значит что в данном контексте они не используются, у вас не возникает вопроса почему?
3. «А если Вы захотите еще настольную MAC версию сделать ??? еще одна ветка ??? или заново все писать ???» Вот тут вы себе противоречите, как раз будет куча веток классов наследования, каждый композитор будет перенаследован, кроме того будет написано куча обслуживающего кода: адапторы, фабрики. Кроме того поедит производительность. Кроме того стоит учитывать тот факт что iPhone/iPad — почти идентичные платформы, следовательно код у них почти одинаков, меняется представление и чаще всего оно всего лишь расширяется для iPad. А под Mac используются совершенно другие компоненты и поведение, для него можно портировать только МОДЕЛЬ. Впринципе модель можно портировать под любую платформу.
4. Свои компоненты чаще всего неизбежны за счет ограничений стандартных. Чего тут спорить? Ну никак нельзя UISplitViewController посадить на навигатор, что вы предложите в замен?
По соотношениям Количество кода/Ошибки, Время разработки/читаемость кода, Масштабиремость / Быстрота исполнения в конкретном продукте я посчитал макросы идеальным решением
он жив только благодаря тому, что objective-c — это в первую очередь C.
“По соотношениям Количество кода/Ошибки, Время разработки/читаемость кода, Масштабиремость / Быстрота исполнения в конкретном продукте я посчитал макросы идеальным решением»
Странно, а я именно по этим критерям считаю его самым худшим решением. Так как поддержка кода, содержащего такой подход, — это просто ад.
Вы же не писали для Картотеки код, откуда вам знать что это для нее наихудшее решение?
Вы видимо предположили из своего опыта, очевидно негативного, а я пытался донести до вас свой позитивный опыт. Это рецепт, одного из блюд, которое может быть использовано совместно с другими.
извините, в моем утверждение нужно выкинуть «в конкретном продукте», так как я не понял что Вы имеете ввиду эменно этот продукт.
2. Треть статьи описывает модификацию паттерна MVC. Почему бы не описать простые паттерны для написания кросс-платформенного кода, мне не понятно.
Я не говорю что нужно тут описывать паттерны, наоботор. Просто нужно упомянуть хотя-бы названия (а лучше со ссылками) те паттерны, которые будут полезны.
3.Нисколько не противоречю. Код и проект долежн быть один. Разделение платформ должно происходить за счет паттернов и архитектуры а не за счет ветвлений кода макросами. Иначе прийдется портировать кусками, как Вы и предложили, например портировать Модель. Но портировать код — это значит сделать отдельную ветку, и поддерживать теперь прийдется две модели, хоть вышли они из одной точки. Плюс появится еще один код.
Мод Мак как раз испольузется тоже Cocoa. Они немного различаются, но это один фреймворк и один код. Просто для разных целевых платформ у него различное поведение заложеное как раз паттернами, а не ветвлениями макросов.
4. Расширение стандартных компонент — это не написание собственных. Это расширение стандартных.
3. я бы сказал парадигма одна, контролы и суп из них отличаются. Суть в том что кода надо будет настолько больше переписывать, что я лично не вижу делать его единым. Но не об этом статья, и не будет под Mac Картотеки, уверяю вас. Статья про iOS.
4. Вы уверены что UISplitViewController можно для этого расширить? Дело в том что ограничения стоят на уровне архитектуры. Я читал много статей о нем и все писали свои варианты, ни видел я даже попыток его расширить. Многие компоненты Apple не поддаются дресировки, именно потому что написаны на месадж-ореентированном языке, как это не звучит странно
4.
3. Статья как раз больше чем об iOS, статья о кроссплатформенности. А это тернистый путь :-)
4. С UISplitViewController знаком вскольз. Ограничение я это видел. Оно мне кажется странным и я уверен что в будущем оно исчезнет. Именно поэтому Ваш подход написания собственного аналога — это workaround (или «гвоздь» по русски), чтоб обойти это ограничение. Его нельзя считать правильным подходом. Это не значит, что так делать нельзя. Более того я практически уверен, что Ваше решение обойти проблемму самое логичное и оптимальное. НО!!! я в корне не согласен с утверждением «ПИШИТЕ СВОИ КОМПОНЕНТЫ». Я уверен что нужно писать свои компоненты только в крайнем случае имея очень везкие аргументы, а лучше и факты R&D работы.
Вы победили, насчет компонентов. Мне тоже надоело их писать.
Model-View-Presenter, кстати впервые был замечен вовсе на в .NET: en.wikipedia.org/wiki/Model-view-presenter
макросы позволяют на этапе копиляции убрать ненужный код в конечном приложении, ну например объявили вы массив в iPad для класса и где небудь держите миллион экземпляров этого класса, оно надо iPhone?, память нужно экономить у мобилок
Или метод вызывается в цикле миллион итераций, а в методе надо делать проверку? Насколько все замедлится?
А где был замечен впервые MVP?
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.
Это в теории. На практике, у всех девайсов на iOS достаточно много памяти, чтобы плевать на это.
Где впервые был замечен MVP, можно прочитать в статье по ссылке в разделе history.
в сравнении с Android да, но я на практике встречал задачи для iOS, в которых памяти нехватает и постоянно происходят Memory Warnings, соответственно виджеты перезагружаются и это сказывается на быстродействии
А теперь — более-менее правильное решение с макросами :-)
MyUiControlBase {}
MyUiControlForIPhone: MyUiControlBase {}
MyUiControlForIPad: MyUiControlBase {}
#ifdef _IPAD_
#define MyUiControl MyUiControlForIPad
#else
#define MyUiControl MyUiControlForIPhone
#endif
MyUiControlBase *pControl = new MyUiControl();
Не учите плохому :) Данный код упадет на iOS с версией меньше 3.2.
Нужно использоать макрос
UI_USER_INTERFACE_IDIOM()который проверяет или объект обрабатывает сообщение
userInterfaceIdiomКак-то так:
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
2. Как устройство выбираете iPhone 4. Потом можно в свойствах проекта / таргета задать deployment target. Там может быть меньшая версия. Еще скорее всего надо использовать weak linking для UIKit.
Тут расписано поподробнее — blog.federicomestrone.com/2010/07/18/base-sdk-deployment-target-weak-linking-and-import/
platform.hс непрозрачными структурами данных (struct proj_MyData;), определил бы там же общие функции, и для каждой платформы отдельно написал бы реализацию:ipad.c,iphone.c. (Ну или.m, у вас же Objective-C.) Каждый файл реализации начинается с вопроса препроцессору#ifdef <проверка платформы>, и если нет, все содержимое файла пропускается. Соответственно внутри файла можно писать уже чисто под конкретную платформу. Мне вот сейчас нужно писать разные ветки для Mac/Windows (на С), так я сделаю именно так. В моем-то случае их всяко не поженить :).Разумеется, так выносится только зависимый от платформы код.
Макросы штука хорошая, но они плохо масштабируются.
А вообще похожесь платформ смущать не должна — либо делать приложение которое само собой масштабируется под размеры экрана, либо уж делать приложение с отдельной специально заточенной для другого устройства мордой.
«Макросы штука хорошая, но они плохо масштабируются.» фраза не о чем, подкрепите фактами.
Насчет макросов я просто имел в виду, что если через строчку втыкать
#ifdef, то ум за разум зайдет :) А так ничего утверждать не берусь — сам видел изящные решения с немаленькими макросами, например, собственную обработку исключений на C.Через строку #ifdef достаточно весело, но за счет подсветок IDE в принципе уваривать можно.
Можно немного об UIUtils sizedButtonFromImageNamed? Если я правильно понял, то создается красивая кнопка, которая, ко всему прочему, может еще и растягиваться. Каков принцип работы?