Вы находитесь на странице: 1из 6

Readdle Coding Standard∗

А.А. Буданцов, Д.А. Процеров

1 Введение
Данный документ содержит рекомендации по оформлению исходного кода
на языках Objective-C и, в некоторой степени, C/C++. Соблюдение данных
рекомендаций поможет снизить дискомфорт при работе с исходным кодом
разных разработчиков работающих в Компании, повысить читаемость и
понятность кода, избежать проблем при реиспользовании кода в других
проектах.

2 Здравый смысл
Данный документ является дополнением к здравому смыслу. Список пере-
численных рекомендаций является открытым и не учитывает все богатство
фантазии разработчиков.

3 Общие положения
3.1 Длина строки
При написании кода рекомендуется ограничивать длину строки 120 симво-
лами.

На заметку: В среде разработки Xcode включить индика-


цию горизонтального положения курсора (колонки) можно в ме-
ню Xcode → Preferences... → Text Editing → Display Options →
Show column position

Рассмотрите следующие варианты, для того чтобы разбить длинную


строку на более короткие:

• Если в строке присутствует вызов функции (передача сообщения) с


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

∗ Редакция 1.1

1
UIAlertView *a = [[UIAlertView alloc] initWithTitle:title
message:text
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];

• Если в строке присутствует вложенные вызовы функций (результат


вызова одной функции, является аргументом для другой) — объяви-
те временную переменную строкой выше и поместите туда значение
одной из функций;
• Логические и арифметические выражения следует разбивать на стро-
ки по знакам операций, оставляя сам знак в конце предыдущей строки.

3.2 Пустые строки


Пустыми строками следует разделять:
• Реализации функций и обработчики сообщений;

• Хорошим тоном является разделение пустой строкой разных логиче-


ских блоков внутри функции.

3.3 Пробелы
Пробелом следует разделять
• арифметические и логические операции, оператор присваивания —
выделяются пробелами с обоих сторон:

int buttonOffset = frameOffset + previousButtonHeight + margin;

• составные части конструкции for — пробел ставиться после точки с


запятой: for(i = 0; i < 10; i++)
• аргументы функции(С) — пробел ставится после запятой:
doSomething(arg1, arg2, arg3)

Пробелами не следует разделять


• в вызове сообщения — имя сообщения/аргумента и его значение:
[object callWithValue:value]
• в вызове функции — имя функции и открывающую скобку:
doSomething(argument)
• переменную и операцию инкримента/декримента

2
3.4 Операторные скобки
Открывающая скобка находится на той же строке, на которой происходит
объявление блока:
- (id)initWithFileName:(NSString *)fileName {
...
if (pathToFile && [pathToFile hasSuffix:@"rtfd.zip"]) {
...
for(i = 0; i < 10; i++) {
...
struct mystruct { // не совсем операторные скобки
...
@interface BlackMail : UIView {
Если объявление блока занимает несколько строк, то операторная скоб-
ка начинается с новой строки:
@interface NewGifController : UIViewController <UIImagePickerControllerDelegate,
UINavigationControllerDelegate>
{
Закрывающая скобка всегда находиться на строке одна, и не может со-
провождаться какими-либо другими символами или конструкциями (кроме
комментариев).
Таким образом, предыдущие правила определяют способ расстановки
операторных скобок при использовании else if:

if (a == 1) {
// code
}
else if (b == 1) {
// more code
}
else {
// even more code
}

3.5 * в указателях и функциях


Символ * в объявлении переменных-указателей, возвращаемых значениях
функций, аргументах функций — отбивается пробелами от основных типов
данных:

NSString *RDDocsDirectory();
...
- (void)addColor:(UIColor *)color;
...
NSObject *object = nil;
...
char *test = (char *)malloc(1024);

3
4 Правила именования
В отношении именования классов, функций, сообщений и пр. мы придержи-
ваемся рекомендаций от Apple: http://developer.apple.com/documentation/
Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html
Документ по ссылке выше рекомендуется для тщательного изучения.
Ключевые положения уточняющие этот документ или входящие с ним в
противоречие (и имеющие более высокий приоритет) будут изложены в этом
разделе позднее.

4.1 Префиксы имен классов и функций


Для классов и функций предназначенных для самого широкого использо-
вания, мы используем префикс RD.
Авторам кажется удачной идея использовать для отдельных проектов
свои собственные префиксы (таких как RD2 для ReaddleDocs2). Вопрос ис-
пользования/выбора префикса решается для каждого проекта индивиду-
ально.

4.2 Create Rule


Имена методов возвращающих объекты должны обязательно соответство-
вать Create Rule для Objective-C:

You take ownership of an object if you create it using a method


whose name begins with “alloc” or “new” or contains “copy” (for
example, alloc, newObject, or mutableCopy), or if you send it a
retain message. You are responsible for relinquishing ownership of
objects you own using release or autorelease. Any other time you
receive an object, you must not release it.

4.3 #define
Запрещается использовать #define для
• объявления констант

• реализации макросов-функций (за исключением случаев, когда это


оправдано требованиями производительности)

4.4 Константы
Константы объявляются с использованием обычного C кода. Никакие спе-
циальные префиксы (вроде ‘k-’) в именах констант не используются.
Константа действующая внутри файла, определяется как
static int const RD2MagicNumberUniverseAnswer = 42;

Глобальные константы для проекта объявляются с использованием обыч-


ного extern. В m-файле:
int const RD2MagicNumberUniverseAnswer = 42;

4
В h-файле:
extern int const RD2MagicNumberUniverseAnswer;

5 Прочие рекомендации
5.1 init и dealloc
В исходном коде рекомендуется располагать реализацию обработчика сооб-
щения dealloc сразу после обработчиков сообщений init-. . . .

5.2 Переменные класса


В случае, если в реализации класса есть шанс перепутать переменную клас-
са и переменную объявленную внутри метода (или являющуюся аргументом
метода), рекомендуется предварять имя переменной класса символом _.
Например:
- (void)setObject:(RDObject *)object {
_object = [object retain];
[self doSomething];
}
Хорошей альтернативой является использование артиклей для имен ар-
гументов:

- (void)setObject:(RDObject *)anObject {
object = [anObject retain];
[self doSomething];
}
Символ подчеркивания в имени аргумента — это плохо.

5.3 NSLocalizedString
Все строки пользовательского интерфейса должны присутствовать в исход-
ном коде внутри макроса NSLocalizedString.

NSLocalizedString(строка, описание того, где она используется)

Например:

email = [UITextField alloc] initWithFrame:...];


email.placeholder = NSLocalizedString(@"e-mail",
@"placeholder for email field");

По-умолчанию NSLocalizedString вернет свой первый аргумент. На на-


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

5
5.4 NSAssert
Настоятельно рекомендуется использовать NSAssert для проверки условий
при которых работа программы окажется бессмысленной или невозможной.

NSAssert(условие, ошибка для случая если условие не выполняется)

Например:
FILE *f = fopen(file, "r");
NSAssert(f != NULL, @"unable to open the File");
...

Существуют так же NSAssert1, NSAssert2, NSAssert3, NSAssert4, NSAssert5


у которые есть дополнительные аргументы, на которые можно ссылатся
(форматной строкой, как в NSLog) из описания ошибки.
NSAssert прерывает работу программы и должен использоваться только
для фатальных ошибок.

5.5 ReaddleLib
К использованию во всех проектах Readdle предлагается ReaddleLib (ReaddleLib.h,
ReaddleLib.m) содержащие некоторые функции и расширения системных
классов.

5.6 #pragma mark


Хорошим тоном является разбиение длинных файлов на логические секции
при помощи #pragma mark. Для наглядного выделения, мы добавляем по
две директивы #pragma mark - выделяя в Xcode заголовок тонкими лини-
ями.

#pragma mark -
#pragma mark Заголовок
#pragma mark -

5.7 Выравнивание в объявлении переменных класса


Как свидетельствует опыт, использование выравнивания в объявлении пе-
ременных класса ведет к улучшению читаемости кода.

@interface TestClass : NSObject {


NSInteger member1;
NSInteger member2;
RDSomeLongClassName *classMemeber1;
}

@property (nonatomic) NSInteger member1;


@property (nonatomic, readonly) RDSomeLongClassName *classMemeber1;