Slide 1

Slide 1 text

Работа над ошибками Cocoa Touch tips&tricks © 2010 Владимир Пузанов, Hack&Dev FSO

Slide 2

Slide 2 text

О чем мы сегодня поговорим ✤ Как правильно писать код в команде ✤ Для чего нужен VCS ✤ Советы по оформлению и типичные ошибки

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

Структура проекта ✤ Classes/ – отдельный каталог для классов ✤ Tests/ – отдельный каталог для тестов ✤ xib’ы традиционно валяются в корне проекта ✤ *.png; *.jpg; etc. – выносить в Resources/ если их больше пяти штук ✤ В общем случае – выносить в отдельные каталоги логические группы файлов, когда их нагромождение в корне затрудняет поиск

Slide 6

Slide 6 text

Структура проекта ✤ Tests – отдельная группа для Unit-тестов ✤ Classes/ ✤ Support/ – код поддержки (дополнительные категории, общие делегаты) ✤ Controllers/, UI Controllers/ – контроллеры хранилища, сети, интерфейса. Удобно далее группировать по UITabBar’у ✤ Model/ – любые ORM-like классы, в том числе производные от NSManagedObject ✤ Other Sources/ – удачное место для всех «внешних» фреймворков (DDXML, Three20, ...)

Slide 7

Slide 7 text

Названия файлов ✤ Отдельный хедер – изолированный класс или протокол: ✤ FooAppDelegate: FooAppDelegate.h ✤ Общий хедер – связанные классы и протоколы: ✤ FooController, FooControllerDelegate: FooController.h ✤ в том числе – связанные структуры данных (enum, struct) ✤ Отдельный хедер – категория: ✤ NSString (SmsLength): NSString+SmsLength.h (или NSStringAdditions.h) ✤ Нет хедера – Unit-тест: ✤ FooControllerTest: FooControllerTest.m

Slide 8

Slide 8 text

Форматирование кода ✤ У проекта может быть только один стиль форматирования ✤ Это очень важно! ✤ Его любыми способами навязывает тимлид ✤ в том числе – хуки на VCS, финансовые штрафы ✤ если я ставлю { ... } в стиле “linux kernel”, то все мои девелоперы тоже ставят { ... } аналогично ✤ brew install uncrustify + UniversalIndentGUI

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

Для чего нужен VCS

Slide 11

Slide 11 text

Для чего нужен VCS ✤ VCS – Version Control System ✤ Средство для работы с версионным кодом, а не механизм для обмена файлами !=

Slide 12

Slide 12 text

Для чего используют VCS ✤ «Закоммить что вчера делал» ✤ «Давайте пока SDK4.0 в отдельный бранч засунем, потом разберемся» ✤ «Ты на этой неделе мало наработал»

Slide 13

Slide 13 text

Для чего можно использовать VCS ✤ branch – средство активной паралельной разработки ✤ blame – механизм поиска авторства строк кода ✤ bisect (git) – оптимальный механизм поиска регрессионной ревизии ✤ log/diff – актуальная история изменений ✤ externals/submodules – разделение кода на подпроекты

Slide 14

Slide 14 text

Use Git, Luke! ✤ Локальная история и bisect – два огромных плюса ✤ быстро работающие log, diff, blame ✤ Дешевые бранчи позволяют перестроить подход к написанию кода и систематизировать коммиты (см. bit.ly/git-branching) ✤ git-svn позволяет прозрачно и удобно работать в корпоративной «svn- среде»

Slide 15

Slide 15 text

Советы по оформлению и типичные ошибки

Slide 16

Slide 16 text

Оформление кода ✤ Читайте «Coding Guidelines for Cocoa» ✤ Думайте ✤ Спрашивайте у коллег

Slide 17

Slide 17 text

Общие принципы именования ✤ Ясность ✤ Краткие и ясные называния. Или хотя бы ясные ✤ insertObject: atIndex: – коротко и понятно ✤ insert: at: – что мы встявляем? Что означает второй аргумент? ✤ removeObjectAtIndex:, removeObject: – удачные названия ✤ remove: – что мы удаляем? ✤ Не придумывайте лишних аббревиатур ✤ destinationSelection:, setBackgroundColor: – хорошо ✤ destSel:, setBkgdColor: – плохо ✤ Для списка общеупотребляемых аббревиатур смотрите Coding Guidelines ✤ Соблюдайте ясность интерпретации названия ✤ sendPort – отправляет порт или возвращает порт отправки? ✤ displayName – показывает имя или возвращает значение заголовка?

Slide 18

Slide 18 text

Общие принципы именования ✤ Постоянство ✤ Используйте имена, аналогичные применяемым в Cocoa/Cocoa Touch ✤ Особенно это важно для полиморфизма ✤ - (int)tag существует в ряде разных классов Cocoa (не связанных прямым наследованием) ✤ Не ссылайтесь на себя ✤ Имена не должны ссылатся на сам объект: ✤ NSString vs NSStringObject ✤ Исключение из правила – константы-маски и константы уведомлений: ✤ NSUnderlineByWordMask ✤ NSTableViewColumnDidMoveNotification

Slide 19

Slide 19 text

Префиксы ✤ В Objective-C нет стандартных средств для реализации пространств имен ✤ Используйте префиксы в именах классов, протоколов, функций, констант и структур ✤ Используйте префиксы в названиях методов категорий, расширяющих стандартные классы ✤ Не используйте префиксы для других методов, имен полей

Slide 20

Slide 20 text

Общие принципы именования ✤ Используйте «camel case» для названий классов и методов, состоящих из нескольких слов: ✤ fileExistsAtPath:isDirectory: ✤ Кроме общеупотребляемых аббревиатур: ✤ TIFFRepresentation

Slide 21

Slide 21 text

Использование символа «_» ✤ Apple резервирует названия, начинающиеся на «_» для себя ✤ Это не значит, что вы никогда не столкнетесь с коллизией имени без префикса «_» при сабклассинге ✤ Будьте бдительны!

Slide 22

Slide 22 text

Названия классов и протоколов ✤ Имя класса должно содержать существительное, которое описывает задачи класса ✤ Название класса должно начинаться с большой буквы ✤ Название протокола обычно обозначает общее поведение методов протокола, Apple рекомендует использовать герундий: ✤ NSLocking vs. NSLock

Slide 23

Slide 23 text

Названия методов ✤ Названия начинаются с маленькой буквы ✤ Ключевые слова init, copy, new обозначают специальное поведение метода (retain count +1) ✤ Методы, которые описывают действие, выполняемое над объектом, удобно называть с глагола: ✤ - (void)invokeWithTarget:(id)target; ✤ - (void)selectTabViewItem:(NSTabViewItem *)tabViewItem;

Slide 24

Slide 24 text

Названия методов ✤ Если метод возвращает значение аттрибута (getter), не используйте «get» в качестве префикса ✤ - (NSSize)cellSize; ✤ - (NSSize)calcCellSize; ✤ - (NSSize)getCellSize; ✤ «get» используется для индикации непрямой передачи результата ✤ - (void)getBytes:(void *)buffer length:(NSUInteger)length;

Slide 25

Slide 25 text

Названия методов ✤ Не используйте анонимные аргументы, по названию метода должно быть понятно, как его использовать: ✤ - (void)sendAction:(SEL)aSelector to:(id)anObject forAllCells: (BOOL)flag; ✤ - (void)sendAction:(SEL)aSelector :(id)anObject :(BOOL)flag; ✤ Слово перед аргументом должно описывать аргумент: ✤ - (id)viewWithTag:(int)aTag; ✤ - (id)taggedView:(int)aTag;

Slide 26

Slide 26 text

Названия методов ✤ Не используйте «and» для объединения частей имени метода ✤ - (int)runModalForDirectory:(NSString *)path andFile:(NSString *) name andTypes:(NSArray *)fileTypes; ✤ Кроме того случая, если «and» используется для объединения двух разных действий: ✤ - (BOOL)openFile:(NSString *)fullPath withApplication:(NSString *)appName andDeactivate:(BOOL)flag;

Slide 27

Slide 27 text

Свойства ✤ Используйте генерируемые свойства (@property) везде, где только возможно ✤ Свойства это: ✤ Ограничение доступа (readonly) ✤ Режим управления памятью (assign, retain, copy) ✤ Прозрачная реализация собственных методов доступа (getter, setter)

Slide 28

Slide 28 text

Свойства ✤ Используйте nonatomic. Четко понимайте границы атомарности по умолчанию ✤ Используйте автоматически сгенерированные поля (@synthesize) ✤ В таком случае, блок { ... } в описании класса вообще можно опустить ✤ Для явного доступа к ivar (например в своем setter) используйте постфикс “_” (он некрасиво смотрится, что уменьшит желание его использовать): ✤ @property (nonatomic, copy) NSString *title; ✤ @synthesize title = title_; ✤ Никогда не используйте ivar_ нигде, кроме как в getter/setter

Slide 29

Slide 29 text

«Приватные» методы и свойства ✤ Не выносите приватный код в общий хедер! ✤ Используйте или отдельный файл MyClass+Private.h, или просто анонимную категорию в начале MyClass.m: @interface MyClass () @property (nonatomic, readwrite, retain) *privateObjects; - (void)privateOperation; @end

Slide 30

Slide 30 text

Используйте пулы памяти ✤ -autorelease – это дешево! ✤ Используйте рядом с new/init/copy/retain, чтобы не забыть потом сделать release ✤ Создавайте в своих классах воспомогательные конструкторы с автоматической делегацией объекта в ближайший пул: ✤ + (id)controllerWithSomeObject:(SomeObject *)object;

Slide 31

Slide 31 text

Не забывайте про парные методы ✤ init – dealloc ✤ viewDidLoad – viewDidUnload ✤ someProperty – setSomeProperty:

Slide 32

Slide 32 text

Не надо визуального мусора ✤ Не проверяйте лишний раз объект на nil: ✤ if(myObj != nil) ✤ [myObj retain]; ✤ objc_msgSend делает это в любом случае

Slide 33

Slide 33 text

Полезно почитать ✤ CocoaDevCentral – Cocoa Style for Objective-C ✤ http://cocoadevcentral.com/articles/000082.php ✤ http://cocoadevcentral.com/articles/000083.php ✤ StackOverflow ✤ http://stackoverflow.com/questions/155964/what-are-best- practices-that-you-use-when-writing-objective-c-and-cocoa ✤ The Code Commandments: Best Practices for Objective-C Coding ✤ http://ironwolf.dangerousgames.com/blog/archives/913

Slide 34

Slide 34 text

Вопросы? Всем спасибо (отдельное спасибо @pfactum, за то что вычитал слайды ^__^)