Я намучался изрядно с плюсовыми объектами, которые объявлял как обычные мемберы Objective C классов. Проблема в том, что вы не можете быть уверены, когда будет вызван деструктор такого мембера в момент прекращения жизни Objective C объекта, и будет вообще ли вызван этот деструктор.
К счастью есть простоё и надёжное решение.
Используйте обычный указатель или std::auto_ptr. Теперь вы сможете контролировать момент вызова конструктора и момент вызова деструктора. Если вам нужно будет уничтожать C++ объект при уничтожении его владельца (Objective C объекта), то самое подходящее место для этого - метод dealloc (аналог деструктора в Objective C классах).
Как выяснилось, я не напрасно предпочёл в качестве мемберов использовать указатели вместо обычных объектов. На http://rsdn.ru/?/forum/apple.os/ мне помогли разобраться с этой ситуацией (привели цитату из официальной документации)
Objective-C classes cannot have instance variables of C++ classes that do not have a default constructor or that have one or more virtual methods, but pointers to C++ objects can be used as instance variables without restriction (allocate them with new in the -init method).
среда, 18 мая 2011 г.
UIActivityIndicator не всегда работает!
В некоторых случаях UIActivityIndicator не всегда работает. С чем это связано, я до сих пор не знаю.
Выяснил вот что - если после запуска в основном потоке активити-индикатора программа в основном потоке ничего не делает (что само по себе редкость и вряд ли имеет смысл, ведь пользователю нужно дать знать, что дескать программа что-то будет делать, и что она не зависла, а занята выполнением работы), то в таком случае активити-индикатор работает исправно.
Если же программа занялась плотно какими-то задачами в основном потоке (кстати, согласно рекомендациям от Apple в iPhone ГУИ-контролы вообще лучше юзать в основном потоке, если я не ошибаюсь), то активити-индикатор может "не успеть" сделать какую-то подготовительную работу и тогда пользователь его не увидит. Но это лишь мои догадки.
Как я вышел из положения? Приходится программно запускать специально созданный для этого таймер на 1/10 долю секунды (этого времени индикатору хватает), после этого запускать активити-индикатор и просто ничего не делать до срабатывания таймера (то есть до срабатывания функции-обработчика таймера). Этой паузы хватит, чтобы активити-индикатор глотнул воздуха и начал работать. Как только сработает таймер через 1/10 секунды, то останавливайте таймер и запускайте в основном потоке нужные вам функции, это уже не помешает активити-индикатору продолжать показывать, что дескать дела в основном потоке идут.
Конечно, есть риск, что пользователь что-то успеет нажать за 1/10 секунды। Для этого можно перестраховаться с помощью булевой переменной (т.е. заблокировать обработчики нажатий на контролы, вернее выходить из функций обработчиков если эта переменная показывает, что сейчас как раз идёт та самая 1/10 доля секунды).
Добавлено через много месяцев: сейчас я вместо таймера использую более подходящий и простой вызов функции
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay
Смотрите подробнее в документации (эта функция способна вызвать нужный вам код в текущем потоке через нужное время, этого глотка времени хватает, чтобы активити-индикатор закрутился).
Кстати, вся эта статья относится не только к активити-индикаторам, но и многим другим контролам (которым необходим глоток воздуха для того, чтобы успеть отобразиться на экране).
Выяснил вот что - если после запуска в основном потоке активити-индикатора программа в основном потоке ничего не делает (что само по себе редкость и вряд ли имеет смысл, ведь пользователю нужно дать знать, что дескать программа что-то будет делать, и что она не зависла, а занята выполнением работы), то в таком случае активити-индикатор работает исправно.
Если же программа занялась плотно какими-то задачами в основном потоке (кстати, согласно рекомендациям от Apple в iPhone ГУИ-контролы вообще лучше юзать в основном потоке, если я не ошибаюсь), то активити-индикатор может "не успеть" сделать какую-то подготовительную работу и тогда пользователь его не увидит. Но это лишь мои догадки.
Как я вышел из положения? Приходится программно запускать специально созданный для этого таймер на 1/10 долю секунды (этого времени индикатору хватает), после этого запускать активити-индикатор и просто ничего не делать до срабатывания таймера (то есть до срабатывания функции-обработчика таймера). Этой паузы хватит, чтобы активити-индикатор глотнул воздуха и начал работать. Как только сработает таймер через 1/10 секунды, то останавливайте таймер и запускайте в основном потоке нужные вам функции, это уже не помешает активити-индикатору продолжать показывать, что дескать дела в основном потоке идут.
Конечно, есть риск, что пользователь что-то успеет нажать за 1/10 секунды। Для этого можно перестраховаться с помощью булевой переменной (т.е. заблокировать обработчики нажатий на контролы, вернее выходить из функций обработчиков если эта переменная показывает, что сейчас как раз идёт та самая 1/10 доля секунды).
Добавлено через много месяцев: сейчас я вместо таймера использую более подходящий и простой вызов функции
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay
Смотрите подробнее в документации (эта функция способна вызвать нужный вам код в текущем потоке через нужное время, этого глотка времени хватает, чтобы активити-индикатор закрутился).
Кстати, вся эта статья относится не только к активити-индикаторам, но и многим другим контролам (которым необходим глоток воздуха для того, чтобы успеть отобразиться на экране).
Ярлыки:
активити,
индикатор,
таймер,
nstimer,
uiactivityindicator
четверг, 17 марта 2011 г.
Стандартные размеры контролов
Материал взят из http://jdg.net/post/106465937/standard-iphone-element-sizes
Core Elements:
Carrier Status bar - 320x20
UIView - 320x460
UINavigationBar - 320x44
UITabBar - 320x49
UISearchBar - 320x44
UIToolBar - 320x44
Data Input:
UIPickerView - 320x216
UIDatePicker - 320x216
UIKeyboard - 320x216
Buttons:
UISegmentedControl - 320x44
UIButton xx37
Fields:
UITextField - xx37
UISwitch 94x27
UISlider - xx23
Indicators:
UIProgressView -xx9
UIActivityIndicatorView - 37x37
UIPageControl - 38x36
Ярлыки:
контрол,
ipad,
iphone,
iphone os,
iphone sdk,
ipod,
ipod touch
четверг, 10 февраля 2011 г.
Как сделать один общий проект для нескольких статических библиотек (либ)
Недавно я сумел таки обойти некоторые ограничения Xcode и сделать один общий проект для нескольких статических библиотек (либ).
Ограничения касаются прежде всего такого макроопределения как __IPHONE_3_1 (последние цифры не столь важны, это уже технические моменты - всё зависит от того, начиная с какой версии IOS ваше приложение и библиотеки должны работать).
Если для каждой либы (т.е. библиотеки) вы создаёте свой отдельный Xcode-проект, то в m и mm исходниках (а также в c/cpp - исходниках, если они в своих свойствах выставлены как c.objcpp и cpp.objcpp файлы) макроопределения __IPHONE_... срабатывают безотказно.
То есть вы можете в вашем коде сделать такую проверку:
#ifdef __IPHONE_3_1
sad;flkasjdf;laksjdfa;sldfkja;sdlkfjasd;lkfj; // всякая дрянь, которая не точно компилируется
#endif
Если компилятор будет ругаться на эту дрянь, то значит всё в порядке.
Проблема начинается, когда вы объединяете несколько либ в один проект (то есть для каждой либы добавляете в проект новый Target с указанием имени либы, а потом нужные для этой либы исходники указываете в свойствах как предназначенные именно для этого Target).
Можно искусственным способом заставить ваш проект узнавать макроопределение __IPHONE_3_1
Для этого зайдите в свойства проекта и найдите там раздел GCC 4.2 Preprocessing, а в этом разделе такую строку (слева) Preprocessor Macros. Так вот в поле справа можно добавить такую строку
__IPHONE_3_1=1
Туда же можно добавить и другие важные строки, например __GNUC__=1 или TARGET_OS_IPHONE=1
Если вы не найдёте такой раздел (это увы случается, и я пока не выяснил почему так бывает), то можете сделать по другому. Попробуйте ввести в поле поиска наверху строку GCC_PREPROCESSOR_DEFINITIONS - сразу же должно будет появиться внизу то, что нужно.
Ограничения касаются прежде всего такого макроопределения как __IPHONE_3_1 (последние цифры не столь важны, это уже технические моменты - всё зависит от того, начиная с какой версии IOS ваше приложение и библиотеки должны работать).
Если для каждой либы (т.е. библиотеки) вы создаёте свой отдельный Xcode-проект, то в m и mm исходниках (а также в c/cpp - исходниках, если они в своих свойствах выставлены как c.objcpp и cpp.objcpp файлы) макроопределения __IPHONE_... срабатывают безотказно.
То есть вы можете в вашем коде сделать такую проверку:
#ifdef __IPHONE_3_1
sad;flkasjdf;laksjdfa;sldfkja;sdlkfjasd;lkfj; // всякая дрянь, которая не точно компилируется
#endif
Если компилятор будет ругаться на эту дрянь, то значит всё в порядке.
Проблема начинается, когда вы объединяете несколько либ в один проект (то есть для каждой либы добавляете в проект новый Target с указанием имени либы, а потом нужные для этой либы исходники указываете в свойствах как предназначенные именно для этого Target).
Можно искусственным способом заставить ваш проект узнавать макроопределение __IPHONE_3_1
Для этого зайдите в свойства проекта и найдите там раздел GCC 4.2 Preprocessing, а в этом разделе такую строку (слева) Preprocessor Macros. Так вот в поле справа можно добавить такую строку
__IPHONE_3_1=1
Туда же можно добавить и другие важные строки, например __GNUC__=1 или TARGET_OS_IPHONE=1
Если вы не найдёте такой раздел (это увы случается, и я пока не выяснил почему так бывает), то можете сделать по другому. Попробуйте ввести в поле поиска наверху строку GCC_PREPROCESSOR_DEFINITIONS - сразу же должно будет появиться внизу то, что нужно.
среда, 26 января 2011 г.
Xcode vs Visual Studio
Я уже работаю полтора года разработчиком приложений для iPhone (используя единственную официальную среду разработки Xcode). За несколько лет до этого я несколько месяцев работал с Visual Studio.
Да, действительно чувствуется, что в Apple самые главные люди - дизайнеры, а не программисты. Microsoft проявляет больше заботы об удобстве работы программистов с их основным инструментом.
То есть я больше люблю Visual Studio, чем Xcode.
Да, действительно чувствуется, что в Apple самые главные люди - дизайнеры, а не программисты. Microsoft проявляет больше заботы об удобстве работы программистов с их основным инструментом.
То есть я больше люблю Visual Studio, чем Xcode.
вторник, 14 декабря 2010 г.
Как узнать в iPhone-приложении, существует ли файл
Материал взят из http://stackoverflow.com/questions/1356701/whats-a-quick-way-to-test-to-see-a-file-exists
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:somePath];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:somePath];
среда, 24 ноября 2010 г.
Скрипт для автоматического создания архива проекта с датой и временем в имени файла
Этот скрипт расчитан на консоль для Unix-подобных систем (впрочем, возможно его можно запустить и в Cygwin-консоли в Windows, но думаю, что проще найти похожие функции для bat-файлов, принятых в Windows).
Разумеется, нужно вместо MyProject и MyProjectFolderFullPath подставить полные или корректные относительные пути к вашей папке с проектом и к архиву (zip-файлу)
Предположим, что архив будет создаваться в текущей папке:
#!/bin/sh
echo "Enter comment: "
read comment
zipFileName="./MyProject$(date +%Y%m%d_%H-%M)"
echo "compress MyProject to zip archive..."
txtFileName="$zipFileName.txt"
echo $comment > $txtFileName
zip -r $zipFileName MyProjectFolderFullPath
Не забудьте сделать скрипт исполняемым файлом. Теперь в консоли достаточно будет ввести имя файла этого скрипта (проще разместить его в домашней папке) и нажать Enter - и архив папки проекта вместе с одноимённым текстовым файлом комментариев будут выглядеть примерно так:
MyProject20101124_14-20.txt
MyProject20101124_14-20.zip
Очень удобно.
Разумеется, нужно вместо MyProject и MyProjectFolderFullPath подставить полные или корректные относительные пути к вашей папке с проектом и к архиву (zip-файлу)
Предположим, что архив будет создаваться в текущей папке:
#!/bin/sh
echo "Enter comment: "
read comment
zipFileName="./MyProject$(date +%Y%m%d_%H-%M)"
echo "compress MyProject to zip archive..."
txtFileName="$zipFileName.txt"
echo $comment > $txtFileName
zip -r $zipFileName MyProjectFolderFullPath
Не забудьте сделать скрипт исполняемым файлом. Теперь в консоли достаточно будет ввести имя файла этого скрипта (проще разместить его в домашней папке) и нажать Enter - и архив папки проекта вместе с одноимённым текстовым файлом комментариев будут выглядеть примерно так:
MyProject20101124_14-20.txt
MyProject20101124_14-20.zip
Очень удобно.
Подписаться на:
Сообщения (Atom)