среда, 30 июня 2010 г.

Upgrade Current Target for iPad - проблемы!

Upgrade Current Target for iPad - увы, я не нашёл этот пункт в контекстном меню при использовании iPhone SDK 3.2 beta (включающего в себя Xcode 3.2.2).

Вместо него там стоит пункт Transition - который выполняет именно то, что должен был выполнять пункт
Upgrade Current Target for iPad.

Должен отметить, мне нравится, куда располагаются xib-файлы для iPad, автоматически генерируемые из одноимённых файлов для iPhone. Но я после этого создаю отдельные папки Resource-iPhone (куда перемещаю ресурсы
, специфичные только для iPhone, в том числе и xib-файлы) и Resource-Common (куда перемещаю общие ресурсы). После этого нельзя забыть удалить из проекта потерянные ресурсы (обозначенные красным цветом в дереве Xcode-проекта) и снова присоединить их к проекту уже из их новых папок. Теперь с ресурсами всё выглядит более логично и организованно.

пятница, 11 июня 2010 г.

Quartz-рисование в отдельном потоке

Будьте заранее готовы к некоторым проблемам, если захотите рисовать что-либо в отдельном потоке. Отдельный поток для рисования сложного контента необходим для того, чтобы GUI-контролы продолжали отвечать на ваши нежные прикосновения к экрану iPhone в то время, как на экране что-то продолжает рисоваться.

Из основного потока вы можете нажать какой-либо GUI-контрол (например кнопку или слайдер). Если нужно, то можно через изменение некоторых объектов (или даже простых bool переменных) попросить поток рисования изменить параметры рисунка или что-то в этом роде.

Есть одна очень существенная деталь, которую нужно помнить!

Ну само собой, нужно защищать переменные от одновременного изменения их значений из разных потоков одновременно. Для этого существуют различные средства синхронизации, pthread-мютексы (в C/C++), @synchronized-блоки (в Objective C).

Я хотел предупредить о другом. Сейчас я столкнулся с серьёзной проблемой. Оказывается, когда вы захотите сделать контекст (в который вы рисуете что-либо) текущим с помощью вызова функции UIGraphicsPushContext (и потом вернуть всё как было с помощью функции UIGraphicsPopContext) ТО ВАЖНО ЗНАТЬ, ЧТО ЭТИ 2 ФУНКЦИИ МОЖНО ВЫЗЫВАТЬ ТОЛЬКО ИЗ ОСНОВНОГО ПОТОКА ПРОГРАММЫ!

Мне нужно рисовать в контекст (не контекст экрана, а контекст в памяти) текст. Если я не сделаю этот контекст текущим, то текст в результате не нарисуется. Проблема в том, что я должен рисовать текст в отдельном потоке рисования. Из-за этого я вынужден из этого отдельного потока просить главный поток программы делать вызовы этих 2-х функций (UIGraphicsPushContext и UIGraphicsPopContext) и ждать каждый раз пока главный поток не соизволит это сделать (а главный поток может быть занят в это время чем-то важным, как ему кажется). Это приводит к целому ряду проблем, которых можно было бы избежать, если я бы знал об этом заранее (это бы позволило предпринять некоторые меры при предварительном проектировании, ещё до того, как была написана первая строка кода). У меня сейчас даже случаются дедлоки (взаимные блокировки потоков).

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

Макрос _T при переносе Win32 проектов на iPhone

Как правило сейчас уже во всех Win32 (MFC) проектах такая строка в коде _T("Я люблю вас, девочки") воспринимается компилятором как L"Я люблю вас, девочки" (то есть как wchar_t строка).

Чтобы не перелопачивать код, который вам нужно портировать из Windows в iPhone, можете добавить в общий заголовочный файл (например, в исходники, где определены все макросы и константы) такое макроопределение:

#ifdef __IPHONE_3_1
#ifndef _T
#define _T(a) L##a
#endif
#endif


После этого вам должно стать хорошо и приятно :)

среда, 2 июня 2010 г.

Проблемы с isnan функцией (при портировании кода Win32-приложения для iPhone)

Функции _isnan нет в iPhone OS (там должна быть функция isnan, включенная в math.h или cmath заголовки), поэтому я делаю такой трюк:

// где-то наверху файла
#ifdef __IPHONE_3_1
#include < cmath > // или #include < math.h >
#endif

// где-то в коде
#ifdef _WIN32
if(_isnan(val))
#elif defined(__IPHONE_3_1)
if (isnan(val))
#endif

//////////////////////////////////
// увы, иногда < cmath > или < math.h > бессильны нам помочь (мистика?),
// и тогда делайте так в одном месте, где-нибудь в общем заголовке:

#ifdef __IPHONE_3_1
#define _isnan(x) \
( sizeof (x) == sizeof(float ) ? __inline_isnanf((float)(x)) \
: sizeof (x) == sizeof(double) ? __inline_isnand((double)(x)) \
: __inline_isnan ((long double)(x)))
#endif //__IPHONE_3_1


Если вы хотите, чтобы #ifdef __IPHONE_3_1 условие точно срабатывало, то один из способов гарантировать это - сделать cpp файл типом objcpp (в свойствах файла, если щёлкнуть по имени файла в дереве Xcode-проекта). С заголовочными файлами обстоит немного посложнее, но если заголовочник уже включен в cpp-файл, с которым вы сделали как я советую, то обычно всё в порядке будет и в заголовочном файле.

Постоянные читатели