Каковы наилучшие практики, которые вы используете при написании Objective-C и Cocoa?

Я знаю о HIG (что весьма удобно!), но какие методы программирования вы используете при написании Objective-C, и более конкретно при использовании Cocoa (или CocoaTouch).

348
задан pixel 01 окт. '08 в 5:13
источник поделиться

33 ответов

  • 1
  • 2

Есть несколько вещей, которые я начал делать, я не считаю их стандартными:

1) С появлением свойств я больше не использую переменные класса "_" для префикса "private". В конце концов, если переменная может быть доступна другим классам, не должно существовать для нее свойство? Я всегда не любил префикс "_", чтобы сделать код более уродливым, и теперь я могу его оставить.

2) Говоря о частных вещах, я предпочитаю размещать частные определения методов в файле .m в расширении класса, например:

#import "MyClass.h"

@interface MyClass ()
- (void) someMethod;
- (void) someOtherMethod;
@end

@implementation MyClass

Зачем загромождать файл .h с вещами, которые посторонние не должны волновать? Пустой() работает для частных категорий в файле .m и выдает предупреждения компиляции, если вы не реализуете объявленные методы.

3) Я взял, чтобы положить dealloc в начало файла .m, чуть ниже директив @synthesize. Разве вы не должны быть в верхней части списка вещей, о которых вы хотите думать в классе? Это особенно верно в среде, такой как iPhone.

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

3.6) При использовании NSURLConnection, как правило, вы можете захотеть реализовать метод делегата:

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
                  willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
      return nil;
}

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

Также интересны некоторые полезные советы iPhone от Джозефа Маттиелло (полученные в списке рассылки iPhone). Их больше, но они были наиболее полезными, я думал (обратите внимание, что несколько бит теперь слегка отредактированы из оригинала, чтобы включить в него предложения):

4) Используйте только двойную точность, если это необходимо, например, при работе с CoreLocation. Убедитесь, что вы закончили свои константы в 'f', чтобы gcc сохранил их как float.

float val = someFloat * 2.2f;

Это в основном важно, когда someFloat может фактически быть двойным, вам не нужна математика в смешанном режиме, поскольку вы теряете точность в 'val' на хранилище. Хотя числа с плавающей запятой поддерживаются на оборудовании на iPhone, для выполнения арифметики с двойной точностью, в отличие от одиночной точности, может потребоваться больше времени. Ссылки:

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

5) Задайте свои свойства как nonatomic. По умолчанию они atomic, а при синтезе создается код семафора для предотвращения многопоточных проблем. 99% из вас, вероятно, не должны беспокоиться об этом, и код намного раздувается и более эффективен с точки зрения памяти при установке на неатомический.

6) SQLite может быть очень и очень быстрым способом кэширования больших наборов данных. Например, приложение карты может кэшировать свои фрагменты в файлы SQLite. Самая дорогая часть - дисковый ввод-вывод. Избегайте многих мелких записей, отправляя BEGIN; и COMMIT; между большими блоками. Мы используем 2-секундный таймер, например, который сбрасывается на каждый новый submit. По истечении этого срока мы отправляем COMMIT;, что заставляет все ваши записи перемещаться в один большой кусок. SQLite хранит данные транзакций на диск и делает эту операцию "Начало/Окончание" позволяет избежать создания многих файлов транзакций, группируя все транзакции в один файл.

Кроме того, SQL будет блокировать ваш графический интерфейс, если он находится в основном потоке. Если у вас очень длинный запрос, рекомендуется хранить ваши запросы как статические объекты и запускать SQL в отдельном потоке. Обязательно оберните все, что изменяет базу данных для строк запроса в блоках @synchronize() {}. Для коротких запросов просто оставьте вещи в основном потоке для удобства.

Дополнительные советы по оптимизации SQLite приведены здесь, хотя документ выглядит устаревшим. Многие из них, вероятно, все еще хороши;

http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html

400
ответ дан Kendall Helmstetter Gelner 01 окт. '08 в 6:17
источник поделиться

Не используйте неизвестные строки в качестве строк формата

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

Например, при записи строк, возникает соблазн передать строковую переменную в качестве единственного аргумента в NSLog:

    NSString *aString = // get a string from somewhere;
    NSLog(aString);

Проблема заключается в том, что строка может содержать символы, которые интерпретируются как строки формата. Это может привести к ошибочным выводам, сбоям и проблемам безопасности. Вместо этого вы должны подставить строковую переменную в строку формата:

    NSLog(@"%@", aString);
110
ответ дан mmalc 06 окт. '08 в 19:46
источник поделиться

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

Примеры того, что делать и что не делать:

  • Не объявляйте id m_something; в интерфейсе объекта и называйте его переменной-членом или полем; используйте something или _something для своего имени и назовите его переменной экземпляра.
  • Не называйте getter -getSomething; правильное имя Cocoa - это просто -something.
  • Не называйте setter -something:; это должно быть -setSomething:
  • Имя метода перемежается с аргументами и включает двоеточия; это -[NSObject performSelector:withObject:], а не NSObject::performSelector.
  • Используйте inter-caps (CamelCase) в именах методов, параметрах, переменных, именах классов и т.д., а не в нижних строках (подчеркивания).
  • Названия классов начинаются с букв в верхнем регистре, переменных и имен методов с нижним регистром.

Что бы вы ни делали, не использовать венгерскую нотацию Win16/Win32. Даже Microsoft отказалась от этого с переходом на платформу .NET.

108
ответ дан Chris Hanson 01 окт. '08 в 18:47
источник поделиться

IBOutlets

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

@interface MyClass :NSObject {
    NSTextField *textField;
}
@property (nonatomic, retain) IBOutlet NSTextField *textField;
@end

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

107
ответ дан mmalc 03 окт. '08 в 18:43
источник поделиться

Использовать статический анализатор LLVM/Clang

ПРИМЕЧАНИЕ. В Xcode 4 это теперь встроено в среду IDE.

Вы используете Clang Static Analyzer - неудивительно - проанализируйте свой код C и Objective-C (еще не С++) на Mac OS X 10.5. Это тривиально для установки и использования:

  • Загрузите последнюю версию эту страницу.
  • Из командной строки cd в каталог проекта.
  • Выполнить scan-build -k -V xcodebuild.

(Есть некоторые дополнительные ограничения и т.д., в частности, вам следует проанализировать проект в его конфигурации "Отладка" - см. http://clang.llvm.org/StaticAnalysisUsage.html для деталей - но это более или менее то, к чему оно сводится.)

Затем анализатор создает набор веб-страниц для вас, который показывает вероятное управление памятью и другие основные проблемы, которые компилятор не может обнаружить.

98
ответ дан mmalc 04 окт. '08 в 8:15
источник поделиться

Это тонкий, но удобный. Если вы передаете себя как делегат другому объекту, reset, этот делегат объекта перед вами dealloc.

- (void)dealloc
{
self.someObject.delegate = NULL;
self.someObject = NULL;
//
[super dealloc];
}

Выполняя это, вы гарантируете, что больше методов делегата не будет отправлено. Когда вы собираетесь dealloc и исчезаете в эфире, вы хотите удостовериться, что ничто не может отправить вам больше сообщений случайно. Помните, что self.someObject может быть сохранен другим объектом (это может быть синглтон или пул авторекламы или что-то еще), и пока вы не скажете "перестаньте отправлять мне сообщения!", Он думает, что ваш объект, который должен быть освобожден от несанкционированного доступа это честная игра.

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

Тот же принцип применяется к наблюдению за ключевым значением и NSNotifications.

Edit:

Еще более защитный, измените:

self.someObject.delegate = NULL;

в

if (self.someObject.delegate == self)
    self.someObject.delegate = NULL;
95
ответ дан schwa 01 окт. '08 в 7:59
источник поделиться

@kendell

Вместо:

@interface MyClass (private)
- (void) someMethod
- (void) someOtherMethod
@end

Использование:

@interface MyClass ()
- (void) someMethod
- (void) someOtherMethod
@end

Новое в Objective-C 2.0.

Расширения классов описаны в справочнике Apple Objective-C 2.0.

"Расширения классов позволяют объявлять дополнительный API для класса в местах, отличных от блока основного класса @interface"

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

87
ответ дан schwa 01 окт. '08 в 6:53
источник поделиться

Избегайте автообновления

Поскольку вы обычно (1) не имеете прямого контроля над своей жизнью, автореализованные объекты могут сохраняться в течение сравнительно длительного времени и излишне увеличивать объем памяти вашего приложения. Хотя на рабочем столе это может иметь мало значения, на более ограниченных платформах это может быть серьезной проблемой. Поэтому на всех платформах, и особенно на более ограниченных платформах, считается лучшей практикой избегать использования методов, которые приводят к автореализованным объектам, и вместо этого вам предлагается использовать шаблон alloc/init.

Таким образом, вместо:

aVariable = [AClass convenienceMethod];

где возможно, вы должны использовать:

aVariable = [[AClass alloc] init];
// do things with aVariable
[aVariable release];

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

Таким образом, вместо:

- (MyClass *)convenienceMethod {
    MyClass *instance = [[[self alloc] init] autorelease];
    // configure instance
    return instance;
}

вы можете написать:

- (MyClass *)newInstance {
    MyClass *instance = [[self alloc] init];
    // configure instance
    return instance;
}

Поскольку имя метода начинается с "нового", пользователи вашего API знают, что они отвечают за освобождение полученного объекта (см., например, NSObjectController newObject).

(1) Вы можете взять управление, используя собственные локальные пулы автоопределений. Подробнее об этом см. Пулы автообновления.

75
ответ дан mmalc 06 окт. '08 в 22:45
источник поделиться

Некоторые из них уже упоминались, но здесь я могу думать о моей голове:

  • Следуйте правилам именования KVO. Даже если вы не используете KVO сейчас, по моему опыту часто это время еще полезно в будущем. И если вы используете KVO или привязки, вам нужно знать, что все работает так, как они должны. Это распространяется не только на методы доступа и переменные экземпляра, но и на многие отношения, проверку достоверности, автоматическое уведомление зависимых ключей и т.д.
  • Поместить частные методы в категорию. Не только интерфейс, но и реализация. Хорошо иметь некоторую дистанцию ​​концептуально между частными и не частными методами. Я включаю все в файл .m.
  • Поместите методы потока фона в категорию. То же, что и выше. Я нашел, что хорошо держать четкий концептуальный барьер, когда вы думаете о том, что на главной теме, а что нет.
  • Использовать #pragma mark [section]. Обычно я группирую свои собственные методы, каждый подкласс переопределяет и любые информационные или формальные протоколы. Это значительно облегчает переход к тому, что я ищу. В той же теме групповые аналогичные методы (например, методы делегата представления таблиц) вместе не помещаются в них.
  • Префикс private methods и ivars с _. Мне нравится, как он выглядит, и я с меньшей вероятностью использую ivar, когда я имею в виду свойство случайно.
  • Не используйте методы/свойства mutator в init и dealloc. Я никогда не имел ничего плохого из-за этого, но я могу видеть логику, если вы измените метод, чтобы сделать что-то, что зависит от состояния вашего объекта.
  • Поместите IBOutlets в свойства. Я на самом деле просто прочитал это здесь, но я собираюсь начать делать это. Независимо от каких-либо преимуществ памяти, это выглядит стилистически (по крайней мере, для меня).
  • Избегайте написания кода, который вам не нужен.. Это действительно охватывает множество вещей, например, создание ivars, когда будет выполняться #define, или кеширование массива вместо сортировки его каждый раз, когда данные необходимы. Там я могу сказать об этом, но в нижней строке не писать код, пока он вам не понадобится, или профайлер говорит вам. Это упрощает работу в долгосрочной перспективе.
  • Завершите то, что вы начинаете. Имея много половины готового кода, глючный код является самым быстрым способом убить проект мертвым. Если вам нужен метод заглушки, который будет прекрасным, просто укажите его, вставив NSLog( @"stub" ) внутрь, или же вы хотите отслеживать все.
70
ответ дан Marc Charbonneau 18 нояб. '08 в 2:11
источник поделиться

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

У вас также нет видимости public vs. protected vs. private method, которая мешает написанию тестов для ваших внутренних компонентов.

56
ответ дан Chris Hanson 01 окт. '08 в 11:04
источник поделиться

Золотое правило: если вы alloc, то вы release!

UPDATE: если вы не используете ARC

55
ответ дан JamesSugrue 01 окт. '08 в 5:16
источник поделиться

Не записывайте Objective-C, как если бы это были Java/С#/С++/etc.

Я когда-то видел, что команда, используемая для написания веб-приложений Java EE, пытается написать настольное приложение Cocoa. Как будто это веб-приложение Java EE. Было много абстрактных FooFactory и FooFactory и IFoo и Foo, когда они действительно нуждались в классе Foo и, возможно, в протоколе Fooable.

Часть обеспечения того, что вы этого не делаете, действительно понимает различия в языке. Например, вам не нужны абстрактные классы factory и factory, потому что методы класса Objective-C отправляются так же динамически, как методы экземпляра, и могут быть переопределены в подклассах.

55
ответ дан Chris Hanson 01 окт. '08 в 18:40
источник поделиться

Убедитесь, что вы закладок Отладка магии". Это должно быть вашей первой остановкой, когда вы стучите головой о стену, пытаясь найти источник ошибки Cocoa.

Например, он расскажет вам, как найти метод, в котором вы сначала выделили память, которая впоследствии вызывает сбои (например, во время завершения приложения).

50
ответ дан mj1531 01 окт. '08 в 19:35
источник поделиться

Попытайтесь избежать того, что я теперь решил назвать Newbiecategaholism. Когда новички в Objective-C обнаруживают категории, они часто бывают свирепыми, добавляя полезные маленькие категории к каждому существующему классу ( "Что? Я могу добавить метод для преобразования числа в римские цифры в NSNumber rock!" ).

Не делайте этого.

Ваш код будет более переносимым и более понятным с помощью множества десятков методов, которые можно разбросать поверх двух десятков базовых классов.

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

Существуют и другие опасности, если вы не используете имена ваших методов категорий (и кто, кроме безумного ддрибина?), есть вероятность, что Apple, или плагин, или что-то еще, работающее в вашем адресном пространстве, также определит метод той же категории с тем же именем со слегка отличающимся побочным эффектом....

OK. Теперь, когда вас предупредили, игнорируйте "не делайте эту часть". Но проявляйте чрезвычайную сдержанность.

38
ответ дан schwa 01 окт. '08 в 8:16
источник поделиться

Сортировка строк по желанию пользователя

Когда вы сортируете строки для представления пользователю, вы не должны использовать простой метод compare:. Вместо этого вы всегда должны использовать локализованные методы сравнения, такие как localizedCompare: или localizedCaseInsensitiveCompare:.

Подробнее см. Поиск, сравнение и сортировка строк.

38
ответ дан mmalc 06 окт. '08 в 19:49
источник поделиться

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

Например, в Java вы часто используете экземпляры анонимных подклассов *Listener, а в .NET вы часто используете подклассы EventArgs. В Cocoa вы тоже не выполняете: вместо этого используется целевое действие.

37
ответ дан Chris Hanson 01 окт. '08 в 11:10
источник поделиться

Объявленные свойства

Обычно вы должны использовать функцию объявленных свойств Objective-C 2.0 для всех ваших свойств. Если они не являются общедоступными, добавьте их в расширение класса. Использование объявленных свойств упрощает семантику управления памятью и упрощает проверку вашего метода dealloc - если вы объединяете объявления свойств, вы можете быстро их сканировать и сравнить с реализацией вашего метода dealloc.

Вы должны много думать, прежде чем не указывать свойства как "неатомные". Поскольку Примечания по языку программирования Objective C, свойства по умолчанию являются атомарными и несут значительные накладные расходы. Более того, просто сделать все ваши свойства атомарными не делает ваше приложение потокобезопасным. Также обратите внимание, конечно, что если вы не укажете "неатомические" и не реализуете свои собственные методы доступа (вместо их синтезирования), вы должны реализовать их по-атомному.

31
ответ дан mmalc 03 окт. '08 в 18:51
источник поделиться

Подумайте о значениях nil

Как этот вопрос, сообщения nil действительны в Objective-C. Хотя это часто является преимуществом, что приводит к более чистому и более естественному коду, функция может иногда приводить к сложным и сложным ошибкам, если вы получаете значение nil, когда вы этого не ожидали.

26
ответ дан mmalc 12 окт. '08 в 23:14
источник поделиться

Используйте NSAssert и друзей. Я использую nil как действительный объект все время... особенно отправка сообщений в nil отлично действует в Obj-C. Однако, если я действительно хочу убедиться в состоянии переменной, я использую NSAssert и NSParameterAssert, что помогает легко отслеживать проблемы.

26
ответ дан NikWest 07 мая '09 в 23:57
источник поделиться

Простая, но забытая. Согласно спецификации:

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

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

@interface FooInt:NSObject{}
-(int) print;
@end

@implementation FooInt
-(int) print{
    return 5;
}
@end

@interface FooFloat:NSObject{}
-(float) print;
@end

@implementation FooFloat
-(float) print{
    return 3.3;
}
@end

int main (int argc, const char * argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];    
    id f1=[[FooFloat alloc]init];
    //prints 0, runtime considers [f1 print] to return int, as f1 type is "id" and FooInt precedes FooBar
    NSLog(@"%f",[f1 print]);

    FooFloat* f2=[[FooFloat alloc]init];
    //prints 3.3 expectedly as the static type is FooFloat
    NSLog(@"%f",[f2 print]);

    [f1 release];
    [f2 release]
    [pool drain];

    return 0;
}   
23
ответ дан Özgür 27 авг. '10 в 13:17
источник поделиться

Если вы используете Leopard (Mac OS X 10.5) или более позднюю версию, вы можете использовать приложение "Инструменты" для поиска и отслеживания утечек памяти. После создания вашей программы в Xcode выберите "Выполнить" > "Начать работу с инструментом производительности" > "Утечки".

Даже если ваше приложение не показывает никаких утечек, вы можете слишком долго хранить объекты. В Инструментах для этого вы можете использовать инструмент ObjectAlloc. Выберите инструмент ObjectAlloc в документе "Инструменты" и вызовите деталь инструмента (если он еще не отображается), выбрав "Просмотр" > "Подробно" (рядом с ним должна быть отметка). В разделе "Распределение продолжительности жизни" в деталях ObjectAlloc убедитесь, что вы выбрали переключатель рядом с "Созданный и неподвижный".

Теперь, когда вы прекращаете запись своего приложения, выбирая инструмент ObjectAlloc, вы покажете, сколько ссылок есть на каждый неподвижный объект в вашем приложении в столбце "# Net". Убедитесь, что вы не только просматриваете свои собственные классы, но и классы ваших объектов верхнего уровня NIB файлов. Например, если у вас нет окон на экране, и вы видите ссылки на все еще живое NSWindow, возможно, вы не выпустили его в свой код.

22
ответ дан mj1531 01 окт. '08 в 19:57
источник поделиться

Очистка в dealloc.

Это одна из самых простых вещей, которые нужно забыть - особенно. при кодировании со скоростью 150 миль в час. Всегда, всегда, всегда очищайте свои атрибуты/переменные-члены в dealloc.

Мне нравится использовать атрибуты Objc 2 - с новой точечной нотацией, поэтому это делает очистку безболезненной. Часто так же просто, как:

- (void)dealloc
{
    self.someAttribute = NULL;
    [super dealloc];
}

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

Когда GC включен в 10.5, это больше не нужно, но вам все равно нужно очистить другие ресурсы, которые вы создаете, но вы можете сделать это в методе finalize.

21
ответ дан schwa 01 окт. '08 в 7:54
источник поделиться

Все эти комментарии замечательные, но я действительно удивлен, что никто не упоминал Google Objective-C Руководство по стилю, которое было опубликовано некоторое время назад. Я думаю, что они проделали очень тщательную работу.

17
ответ дан slf 16 дек. '08 в 22:27
источник поделиться

Кроме того, тема, связанная с полусвязью (с возможностью больше ответов!):

Что представляют собой те маленькие подсказки и трюки Xcode, которые вы хотели бы узнать около 2 лет назад?

15
ответ дан schwa 01 окт. '08 в 8:31
источник поделиться

Не забывайте, что NSWindowController и NSViewController освободят объекты верхнего уровня файлов NIB, которые они определяют.

Если вы вручную загружаете файл NIB, вы несете ответственность за освобождение объектов верхнего уровня NIB, когда вы закончите с ними.

13
ответ дан mj1531 01 окт. '08 в 20:02
источник поделиться

Один довольно очевидный для новичков: используйте функцию автодементации Xcode для вашего кода. Даже если вы копируете/вставляете из другого источника, после того, как вы вставили код, вы можете выбрать весь блок кода, щелкнуть правой кнопкой мыши по нему, а затем выбрать вариант для повторного отступов всего внутри этого блока.

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

12
ответ дан iwasrobbed 12 июля '10 в 22:09
источник поделиться

Переменные и свойства

1/Сохранение заголовков в чистоте, скрытие реализации
Не включайте переменные экземпляра в свой заголовок. Частные переменные помещаются в класс как свойства. Публичные переменные объявляют как публичные свойства в вашем заголовке. Если он должен быть только прочитан, объявите его как readonly и перезапишите его как readwrite в непрерывном классе. В основном я вообще не использую переменные, только свойства.

2/Дайте вашим свойствам имя переменной, отличное от значения по умолчанию, например:


@synthesize property = property_;

Причина 1: вы поймаете ошибки, вызванные забыванием "я". при назначении свойства. Причина 2: Из моих экспериментов Leak Analyzer в Инструментах имеет проблемы с обнаружением свойства утечки с именем по умолчанию.

3/Никогда не используйте удержание или выпуск непосредственно по свойствам (или только в исключительных ситуациях). В вашем dealloc просто назначьте им нуль. Сохраняемые свойства предназначены для самостоятельной обработки удержания/выпуска. Вы никогда не знаете, нет ли сеттера, например, добавление или удаление наблюдателей. Вы должны использовать переменную непосредственно только внутри своего сеттера и получателя.

Просмотры

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

2/Не пытайтесь оптимизировать представления, уменьшая количество просмотров. Не создавайте UIImageView в коде вместо xib только потому, что вы хотите добавить в него subviews. Вместо этого используйте UIImageView. Структура представления может обрабатывать сотни представлений без проблем.

3/IBOutlets не обязательно всегда сохраняться (или сильным). Обратите внимание, что большинство ваших IBOutlets являются частью вашей иерархии представлений и поэтому неявно сохраняются.

4/Отпустите все IBOutlets в viewDidUnload

5/Вызов viewDidUnload из вашего метода dealloc. Это неявно называется.

Память

1/Объекты Autorelease при их создании. Многие ошибки вызваны перемещением вашего запроса на выпуск в одну ветвь if-else или после оператора return. Выпуск вместо автореферата должен использоваться только в исключительных ситуациях - например, когда вы ожидаете runloop, и вы не хотите, чтобы ваш объект был автореализован слишком рано.

2/Даже если вы используете Authomatic Reference Counting, вы должны прекрасно понимать, как работают методы удержания. Использование сохранения-освобождения вручную не сложнее, чем ARC, в обоих случаях вы должны разбираться в утечках и циклах сохранения. Рассмотрите возможность использования сохранения-выпуска вручную в больших проектах или сложных иерархиях объектов.

Комментарии

1/Сделайте свой код автодокументированным. Каждое имя переменной и имя метода должны указывать, что он делает. Если код написан правильно (вам нужно много практики в этом), вам не понадобятся комментарии коментариев (не то же самое, что и комментарии к документации). Алгоритмы могут быть сложными, но код всегда должен быть простым.

2/Иногда вам нужен комментарий. Обычно описывать поведение, не являющееся очевидным кодом, или взломать. Если вы чувствуете, что вам нужно написать комментарий, сначала попробуйте переписать код, чтобы он был проще и без комментариев.

Отступ

1/Не увеличивайте отступ слишком сильно. Большая часть вашего кода метода должна быть отступом на уровне метода. Вложенные блоки (если, для и т.д.) Уменьшают читаемость. Если у вас есть три вложенных блока, вы должны попытаться поместить внутренние блоки в отдельный метод. Четыре или более вложенных блоков никогда не должны использоваться. Если большая часть вашего кода метода находится внутри if, отрицайте условие if, например:


if (self) {
   //... long initialization code ...
}

return self;


if (!self) {
   return nil;
}

//... long initialization code ...

return self;

Понять код C, в основном C structs

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


view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, view.frame.size.height + 20);

совпадает с:


CGRect frame = view.frame;
frame.size.height += 20;
view.frame = frame;

И многое другое

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

Наши стандарты кодирования имеют в настоящее время около 20 страниц, сочетание стандартов кодирования Java, стандартов Google Obj-C/С++ и наших собственных дополнений. Документируйте свой код, используйте стандартные стандартные отступы, пробелы и пустые строки в нужных местах и ​​т.д.

10
ответ дан Sulthan 19 окт. '11 в 5:58
источник поделиться

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

Также часто выполняйте статический анализ Clang; вы можете включить его для всех сборок через настройку сборки "Запустить статический анализатор".

Напишите модульные тесты и запустите их с каждой сборкой.

10
ответ дан oefe 18 окт. '09 в 21:12
источник поделиться

Я знаю, что я пропустил это при первом входе в программирование Cocoa.

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

10
ответ дан mj1531 01 окт. '08 в 19:19
источник поделиться

Быть более функциональным.

Objective-C - это объектно-ориентированный язык, но Cocoa функциональный стиль фреймворка и во многих случаях разработан функциональный стиль.

  • Существует разделение изменчивости. Используйте неизменяемые классы как первичные, а изменчивый объект - как вторичный. Например, сначала используйте NSArray и используйте NSMutableArray только тогда, когда вам нужно.

  • Существуют чистые функции. Не так много, купите многие из API-интерфейсов инфраструктуры, разработанных как чистая функция. Посмотрите на функции, такие как CGRectMake() или CGAffineTransformMake(). Очевидно, что форма указателя выглядит более эффективной. Однако косвенный аргумент с указателями не может обеспечить побочный эффект. Конструктивные конструкции максимально в максимально возможной степени. Разделяйте даже объекты состояния. Используйте -copy вместо -retain при передаче значения другому объекту. Поскольку совместное состояние может влиять на мутацию, чтобы значение в другом объекте было тихо. Таким образом, не может быть побочным эффектом. Если у вас есть значение от внешнего объекта, скопируйте его. Таким образом, это также важно для разработки общего состояния как можно более минимального.

Однако не бойтесь использовать нечистые функции.

  • Существует ленивая оценка. Посмотрите что-то вроде свойства -[UIViewController view]. Представление не будет создано при создании объекта. Он будет создан, когда вызывающий абонент читает свойство view в первый раз. UIImage не будет загружаться до фактического рисования. Существует много реализаций, подобных этой конструкции. Подобные проекты очень полезны для управления ресурсами, но если вы не знаете понятия ленивой оценки, нелегко понять их поведение.

  • Существует закрытие. Используйте C-блоки как можно больше. Это значительно упростит вашу жизнь. Но прочитайте еще раз об управлении блочной памятью, прежде чем использовать его.

  • Существует полуавтоматический GC. NSAutoreleasePool. Используйте -autorelease primary. Используйте ручную -retain/-release вторичную, когда вам действительно нужно. (например: оптимизация памяти, явное удаление ресурсов)

9
ответ дан Eonil 29 марта '11 в 20:51
источник поделиться
  • 1
  • 2

Другие вопросы по меткам