Показаны сообщения с ярлыком programming. Показать все сообщения
Показаны сообщения с ярлыком programming. Показать все сообщения

1 сент. 2016 г.

Objectve C: немножно макросов для облегчения имплементации протокола NSCoding

Для поддержки протокола NSCoding в Objective C класс должен реализовать два метода для (де)сериализации каждого поля объекта. Ниже привожу набор макросов, которые упрощают этот процесс:

In order to support NSCoding protocol in Objective C class must implement 2 methods to (de)serialize every object's field. Below is set of macro to make it little easy:


#define encObj(__name__) {if(__name__) {[aCoder encodeObject:__name__ forKey:@#__name__];} }
#define encPoint(__name__) [aCoder encodeCGPoint:__name__ forKey:@#__name__];
#define encSize(__name__) [aCoder encodeCGSize:__name__ forKey:@#__name__];

#define encInt(__name__) [aCoder encodeInt:__name__ forKey:@#__name__];
#define encFloat(__name__) [aCoder encodeFloat:__name__ forKey:@#__name__];
#define encDouble(__name__) [aCoder encodeDouble:__name__ forKey:@#__name__];
#define encBool(__name__) [aCoder encodeBool:__name__ forKey:@#__name__];

////////////////////
////////////////////
#define decObj(__name__) __name__ = [[aDecoder decodeObjectForKey:@#__name__] retain];
#define decInt(__name__) __name__ = [aDecoder decodeIntForKey:@#__name__];
#define decFloat(__name__) __name__ = [aDecoder decodeFloatForKey:@#__name__];
#define decDouble(__name__) __name__ = [aDecoder decodeDoubleForKey:@#__name__];
#define decBool(__name__) __name__ = [aDecoder decodeBoolForKey:@#__name__];
#define decPoint(__name__) __name__ = [aDecoder decodeCGPointForKey:@#__name__];
#define decSize(__name__) __name__ = [aDecoder decodeCGSizeForKey:@#__name__];

24 мая 2016 г.

Знания, как расходный материал

Намедни возникла мысль, которая еще не полностью сформировалась, но что-то в ней есть. Не уверен, что это относится к другим профессиям, потому мысль относится к сфере IT. А точнее к разработчикам. Работая над каким-то проектом разработчик все глубже погружается в используемые в нем инструменты, технологии, языки. И чем дольше он занимается этим проектом, тем более узким, или наверное точнее будет сказать заточенным, становится набор его умений. Он не забывает окончательно все, что знал до этого. Основы других языков и областей, общие какие-то принципы и понятия, названия и назначения инструментов, которые не используются в текущем проекте. Однако у него уже не получится просто взять и переключиться на другой, забытый или еще незнакомый инструмент. Особенно вне рамок текущего проекта. Уйдет время на отвыкание от приобретенных привычек и рефлексов, на чтение, пробы, обучение новому.
Возникает аналогия с амортизацией, финансовые и временные расходы на которую необходимо учитывать при использовании автомобиля или любой другой техники. Чем активнее используется, скажем, автомобиль, чем более неровные дороги он покрывает надрывая двигатель, тем дороже и дольше обойдется его ремонт и восстановление. А рано или поздно это придется делать. Или менять его на новый автомобиль. Можно, конечно, делать текущий Т/О достаточно часто, чтобы предотвратить критические поломки. Но это связано с дополнительными затратами на транспортировку к месту ТО, на сам осмотр и т.д. В случае программиста чем дольше он занят на одном проекте, и чем глубже он в него погружен и, соответственно, не имеет возможности отвлечься на развитие в других направлениях, тем больше он упускает новинок. И тем больше ему придется наверстывать, когда по той или иной причине ему таки придется уйти из проекта. Как и в случае с периодическим техосмотром авто программист может (и должен) иногда переключаться на другие активности и направления. Однако, как и в случае с авто, это связано с последующими временными затратами на восстановление "потока" в текущем проекте. Ну и на дорогу туда-сюда. И стоимость этого периода наверстывания так же должен быть включен в стоимость текущей эксплуатации знаний программиста, чтобы потом компенсировать месяц, полгода, год, которые уйдут на разгребание навалившихся новых фреймворков, технологий, версий операционок и языков.

29 мар. 2016 г.

Unicode последовательности и NSString. Unicode composed sequence and NSString.

Завязался с оперированием эмотиконками из набора Unicode символов строке NSString. Одна из сложностей с Unicode в том, что он бывает не только UTF-8, но и UTF-16, и UTF-32. В данном случае стояла задача удаления последней эмотиконки из строки текста. Посимвольное удаление не работает, поскольку даже при том, что для этих значков используется UTF-32 (то есть длина символа понятна — 4 байта), существую так называемые Композиционные последовательности Unicode (вольный перевод). Например, такой неоднозначный значок как "👨‍👨‍👦‍👦"(Family: MAN, MAN, BOY, BOY) состоит из 7 символов: U+1F468 U+200D U+1F468 U+200D U+1F466 U+200D U+1F466. Соответственно, чтобы удалить одну иконку, нужно удалять до 7 символов. Причем от иконки к иконке их количество меняется. У NSString для этих случаев есть набор методов для работы с такими последовательностями. Они описываются в статье "NSString and Unicode", поэтому их все я тут описывать не буду. Конкретная задача удаления последней иконки, вне зависимости от количества составляющих ее Unicode символов была решена так:

NSRange rng = [str rangeOfComposedCharacterSequenceAtIndex:[str length]-1];
        str = [str substringToIndex:rng.location];

В частности, здесь использован метод rangeOfComposedCharacterSequenceAtIndex, который возвращает NSRange, указывающий на первый символ последовательности и на длину самой последовательности. Дальнейшее оперирование производится как с обычными символами.

31 янв. 2016 г.

Почему так мало людей становятся программистами?

В дополнение к статье "Не будите спящего программиста" хочется зафиксировать еще одну статейку, правда на английском. Это ответ на вопрос на сервисе Quora: "Why Don't More People Work As Programmers?" Поскольку подобные сервисы грешат всякими пропаданиями, зафиксирую ее копипастом здесь. В кратком изложении заметка рассказывает о том, что быть программистом (от себя добавлю, что описание может касаться и некоторых други Software специальностей типа DevOps и QA), нужно постоянно учиться чему-то новому, постоянно соревноваться с новичками, которые знают меньше, но готовы пыхтеть ночами, говнокодить, использовать кучу лишних костылей и велосипедов, постоянно нужно быть в курсе новых технологий, веяний, языков, инструментов... И к тому же, нужно учиться создавать продукты во все более узких рамках и короткие сроки. Постоянно. Бесконечно. Далеко не все могут, хотят, готовы на такие темпы.

Becoming a good programmer is incredibly difficult and it doesn't happen quickly.

We can't expect to plant some trees and have 2000-year-old redwoods grow overnight, regardless of the demand for them.


Personality traits

  • One basically has to be an autodidact to learn programming. It takes years of practice to learn everything necessary to get beyond just a basic level where you can write short programs that work. No one has ever become a great programmer just by taking classes or reading books. It takes hours of practice. And contrary to popular belief, CS programs do not teach programming. CS programs teach theory.
  • As a programmer you need to have nearly unlimited persistence to continue trying to troubleshoot, fix, and develop things. It takes a special person to persist this much, especially when it often seems like you're not making any progress. This is pretty much a personality trait, and not having this level of persistence is enough to turn off most people who don't have it from the profession.
  • You need to be exceptional at math and problem solving. Programming is a LOT of problem solving.
  • You need to have an excellent short term (and long term) memory so that you can juggle multiple things in your head simultaneously, and remember what you wrote a month ago.
  • You need to have a great understanding of how things interrelate and how to design good architecture. If I change this little thing here, what might I be breaking elsewhere?
  • You need to have incredible attention to detail. Close doesn't cut it in programming. Forget a semicolon somewhere? Program isn't going to compile! Misspell a function name? Your program could be doing something completely different than you anticipated.


Not having these personality traits is enough to weed out most people.



Subject Matter

  • You need to have a strong understanding of data structures and classes and know when and how to use them.
  • You need to have some familiarity with libraries that have already been developed so that you don't have to reinvent the wheel.
  • You need to have familiarity with a lot of basic (and advanced) algorithms, again so that you don't have to reinvent the wheel.
  • Often you need to know the limits of the hardware that you're working with so that you can do things like managing memory properly and avoiding running out of it, or utilizing your memory properly to eliminate wasted transfer of data within the processor and speed up processing.
  • So you can program. Great! But do you know anything about packet structure, TCP/IP, HTML, CSS, user interface design, or databases? Programs don't run in isolation.
  • There's a ton of stuff you need to know, and it keeps changing! It's not something you can be truly great at unless it's your main focus. You can't be a "weekend programmer."



Work/Life Environment

  • You need to have long blocks of uninterrupted time so that you don't lose your concentration when you're programming (and learning to program). Many work (and home) environments struggle to offer this. Phone rings? Great, it's going to take you 15 minutes to regain your train of thought.
  • You often have to make decisions about tradeoffs on the fly. Sure, you could write a program that could handle every single case, but how often is someone really going to put in "zero" as an input? Besides, we're behind schedule, and it's more important to get something up and running right now.
  • On top of all this, the language that you thought was the next big thing was a passing fad and nobody is using it 5 years later. Now you're on to the next cool language, which might not be used 5 years from now. You constantly have to stay on top of things.



On top of that there are the management aspects.

Programmers are often treated like factory workers. People with no programming talent (and less business sense) are often in charge of projects. They think programmers are cogs in the machines. The truth is programmers are artisans and to get the best results from a project the wise thing to do would be to ask the people who are experts at programming how things should be done! Just about every project ends up being over budget and behind schedule, forcing programmers to work tons of uncompensated and unappreciated overtime to deliver a poorly-designed and poorly-tested product. The great programmers realize that they're not being paid more than the crappy programmers because management can't tell the difference - and on top of that, they're doing extra work to compensate for other programmers being below-par. And great programmers who speak up and try to change things for the better are often intimidating to managers, who often try to get rid of them (which is a general employment trend discussed in other posts). Enough of this and it's easy to see why good people get fed up with the profession - especially since there are plenty of other opportunities. People who are even average programmers, as long as they're reasonably good at dealing with people, have enough skills to be successful in a variety of other professions. Programming is something that can be easily transferred out of, but not into.


Good programmers are probably less likely to be randomly looking for work.

It's easy to find programmers. It's hard to find good programmers. The crappy programmers are probably perpetually looking for work. The good programmers, if a company realizes that they're good, should do whatever it takes to hang on to them, so they're probably looking for work a lot less often. And when they do they're choosy about where they want to work - which would explain why many companies claim "there are no good programmers available - all we can find are crappy ones." As has been said elsewhere, a good programmer can certainly be worth several times what an average programmer is worth, and a crappy programmer can actually have negative value. And it's really tough (if not impossible) for crappy and average programmers to turn into good ones - and certainly not worth the investment for any startup to try to undertake when they're supposed to be focused on developing something quickly and getting it out the door.

3 нояб. 2015 г.

Оповещение снятия скришота с экрана приложения в iOS

Наткнулся на оповещение UIApplicationUserDidTakeScreenshotNotification, которое приходит от NSNotificationCenter когда пользователь нажал кнопку Home + Power. Приходит оповещение постфактум, но это и логично — чтобы приложение не могло запретить пользователю делать скриншоты. Ютуб бы этим очень стал пользоваться.

1
2
3
4
5
6
7
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationUserDidTakeScreenshotNotification
                                                  object:nil
                                                   queue:mainQueue
                                              usingBlock:^(NSNotification *note) {
                                                 // executes after screenshot
                                              }];

Android предлагает похожее решение:


1
NotificationCenter.getInstance().addObserver(this, NotificationCenter.screenshotTook);

23 дек. 2013 г.

iOS рзаработка: зачем тестировать приложения на таргет-устройствах?! Есть же симулятор!

Решил сохранить цитаты из App Distribution Guide:

If you have an iOS app, make sure you test it not only in iOS Simulator but on all the devices and releases that your app supports. Testing on more than one kind of device ensures that your app operates exactly as you thought it would, no matter which device it’s running on. 
и из раздела "Beta Testing Your iOS App" 
Important: Rigorously test your app on a variety of devices and iOS versions. Because different kinds of devices and iOS releases have different capabilities, it’s not sufficient to test your app on a device provisioned for development or the simulator. iOS Simulator doesn’t run all threads that run on devices, and launching apps on devices through Xcode disables some of the watchdog timers. At a minimum, test the app on all devices you support and have available. In addition, keep prior versions of iOS installed on devices for compatibility testing. If you don’t support certain devices or iOS versions, indicate this in the project target settings in Xcode, as described in “Setting Deployment Info.” 
, чтобы ссылаться на них в случае возникновения вопросов у заказчика/работодателя по поводу ненадобности хардварных тестовых устройств. 

15 дек. 2013 г.

Генератор ссылок на iTunes от авторов iTunes

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

2 дек. 2013 г.

Tips: Размеры некоторых элементов экрана iPhone/iPad

CGRect rect;

// Get screen dimensions
rect = [[UIScreen mainScreenbounds];
NSLog(@"Bounds: %@", NSStringFromCGRect(rect));

// Get application frame dimensions (basically screen - status bar)
rect = [[UIScreen mainScreenapplicationFrame];
NSLog(@"App Frame: %@"NSStringFromCGRect(rect));

// Get status bar frame dimensions
rect = [[UIApplication sharedApplicationstatusBarFrame];
NSLog(@"Statusbar frame: %@"NSStringFromCGRect(rect));

10 нояб. 2013 г.

Однострочники: Макрос получения локализированных строк

Простой Objective-C-макрос для получения строковых ресурсов в зависимости от дефолтной локали
#define LOC(__key__) [[NSBundle mainBundle] localizedStringForKey:(__key__) value:nil table:nil] 

7 нояб. 2013 г.

5 нояб. 2013 г.

Bzzzer - скромный напоминатель

Выложил в Аппстор свою программу под названием Bzzzer. Функционал программы прост. После нажатия кнопки Start Bzzzer воспроизводит выбранный звук с выбранной же периодичностью. Периодичность предоставлена набором из 5, 10, 15 или 30 минут.
Однако смысл программы гораздо глубже, чем может показаться! Когда человек занимается каким-то увлекательным, а возможно совсем не увлекательным и рутинным, делом (листание какого-нибудь агрегатора фан-контента, чтение, рисование, программирование), легко забыть про течение времени. Но вместе с тем, не всегда есть возможность или желание отвлекаться, чтобы посмотреть на часы, вспомнить когда ты последний раз засекал время, сколько прошло с тех пор... Bzzzer ненавязчиво напоминает, что прошло пять минут. Или тридцать. И не отвлекаясь от работы ты отмечаешь, что с момента пуска Bzzzer прошло около 2 часов. Надо бы встать, размяться, подышать воздухом.
Таким образом Bzzzer скромно напоминает, что время уходит, что нужно подсуетиться и успеть больше.
Сам я Базззера пользую уже около 3 лет. Всегда очень помогает держать себя в рамках времени и при этом не просыпаться :)

Так что, welcome, как говорится.


21 сент. 2013 г.

iOS 6.1 standard fonts list

Стндартный набор шрифтов из iOS 6.1

AcademyEngravedLetPlain,
AmericanTypewriter,
AmericanTypewriter-Bold,
AmericanTypewriter-Condensed,
AmericanTypewriter-CondensedBold,
AmericanTypewriter-CondensedLight,
AmericanTypewriter-Light,
AppleColorEmoji,
AppleSDGothicNeo-Bold,
AppleSDGothicNeo-Medium,
Arial-BoldItalicMT,
Arial-BoldMT,
Arial-ItalicMT,
ArialHebrew,
ArialHebrew-Bold,
ArialMT,
ArialRoundedMTBold,
Avenir-Black,
Avenir-BlackOblique,
Avenir-Book,
Avenir-BookOblique,
Avenir-Heavy,
Avenir-HeavyOblique,
Avenir-Light,
Avenir-LightOblique,
Avenir-Medium,
Avenir-MediumOblique,
Avenir-Oblique,
Avenir-Roman,
AvenirNext-Bold,
AvenirNext-BoldItalic,
AvenirNext-DemiBold,
AvenirNext-DemiBoldItalic,
AvenirNext-Heavy,
AvenirNext-HeavyItalic,
AvenirNext-Italic,
AvenirNext-Medium,
AvenirNext-MediumItalic,
AvenirNext-Regular,
AvenirNext-UltraLight,
AvenirNext-UltraLightItalic,
AvenirNextCondensed-Bold,
AvenirNextCondensed-BoldItalic,
AvenirNextCondensed-DemiBold,
AvenirNextCondensed-DemiBoldItalic,
AvenirNextCondensed-Heavy,
AvenirNextCondensed-HeavyItalic,
AvenirNextCondensed-Italic,
AvenirNextCondensed-Medium,
AvenirNextCondensed-MediumItalic,
AvenirNextCondensed-Regular,
AvenirNextCondensed-UltraLight,
AvenirNextCondensed-UltraLightItalic,
BanglaSangamMN,
BanglaSangamMN-Bold,
Baskerville,
Baskerville-Bold,
Baskerville-BoldItalic,
Baskerville-Italic,
Baskerville-SemiBold,
Baskerville-SemiBoldItalic,
BodoniOrnamentsITCTT,
BodoniSvtyTwoITCTT-Bold,
BodoniSvtyTwoITCTT-Book,
BodoniSvtyTwoITCTT-BookIta,
BodoniSvtyTwoOSITCTT-Bold,
BodoniSvtyTwoOSITCTT-Book,
BodoniSvtyTwoOSITCTT-BookIt,
BodoniSvtyTwoSCITCTT-Book
BradleyHandITCTT-Bold,
ChalkboardSE-Bold,
ChalkboardSE-Light,
ChalkboardSE-Regular,
Chalkduster,
Cochin,
Cochin-Bold,
Cochin-BoldItalic,
Cochin-Italic,
Copperplate,
Copperplate-Bold,
Copperplate-Light,
Courier,
Courier-Bold,
Courier-BoldOblique,
Courier-Oblique,
CourierNewPS-BoldItalicMT,
CourierNewPS-BoldMT,
CourierNewPS-ItalicMT,
CourierNewPSMT,
DevanagariSangamMN,
DevanagariSangamMN-Bold,
Didot,
Didot-Bold,
Didot-Italic,
EuphemiaUCAS,
EuphemiaUCAS-Bold,
EuphemiaUCAS-Italic,
Futura-CondensedExtraBold,
Futura-CondensedMedium,
Futura-Medium,
Futura-MediumItalic,
GeezaPro,
GeezaPro-Bold,
Georgia,
Georgia-Bold,
Georgia-BoldItalic,
Georgia-Italic,
GillSans,
GillSans-Bold,
GillSans-BoldItalic,
GillSans-Italic,
GillSans-Light,
GillSans-LightItalic,
GujaratiSangamMN,
GujaratiSangamMN-Bold,
GurmukhiMN,
GurmukhiMN-Bold,
Helvetica,
Helvetica-Bold,
Helvetica-BoldOblique,
Helvetica-Light,
Helvetica-LightOblique,
Helvetica-Oblique,
HelveticaNeue,
HelveticaNeue-Bold,
HelveticaNeue-BoldItalic,
HelveticaNeue-CondensedBlack,
HelveticaNeue-CondensedBold,
HelveticaNeue-Italic,
HelveticaNeue-Light,
HelveticaNeue-LightItalic,
HelveticaNeue-Medium,
HelveticaNeue-UltraLight,
HelveticaNeue-UltraLightItalic,
HiraKakuProN-W3,
HiraKakuProN-W6,
HiraMinProN-W3,
HiraMinProN-W6,
HoeflerText-Black,
HoeflerText-BlackItalic,
HoeflerText-Italic,
HoeflerText-Regular,
Kailasa,
Kailasa-Bold,
KannadaSangamMN,
KannadaSangamMN-Bold,
MalayalamSangamMN,
MalayalamSangamMN-Bold,
Marion-Bold,
Marion-Italic,
Marion-Regular,
MarkerFelt-Thin,
MarkerFelt-Wide,
Noteworthy-Bold,
Noteworthy-Light,
Optima-Bold,
Optima-BoldItalic,
Optima-ExtraBlack,
Optima-Italic,
Optima-Regular,
OriyaSangamMN,
OriyaSangamMN-Bold,
Palatino-Bold,
Palatino-BoldItalic,
Palatino-Italic,
Palatino-Roman,
Papyrus,
Papyrus-Condensed,
PartyLetPlain,
STHeitiSC-Light,
STHeitiSC-Medium,
STHeitiTC-Light,
STHeitiTC-Medium,
SinhalaSangamMN,
SinhalaSangamMN-Bold,
SnellRoundhand,
SnellRoundhand-Black,
SnellRoundhand-Bold,
Symbol,
TamilSangamMN,
TamilSangamMN-Bold,
TeluguSangamMN,
TeluguSangamMN-Bold,
Thonburi,
Thonburi-Bold,
TimesNewRomanPS-BoldItalicMT,
TimesNewRomanPS-BoldMT,
TimesNewRomanPS-ItalicMT,
TimesNewRomanPSMT,
Trebuchet-BoldItalic,
TrebuchetMS,
TrebuchetMS-Bold,
TrebuchetMS-Italic,
Verdana,
Verdana-Bold,
Verdana-BoldItalic,
Verdana-Italic,
ZapfDingbatsITC,
Zapfino

25 мая 2013 г.

Шпаргалка по разработке Objective-C приложений

Вольный... Нет. Очень вольный перевод статьи Стюарта Холла "iOS Development Tips I Would Want If I Was Starting Out Today" (Шпаргалка по iOS разработке, которую я хотел бы иметь, если бы начинал разрабатывать сегодня).

Программирование под iOS становится легче с каждым релизом Xcode. И каждая новая фича увеличивает количество вариантов выбора. 
В мои годы (запах плесени) было гораздо тяжелее! Это так. Но сейчас предъявляют все более высокие требования к качеству. Планка качества постоянно растет. И это хорошо.
И доведись мне начинать свое знакомство с iOS-разработкой сегодня, я бы сильно хотел, чтобы мне кто-то дал почитать этот текст. Надеюсь он кому-то поможет.

Используйте ARC!

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

Тулим блоки где только можно

Блоки похожи на ARC. По крайней мере в том, что блоки — это тоже замечательно. Используя блок ты пишешь меньше кода, и он значительно лучше, чем раньше. Меньше кода == меньше багов. Вот тут - классное введение к использованию блоков (ахтунг - тут и далее много нерусских букв - прим. переводчика). 
NSNotifications и _delegate/@protocol все еще на коне. Но сначала подумайте о блоках, а потом уже — про Акима

Опасносте детектед! Retain Cycles в Блоках

Тут тема разжована. Кратко: retain cycles, это когда два объекта (будь-то блок, таймер или вездесущий self) ретейнят друг друга и не могут со спокойной душой отойти в мир иной и устраивают утечку памяти. С блоками такое легко подхватить.

Потоки? Не, не слышал. Пользуй GCD

"Был у дева головняк. Он решил заюзать thread. Головняк теперь двояк."
GCD облегчает нам жизнь. Он — наш друг. Только не забудьте вернуться в главный поток, если делаете что-то с UI.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
    // Your code
    dispatch_async(dispatch_get_main_queue(), ^(void) {
        // Now you can interact with the UI
    });
});
Хорошее объяснение GCD можно найти хере

Singletons / Shared Objects

В продолжение о GCD. Он помогает забыть про ручное выпиливание синглтона:
    + (MyClass *)sharedClass {
static MyClass *_shared = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    _shared = [[MyClass alloc] init];
});   
return _shared;
}
Все! Боле ничего не нужно. А зацените, сколько весит NSDateFormatter и его создание при каждом обращении! Хороший повод засунуть его в синглтон.

Story Boards — только для быстрых прототипов

ИМХО, со Story Boards больше геморроя, чем пользы. Но это мое мнение. Многие любят их. Решите сами.

XIBы — только для базовых набросков

У Interface Builder столько "низзя", что проще собрать нужную вьюшку в рантайме. К тому же, мержинг двух версий XIB-файла — тот еще трюк, который обычно никто и не делает. Гораздо проще смержить два сорца.
Можно что-то набросать базовое. Но ровнять все равно лучше в коде.

Держите свой проект упорядоченным

Я подзавязал с Ruby on Rails. Но организация проекта мне понравилась. Я так организую свои проекты в Xcode:
Xcode structure
Чистота — залог здоровья!

Присмотритесь к Open Source

Существует множество бесплатных опенсорсных библиотек и компонент. Github забит выдающимися сорцами, который можно просто кинуть в свой проект и пользовать их. Кроме того есть Cocoa Controls. Там тоже полно вкусняшек.
Некоторые либы я включаю почти в каждый свой проект:
Если вы гуглите какой-то модуль, он скорее всего уже тут есть. Ну, по крайней мере что-то похожее.

Управление зависимостями проекта

Чтобы управляться с набором либ, подключенных к проекту, рекомендую пользовать CocoaPods. Этот инструмент делает amazing job. Прямо как Ruby's gems.
Или можете просто использовать отдельные модули.

Попробуйте полюбить Stack Overflow

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

Элегантная деградация

Зачастую хочется использовать свежие фичи новых версий iOS. Но девайсы со старой версией iOS все еще в ходу, и фишки типа  Tweet Sheets в iOS 5, SKStoreProductViewController & UIActivityViewController в iOS 6 приходится поддерживать и для более взрослых версий.
В этом нам поможет не Бахметьев, а проверка существования класса в рантайме:
if (NSClassFromString(@"SKStoreProductViewController")) {
// Класс существует, значит мы в iOS 6+
    SKStoreProductViewController *storeController = [[SKStoreProductViewController alloc] init];
….
}
else {
    // Нет такого класса - значит мы на старом корыте
}

Кастомные шрифты

В прежних версиях iOS (lj 3.2) это была жопа. Поэтому все использовали штатную Helvetica. Но теперь все стало шикарно!
Тутe — краткое описание. Если непонятно как называется шрифт, загляните в Font Book и посмотрите PostScript-имя шрифта.

Локализация должна начинаться до проекта

Локализация реализуется с помощью Xcode очень просто. Особенно, если не использовать xib-файлы. Но легкость локализации проекта в самом начале пропорциональна сложности локализации уже существующего проекта.
Это — замечательный пример локализации приложения под iPhone.

Отслеживайте краши

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

Analyze

Инструмент Product -> Analyze должен стать вашим другом. Статические анализаторы — мощное орудие в борьбе с Хейзенбергом.

Instruments

Product -> Profile билдит приложение и запускает Instruments. Instruments — коллекция инструментов (внезапно) проверки вашего приложения. Во-первых стоит взглянуть на "Time Profiler", который покажет сколько процессорного времени занимает ваше приложение. Если ваша табличка скроллится как растекшееся масло, скорее всего она потреблят слишком много процессорного времени.
Instruments

Отслеживайте обзоры

<без ложной скромности>Баги были, есть и будут. Никуда от них не деться. И в отзывах они будут упомянуты. И будут вести они к плохим обзорам. В том числе от юзверей из стран, про которые вы даже не слышали. Не игнорируйте их. Обрабатывайте и получайте их с помощью AppBot. </без ложной скромности>
Уверен, что забыл кучу полезных советов. Да и не все мои советы будут приняты единогласно. Но буде единая заблудшая душа спасена сим постом, буду считать свою миссию выполненной.

17 мар. 2013 г.

Objective-C: однострочник для логгирования CGRect

Периодически приходится выводить в лог размер и положение какого-то контрола. Может даже двух. А то и вовсе трех. Сваял вот такой макрос для более удобного логгирования. Кстати, подумалось, что из-за используемого #x этот макрос сложно реализовать в виде функции. Обработка передаваемого параметра как строки, насколько я знаю, фишка именно препроцессора C/C++ сотоварищи.

#define LOGRect(x) NSLog(@"Logging Rect %s: %@", (#x), NSStringFromCGRect(x))

21 янв. 2013 г.

Небольшая шутка в Apple-документации

В обычно сухой и строгой документации от Apple написано: "Они могут содержать любые объекты, и эти объекты могут быль любого типа. Объект NSArray может содержать, например, кошек, собак, вомбатов и их комбинации."

29 окт. 2012 г.

Objective-C. Макрос-оболочка к NSLog

Последнее время использую такой макрос, оборачивающий штатный NSLog в Objective-C:
#ifndef DLog
#ifdef DEBUG
#define DLog(_format_, ...) NSLog([NSString stringWithFormat:@"%s: %@", __PRETTY_FUNCTION__, (_format_)], ## __VA_ARGS__)
#else
#define DLog(_format_, ...)
#endif
#endif
Он автоматом добавляет к строке лога имя функции и номер строки в исходнике. Ну и заодно можно отключить логи одним андефайном. Заменить, например #ifdef DEBUG на #ifdef DEBUG1

UPD 2015-01-07:
Макрос постепенно перерос вот в такое:

#ifdef DEBUG
#define DLog( s, ... ) NSLog( @"%@%s:(%d)> %@", [[self class] description], __PRETTY_FUNCTION__ , __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#define DAssert(A, B, ...) NSAssert(A, B, ##__VA_ARGS__);
#define DLogv( var ) NSLog( @"%@%s:(%d)> "# var "=%@", [[self class] description], __PRETTY_FUNCTION__ , __LINE__, var ] )
#elif DEBUG_PROD
#define DLog( s, ... ) NSLog( @"%@%s:(%d)> %@", [[self class] description], __PRETTY_FUNCTION__ , __LINE__, [NSString stringWithFormat:(s), ##__VA_ARGS__] )
#define DLogv( var ) NSLog( @"%@%s:(%d)> "# var "=%@", [[self class] description], __PRETTY_FUNCTION__ , __LINE__, var ] )
#define DAssert(A, B, ...) NSAssert(A, B, ##__VA_ARGS__);
#else
#define DLog( s, ... )
#define DAssert(...)
#define DLogv(...)
#endif
Интересно отметить: наткнулся в сети на вопрос почему именно _DLog_, а не, скажем, ALog, MLog?.. Оказывается, что в используемых на данный момент в Xcode фреймворках нет классов, начинающихся с DL. Потому это относительно безопасный префикс для избежания перекрытия классов.

3 июл. 2012 г.

Программистский боян

Сказка старая, но от этого не менее актуальная (взято на просторах ФИДО):

Русский, Китайцы, Канадец и индус 

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

А в это время, в соседних четырех кубиках, будет ни на секунду не утихать работа китайских программистов, непостижимым образом умудряющихся прийти раньше русского программиста, уйти позже, и при этом сделать примерно втрое меньше. Эта четверка давно не пишет ничего нового, а только поддерживает код, написанный в свое время индусом, и дважды переписанный двумя разными русскими. В этом коде не просто живут баги. Здесь их гнездо. Это гнездо постоянно воспроизводит себя при помощи любимой китайской технологии реиспользования кода - copy/paste. Отсюда баги расползаются в разные стороны посредством статических переменных и переменных, переданных по ссылке (ведь, китайский программист не может смириться с неудобствами вызванными тем, что он не может изменить значение внешнего параметра). Вспоминая об этих переменных и ссылках, русский программист, как правило, на время теряет дар английской речи, и переходит к какой-то помеси русского и китайского. Он давно мечтает переписать весь кусок, над которым работают китайцы, но у него нет времени. Он уже переписывает два больших куска, и доказал начальству необходимость переписать третий. Кроме того, русский программист боится обидеть китайцев. Они могут решить, что он пытается вытеснить их с работы. К слову сказать, напрасно боится, поскольку китайцы уже так решили. 

Hа китайцах висят серьезные баги, о которых знает начальство и постоянно их торопит. Китайцы уважают начальство и потому перевешивают баги друг на друга очень торопливо. Они знают, что все попытки починить приведут к появлению новых багов, еще худших. И в этом они правы. Разобраться в том, в каком порядке меняются статические переменные, и как приобретают свои значения, способен только один человек на фирме - индус. Hо он пребывает в медитации. Поэтому, когда всю четверку уволят во время сокращения... А кого еще увольнять? Русский - еще не переписал свой кусок, а индус - главная ценность фирмы - он редко обращает внимание на проект, но когда обращает, все понимают, что так как он, архитектуру никто не знает. Так вот, когда китайцев увольняют, у их кода возможны две основные судьбы. Первая - он попадет к русским, и его перепишут. Вторая - он попадет к местному, канадскому программисту. 

О, канадский программист это особый тип. Он, ни на минуту не задумываясь, как рыцарь без страха и упрека, бросится фиксить самый свирепый баг китайского кода. Этот Баг живет там уже три года, и китайцы уже четырежды (каждый по разу) сообщали начальству, что он пофиксен. Hо Баг каждый раз возвращался, как Бетмен в свой Готхем. Итак, канадский программист, воспитанный на героической патетике американского футбола - бросаться в бой головой вперед, сделает то, чего китайцы не рисковали делать в течении трех долгих лет. Он, при помощи дебагера, отследит место, где статическая переменная приняла значение -1 вместо правильного 0, и решительным движением заведет рядом вторую переменную с правильным значением. Баг погибнет в неравной схватке с героем. Hо победа будет достигнута тяжелой ценой. Работать перестанет все, включая только что переписанный русским программистом код. Это повергнет русского программиста в задумчивость на целых два дня, после чего он сделает, в общем-то, предсказуемый вывод о том, что дизайн с самого начала был неправильным, и все надо переписать. Hа это нам нужна неделя. Да, неделя, не больше. Канадский программист смело бросится налаживать все, и станет еще хуже, хотя казалось бы... Эта суета выведет из медитации индуса, который придумает и вовсе гениальное решение - отбранчить код. Согласно его плану, мы теперь будем поддерживать две версии одного и того же кода - одну работающую, но с Багом, другую без Бага, но не работающую. Русский программист, услышав об этом плане, сломает линейку об стол и обзовет жену дурой, но на митинге возразить не решится. 

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

29 июн. 2012 г.

Tips and tricks in Xcode.

    Дорвался до видео с WWDC 2012. Видео бесплатны, в хорошем качестве, с субтитрами. Но и без субтитров все понятно - язык технический. Первое из-за чего проспал на работу - сессия по советам работы с Xcode (про Delphi и Visual Studio умолчали). Выступали три инженера. Лиц на видео не показывали, поэтому выдержана ли была политкорректность - не знаю. Но два голоса были мужские и один, кажется, женский. Описывались три схемы работы с IDE: однооконная, с несколькими закладками и многооконная. Хинты, показанные на сессии удобны для всех схем работы. Главный тезис, звучавший сквозь всю сессию, - хоткеи, хоткеи и еще раз автоматизация!
    ИтаГ, какие хоткеи я вынес для себя из просмотра видео:

  • Cmd+Shift+{ напару с Cmd+Shift+} - переключение между закладками приложения (я и раньше эти хоткеи пользовал, но пришлись к столу)
  • Ctrl-Cmd-E - позволяет редактировать идентификатор, на котором установлен текстовый курсор, одновременно со всеми его упоминания в его области видимости (функция, цикл, блок...).
  • Cmd-J - открывает декоративное окошко выбора панели IDE, в которое нужно поместить фокус ввода. В принципе, есть комбинация Cmd-Opt-., которая переключает циклично этот фокус по панелям окна, но про нее почему-то скромно умолчали
  • Мышинный Opt-Click или клавиатурный Cmd-Ctrl-Shift-/ - отобразить всплывающую подсказку по объекту клика. Причем не просто тип, а довольно объемный талмуд 
  • Cmd-Option-[ - переместить текущую строку текста вниз 
  • Cmd-Option-] - переместить текущую строку текста вверх (этих двух я сам нашел - иногда полезно) 
  • Cmd-Shift-O - удобная фича (почти мега-) быстрый поиск идентификатора сквозняком по проекту во всплывающем окошке. После выбора подходящей строки Return открывает соответствующий файл в текущем окне редактора, Opt-Return открывает декоративное окошко, в котором можно выбрать куда поместить файл, Opt-Shift-Return открывает файл во второстепенном редакторе (вертикальное окно рядом с основным).
  • Cmd-Opt-Return - открывает файл объявления идентификатора над текстовом курсором во второстепенном редакторе
  • Cmd-Return - закрывает окно второстепенного редактора.
  • Cmd+Opt+Click (Cmd-Ctrl-Opt-J) - открывает объявление идентификатора в главном редакторе
  • Cmd+Opt+2Click - открывает объявление идентификатора в новом окне. Вообще, двойной клик в Xcode в основном приводит к открытию нового окна
  • Cmd-T - дублирует текущую закладку в новую со всеми текущими настройками
  • Cmd-E - поместить выделенный текст в поле поиска (и в окне редактора, и в окне навигатора проекта). При этом выделенный текст уже считается результатом поиска и можно использовать следующую комбинацию:
  • Cmd-G - перемещаться между результатами поиска в текущем окне
  • Opt-Return в форме поиска в окне редактора - замена в выделенном тексте
  • Двойной клик по скобке выделяет содержимое всего блока внотри пары скобок 
  • Комментарии, предваренные текстом TODO: и FIXME: работают так же, как #pragma mark, то бишь отображаются в списке методов вверху окна редактора
  • При открытом списке этих самых методов можно вводить текст, который будет фильтровать список.
Пара хоткеев от меня - странно, что их не упомянули на сессии:

  • Cmd-Ctrl-D - отобразить словарную карточку слова над текстовым курсором. Имена сущностей должны соответствовать их назначению и писаться орфографически правильно. Фишка эта общекокошная, но и в Xcode ее игнорировать не стоит.
  • Cmd-Ctrl-Down - открыть counterpart (связанный с текущим файл - заголовок или имплементацию)
  • Cmd-Shift-J - отбразить текущий файл в Project Navigator.


    На другом видео рассказывали про навороченность работы Xcode с системами контроля версий - SVN и Git. Работа с репозиториями находится в соответствующем разделе Organizer. Commit, Add и проче команды находятся в меню File/Source Control. Режимы просмотра логов, конфликтов и merging-а переключаются в правом верхнем наборе пиктограмок. Внизу навигатора проекта имеется пиктограммка с хинтом "Show only files with source-control status". Она заставляет навигатор показывать только те файлы, которые каким-то образом отмечены в рабочей версии - A, M, C и т.д. Инструменты для работы с контролем версий довольно стандартны и ничего нового про них рассказать не получится. Но сделаны они с умом. Таймлайн для SVN я первый раз увидел тут. До сих пор видел его только в перфорсе.

    Очень понравился трик, не относящийся, однако, напрямую к Xcode. Это вариант использования Automator. Xcode, как любое Cocoa-приложение работает с ним, как с родным. Точнее, он с Xcode. Записал видюшку с примером.




17 июн. 2012 г.

Кодоперлы.

И такое бывает %)
function TRePolSng.Event_On(ticks: cardinal): boolean;
begin
...
  // ACHTUNG!!! не сломайте моск =)
  FNRZ_EKVIVAL := ( not Power )and( Power );
...
end;

6 июн. 2012 г.

*x. svn + vimdiff = тру!

Небольшое описание настройки SVN с тем, чтобы дефолтным менеджером сравнения использовался трушный vimdiff (специальный режим работы vim). У SVN есть команда diff, которая сравнивает указанный файл с его предыдущими ревизиями - по умолчанию с предыдущей. И, опять-таки по умолчанию, она выводит список различий в довольно таки неудобочитаемом формате. Для использования внешнего менеджера различий нужно указать в командной строке модификатор --diff-cmd <команда запуска менеджера>, либо прописать <команда запуска менеджера> в файле ~/.subversion/config в параметре diff-cmd. Но не все так просто. SVN в дополнение к именам файлов передает менеджеру еще 5 параметров. При брутальном указании vimdiff он начинает ругаться на несуществующие файлы и отсутствующие команды. Для обхода этого используем unix-way - скрипты. Итаг:

1. создаем следующий файл bash-скрипта:
#!/bin/sh

# Configure your favorite diff program here.
VIMDIFFCMD="/usr/bin/vimdiff"

# Subversion provides the paths we need as the sixth and seventh
# parameters.
LEFT=${6}
RIGHT=${7}

# Call the diff command (change the following line to make sense for your merge program).
$VIMDIFFCMD "$LEFT" "$RIGHT"

называем его как-то типа svndiff.sh, устанавливаем права доступа для выполнения
chmod +x svndiff.sh
и кладем где-то в $PATH - можно в домашней директории, можно в /usr/local/bin - куда руки дотянутся.

2.  Далее в файле ~/.subversion/config добавляем/заменяем строку:
diff-cmd = svndiff.sh

Ну и в принципе все. Делаем
svn diff <filename>
и пользуемся правильными инструментами.