Блог О пользователеiphonesdk

Регистрация

 

Теги

_isnan _t apple automation autorelease pool bar bash bug c++ cellforrowatindexpat h cgimage chflags cocoa condition const contentinset contentsize cpp.cpp dealloc debug debugger destructor exc_bad_access exist finger piano share gcc header headers herb sutter interface builder ios ios 5.0 ios 6 ipad iphone iphone os iphone sdk ipod ipod touch isnan junior leader line link linker linux mac os mac os x 10.7 man member memory microsoft visual studio multithread multithreading navigation bar nil nsautoreleasepool nslog nsstring nsthread nstimer nszombieenabled objcpp.cpp objective c objective-c out of memory phread posix pthread pthread_attr_setstac ksize quartz regex regular expressions release rename rotate script senior setevent shell sleep stack stack size static lib status bar std::toupper stricmp team leader template class temporary files thread tinyxml uiactivityindicator uicollectionview uigraphicspopcontext uigraphicspushcontex t uiimage uiscrollview uitableview uitableviewcell unix upgrade current target for ipad validate variables win32 windows www.odesk.com xcode xcode 4.2 xcode-проект xcodebuild xcodeproj xml xml document xml parser yamaha автоматизация автоматически алёна c++ алёна сагалаева андрей александреску антипаттерны банда четырёх бертран мейер библиотеки быстрая разработка программ временные файлы вывод текста герб саттер гигантская гради буч дедлок дерево проекта деструктор джоэл спольски директория дополнительный поток защита знание языка c++ изображение исходник каталог квалификация коллективный проект компилятор компиляция константная константные контрол копировать линкование линковка макроопределение мембер многопоточность настройка несколько библиотек в одном проекте несколько либ ооп основной поток падение память паттерны проектирования переименовать переполнение переполнение стека повернуть получить путь к папке портирование поток проблемы с отладчиком программирование программист проект размер текста разработчик рефакторинг роберт лафоре роберт мартин си++ скрипт смещение контрола ссылки статическая библиотека статические библиотеки статические либы стек стив макконел странности отладчика утечки памяти файл фредерик брукс функция человеко-лет человеко-месяц член член класса шаблонный класс электронные книги электронные читалки

1 |2 |3 |4 |5
 

Apple официально анонсировала iOS 5.0, Mac OS X 10.7 и сервис iCloud


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

 

Источник: Cybersecurity.ru



 
 
 

C++ объекты как мемберы Objective C классов


Я намучался изрядно с плюсовыми объектами, которые объявлял как обычные мемберы 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).

 

UIActivityIndicator не всегда работает!


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

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

Если же программа занялась плотно какими-то задачами в основном потоке (кстати, согласно рекомендациям от Apple в iPhone ГУИ-контролы вообще лучше юзать в основном потоке, если я не ошибаюсь), то активити-индикатор может "не успеть" сделать какую-то подготовительную работу и тогда пользователь его не увидит. Но это лишь мои догадки.

Как я вышел из положения? Приходится программно запускать специально созданный для этого таймер на 1/10 долю секунды (этого времени индикатору хватает), после этого запускать активити-индикатор и просто ничего не делать до срабатывания таймера (то есть до срабатывания функции-обработчика таймера). Этой паузы хватит, чтобы активити-индикатор глотнул воздуха и начал работать. Как только сработает таймер через 1/10 секунды, то останавливайте таймер и запускайте в основном потоке нужные вам функции, это уже не помешает активити-индикатору продолжать показывать, что дескать дела в основном потоке идут.

Конечно, есть риск, что пользователь что-то успеет нажать за 1/10 секунды. Для этого можно перестраховаться с помощью булевой переменной (т.е. заблокировать обработчики нажатий на контролы, вернее выходить из функций обработчиков если эта переменная показывает, что сейчас как раз идёт та самая 1/10 доля секунды).

Добавлено через много месяцев: сейчас я вместо таймера использую более подходящий и простой вызов функции
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay
Смотрите подробнее в документации (эта функция способна вызвать нужный вам код в текущем потоке через нужное время, этого глотка времени хватает, чтобы активити-индикатор закрутился).

Кстати, вся эта статья относится не только к активити-индикаторам, но и многим другим контролам (которым необходим глоток воздуха для того, чтобы успеть отобразиться на экране).

 

Стандартные размеры контролов


Материал взят из 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


 

Как сделать один общий проект для нескольких статических библиотек (либ)


Недавно я сумел таки обойти некоторые ограничения 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 - сразу же должно будет появиться внизу то, что нужно.

 

Xcode vs Visual Studio


Я уже работаю полтора года разработчиком приложений для iPhone (используя единственную официальную среду разработки Xcode). За несколько лет до этого я несколько месяцев работал с Visual Studio.

Да, действительно чувствуется, что в Apple самые главные люди - дизайнеры, а не программисты. Microsoft проявляет больше заботы об удобстве работы программистов с их основным инструментом.

То есть я больше люблю Visual Studio, чем Xcode.

 
 
 

Скрипт для автоматического создания архива проекта с датой и временем в имени файла


Этот скрипт расчитан на консоль для 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

Очень удобно.

 

Прокрутка и масштабирование в UIScrollView


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

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

Но если размер вложенного в UIScrollView-вид контентного вида (например UIView или его наследника) равен размеру UIScrollView-вида (то есть размеру контейнера для вашего контента) ИЛИ если вы забыли установить у UIScrollView-вида свойство contentSize таким, чтобы размеры контента были явно больше размеров самого UIScrollView-вида, то прокрутка будет невозможна (или возможно, но только после растягивания контента, чтобы он стал больше размера родительского окна, то есть UIScrollView-вида).

Есть 2 способа сделать возможной прокрутку:
1) сделать изначально большим размер контентного окна и не забыть установить таким же размер через свойство contentSize вашего UIScrollView-вида.
2) установить свойство contentInset, которое устанавливает дополнительное пространство слева, справа, сверху и снизу от контентного окна, чтобы дать возможность его прокручивать (если размеры контентного окна совпадают с размерами родительского окна).

Так вот, я проверил лично: 2-й способ лучше именно для тех случаев, если вам не нужно размещать большой контент, а именно такой, который размером совпадает с UIScrollView-видом (даже если вы и будете его потом растягивать пальцами). Этот способ заметно экономит потребляемую девайсом память, а значит уменьшает шансы на недопустимое падение программы без всякого предупреждения и спасения данных.

 

Переполнение памяти из-за больших размеров окон (UIView)


Разрабатываемое iPhone-приложение может начать неожиданно падать и при этом отладчик никак не в состоянии помочь.

После нескольких дней поиска (когда программа перестала падать после закомментирования содержимого функции drawRect класса моего окна, наследующего от UIView) удалось случайно выяснить, что слишком большой размер окна (который можно задать либо в Interface Builder либо через self.bounds.size) требует слишком много памяти (в моём случае - это цена за возможность безтормозной прокрутки такого большого окна, если оно отображает контент для UIScrollView). Размер окна составлял примерно 4000 на 2500 пикселей.

Стоило лишь уменьшить размер окна в половину, как падение программы прекратилось.

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

 

Как вывести в отладочную консоль используемую память в iPhone-приложении


Материал взят из 
http://stackoverflow.com/questions/2786539/iphone-memory-usuage

#import < mach/mach.h >


void report_memory(void) {
 
struct task_basic_info info;
  mach_msg_type_number_t size
= sizeof(info);
  kern_return_t kerr
= task_info(mach_task_self(),
                                 TASK_BASIC_INFO
,
                                 
(task_info_t)&info,
                                 
&size);
 
if( kerr == KERN_SUCCESS ) {
   
NSLog(@"Memory used: %u", info.resident_size); //in bytes
 
} else {
   
NSLog(@"Error: %s", mach_error_string(kerr));
 
}
}

 
 
 

Проблемы с UIScrollView и Landscape ориентацией интерфейса


Обнаружил, что при использовании Interface Builder'а (если в нём создавать окно, содержащее UIScrollView окошко) возникают существенные проблемы при попытке обеспечить поддержку не только Portrait но и Lanscape ориентации интерфейса.

Моя задача: автоматически перестраивать размеры контент-вида (именно того вида, который передвигается внутри UIScrollView) так, чтобы его длина и ширина были больше длины и ширины UIScrollView окошка в целое число раз (константу) при любом положении девайса.

Сейчас (истратив десятки часов на е..лю с горячо любимым Xcode) я прихожу к выводу, что бесполезно пытаться программно перестраивать размеры контент-вида (того самого, который можно передвигать пальцем используя UIScrollView). Приложение всё равно игнорирует (во всяком случае при визуальном тестировании на девайсе) весь ваш код, и продолжает упёрто принимать во внимание только тот размер, который вы задавали контент-виду через Interface Builder.

Оказывается, требуется в настройках (см. Inspector в Interface Builder) главного окна (в котором будет расположено окошко UIScrollView) и в настройках самого UIScrollView окошка поставить галочку Autoresize Subviews.

Кроме того, важно выставить правильные настройки (в виде красных отрезков и стрелочек) в разделе Autosizing (см. Inspector в Interface Builder). Мне удалась моя задача, как только я выставил только красные стрелочки и убрал красные отрезки в настройках контент-вида. То есть программное изменение размеров и оффсета контента я в коде тоже оставил и это вероятно работает теперь в совокупности (не стал это выяснять, чтобы не злоупотреблять рабочим временем - главное теперь работает как надо).

Обидно, что для выяснения подобных тонкостей уходят многие часы. Хотя это - цена за бесценный опыт.

ЧЕРЕЗ НЕСКОЛЬКО ЧАСОВ: Теперь после многочасовой возни с отладчиком и отладочной консолью удалось выяснить основную причину всех моих бед.

При повороте девайса можно перехватывать это событие (поворот девайса) как вариант в функции shouldAutorotateToInterfaceOrientation (подробности через Гугл). Так вот, при перехвате этого события размеры Autoresize-окон ещё не поменялись! Если вы будете вызывать при перехвате этого события какие-то функции (меняющие размеры ваших сущностей, в которых вы что-то рисуете), то нельзя ориентироваться на текущие bounds (размеры) ваших окон, которые ещё не успели красиво повернуться, подстроившись под новое положение девайса!

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

 
 
 

CodeFest — конференция разработчиков в Новосибирске 23 сентября


http://codefest.ru/

CodeFest —
конференция разработчиков, посвященная актуальным вопросам разработки, управления проектами и тестирования. Достойные гуру интернет-технологий съезжаются со всей России, чтобы вдохнуть глоток свежих знаний, встретить старых знакомых и завести новые связи.

 

Высота стандартных iPhone-контролов по умолчанию


При разработке iPhone-приложений высота контролов по умолчанию:

Status Bar: 20px
Navigation Bar: 44px
Tab Bar: 50px

Если не ошибаюсь, аналогичная высота и у iPad-контролов.

Помнить эти значения приходится каждый раз, когда вы запихиваете в UIView всякие UITableView и прочие окошки.

Всё-таки Interface Builder при некоторых своих косяках даёт экономию времени (создавать контролы руками через код иногда бывает крайне необходимо, но это в любом случае приходится дольше делать, чем делать несколько движений мышкой в Interface Builder'e - ну и кроме того, снимается ряд головняков, например таких как контроль над утечками памяти программно создаваемых контролов). Особенно я люблю Interface Builder за возможность быстро создать взаимосвязи между контролами и функциями-обработчиками (где в качестве возвращаемого типа указываем IBAction).

Так вот - в ряде случаев применение Interface Builder'а позволяет значительно упростить задачу создавать в одном Xcode-проекте приложение сразу и для iPhone и для iPad (просто для разных экранов работаете мышкой с одноимёнными xib-файлами - поверьте, получается быстрее, чем вручную писать каждый раз if-else или #ifdef ТАКОЙ_ТО_ТИП_ДЕВАЙСА).

 

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

 

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


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

 

Проблемы с 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-файл, с которым вы сделали как я советую, то обычно всё в порядке будет и в заголовочном файле.

 

Прошёл сегодня первый тест по C++ на сайте www.odesk.com


Прошёл сегодня свой первый тест по C++ на сайте www.odesk.com. Результаты получил не самые впечатляющие. Но есть надежда, что через месяц я сдам такой же тест лучше. Думаю, что такая система позволяет измерить уровень подготовки программиста в той или иной области. Вот что мне выдала система:

Passing Score: 2.50      Your Score: 2.75      Grade: Pass


Results by Topic

     Topic         Correct Answers(%)
1.     Classes                       57%
2.     Constructors and Destructors                       86%
3.     Exceptions and Exception Handling                       0%
4.     Functions and Virtual Functions                       75%
5.     Inheritance and Object Oriented Concepts                       67%
6.     Miscellaneous                       0%
7.     Operator Overloading                       75%
8.     Pointers and File Handling                       0%
9.     Standard Template Library, Directives and Macros                       50%
10.     Syntax and Language Fundamentals                       40%

Congratulations!!

By passing this test, you have joined the elite league of individuals who have demonstrated a high level of proficiency in their chosen area.

1 |2 |3 |4 |5

     
ЯнварьФевральМартАпрельМайИюньИюльАвгустСентябрьОктябрьНоябрь (82)Декабрь
           
123456789101112131415161718192021222324252627282930