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

Я знаю о ВЫСОКИЙ (что очень удобно!), Но какие методы программирования вы используете при написании Objective-C, а точнее при использовании Cocoa (или CocoaTouch).

см. это сообщение в блоге, очень приятно. ironwolf.dangerousgames.com/blog/archives/913

user392412 02.04.2012 19:57
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
346
1
122 637
33
Перейти к ответу Данный вопрос помечен как решенный

Ответы 33

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

ОБНОВЛЕНИЕ: если вы не используете ARC

Также, если у вас copy, mutableCopy, new или retain.

Sven 05.09.2010 17:21
Ответ принят как подходящий

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

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

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 val = someFloat * 2.2f;

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

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

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

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

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

Здесь можно найти больше советов по оптимизации SQLite, хотя документ кажется устаревшим, многие пункты, вероятно, все еще хороши;

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

Хороший намек на двойную арифметику.

Adam Ernst 06.10.2008 21:05

Расширения классов теперь являются предпочтительным способом для частных методов: developer.apple.com/Mac/library/documentation/Cocoa/Conceptu‌ al /…

Casebash 03.02.2010 05:06

Ваш совет насчет дублеров на айфоне устарел stackoverflow.com/questions/1622729/…

Casebash 03.02.2010 05:07

Вау, я только начинаю заниматься разработкой для iPhone, и это невероятно!

Tejaswi Yerukalapudi 31.03.2010 08:01

Casebash - спасибо за ссылку, хотя информация о сетях 3G устарела, похоже, у вас есть еще больше причин для использования FP с одинарной точностью, чем когда-либо прежде! Я обновил этот раздел ответа.

Kendall Helmstetter Gelner 31.03.2010 23:44

Не устарело; Совершенно неверно: исходный iPhone поддерживал аппаратное управление плавающей и двойной скоростью примерно с той же скоростью. SQLite также не хранит транзакции в памяти; они записываются на диск. Только длинные запросы блокируют ваш интерфейс; менее беспорядочно запускать все в основном потоке и использовать более быстрые запросы.

tc. 23.09.2010 05:26

@tc: я исправил элемент SQL о транзакциях, обратите внимание, что я сам не писал эти последние четыре или около того. Я также пояснил, что часть, касающаяся перемещения запросов в фон, предназначена только для очень длинных запросов (иногда вы просто не можете сделать их короче). Но назвать все это «неправильным» из-за нескольких моментов - это довольно крайняя крайность. Кроме того, в приведенном выше ответе уже говорилось: «Предположительно, на старых телефонах вычисления выполняются с той же скоростью», но обратите внимание на то, что большее количество регистров одинарной точности делает их по-прежнему предпочтительными.

Kendall Helmstetter Gelner 23.09.2010 11:50

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

JeremyP 23.09.2010 14:34

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

Kendall Helmstetter Gelner 23.09.2010 20:10

+1 за пункт №5. я бы хотел, чтобы неатомные были по умолчанию. atomic довольно бесполезен (imo) - разработчик (или клиент) должен знать, когда многопоточность является проблемой или нет, и они должны решать эти проблемы соответствующим образом. «Обычно это работает, хотя занимает очень много времени» - это не «особенность».

justin 01.02.2011 09:09

По поводу второго пункта .... Объявление частного метода :: Нет необходимости писать какую-либо категорию. Я все еще могу писать методы без объявления и без предупреждения. Вот способ: - (void) myPrivateMethod {} - (void) myClassMethod {[self myPrivateMethod]; } Проверь это...

Mrunal 11.01.2012 22:14

Боюсь, что информация о дублях здесь совершенно неверна. Даже связанный вопрос, упомянутый в качестве источника для (4), полностью противоречит утверждению. Еще раз: iDevices всех видов аппаратно поддерживает математику с двойной точностью.

Tim 14.01.2012 00:25

@Tim Тот факт, что математика с двойной точностью поддерживается аппаратно, не делает ее быстрее, чем математика с одинарной точностью. Можете ли вы предоставить ссылку или пример, чтобы показать, что на самом деле нет никакой разницы или что это будет быстрее? Обратите внимание, что в моем тексте явно указано, что математика с двойной точностью поддерживается аппаратно ... и предоставленные ссылки не противоречат друг другу, они показывают, как одинарная точность может быть быстрее.

Kendall Helmstetter Gelner 14.01.2012 08:57

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

Kendall Helmstetter Gelner 14.01.2012 08:59

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

Tim 14.01.2012 09:51

Понятно, спасибо за разъяснения. Я был смущен.

Kendall Helmstetter Gelner 14.01.2012 09:59

@KendallHelmstetterGelner - Могу я узнать, какие организационные причины?

Mrunal 14.01.2012 12:13

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

Kendall Helmstetter Gelner 14.01.2012 13:01

@KendallHelmstetterGelner Текущие версии clang больше не зависят от объявлений методов для текущей единицы компиляции. Таким образом, теперь они могут быть исключены из расширения класса без вреда.

Nikolai Ruhe 03.05.2012 03:52

@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 Reference.

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

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

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

Kendall Helmstetter Gelner 01.10.2008 08:03

За исключением является, разница между частными категориями и расширениями классов: «Расширения классов позволяют вам объявлять дополнительный требуемый API для класса в местах, отличных от основного блока @interface класса, как показано в следующем примере:« См. Ссылку в редактировании.

schwa 01.10.2008 08:46

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

Kendall Helmstetter Gelner 01.10.2008 09:03

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

Kendall Helmstetter Gelner 01.10.2008 09:08

Я действительно не считаю (Private) более удобным в обслуживании, чем (). Если вы так обеспокоены, то может помочь хорошая доза комментариев. Но, очевидно, живи и дай жить другим. YMMV и др.

schwa 01.10.2008 09:18

Использование () вместо (Private) (или другого названия категории) дает довольно важное преимущество: вы можете повторно объявить свойства как readwrite, в то время как для публики они доступны только для чтения. :)

Pascal 04.12.2009 14:43

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

Walt Sellers 12.01.2012 04:11

Если вы действительно хотите написать Private, вы можете сделать (/*Private*/), и, поскольку это комментарий, на самом деле это (), и вы все равно можете объявлять свойства

Jonathan. 06.04.2012 13:15

Очистите в dealloc.

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

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

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

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

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

В общем, вам следует нет использовать методы доступа в dealloc (или init).

mmalc 03.10.2008 19:38

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

mmalc 03.10.2008 19:53

Помимо причин производительности (аксессоры немного медленнее, чем прямой доступ), почему бы мне не использовать аксессоры в dealloc или init?

schwa 10.10.2008 23:11

(a) Причины производительности вполне адекватны сами по себе (особенно если ваши аксессоры атомарны). (b) Вам следует избегать любых побочных эффектов, которые могут иметь средства доступа. Последнее особенно важно, если ваш класс может быть подклассом.

mmalc 11.10.2008 08:28

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

Louis Gerbarg 10.11.2008 23:34

Более подробное представление о том, следует ли использовать методы / свойства средств доступа в методах -init и -dealloc, можно найти здесь: mikeash.com/?page=pyblog/…

Johan Kool 28.11.2009 10:49

Разве это не должно быть nil, а не NULL?

Danyal Aytekin 12.04.2012 13:41

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

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

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

Привыкание к этой привычке избавит вас от множества странных сбоев, отлаживать которые сложно.

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

Редактировать:

Еще более оборонительное изменение:

self.someObject.delegate = NULL;

в:

if (self.someObject.delegate == self)
    self.someObject.delegate = NULL;

В этом нет ничего тонкого, в документации четко сказано, что вы обязаны это сделать. С Memory Management Programming Guide for Cocoa: Additional cases of weak references in Cocoa include, but are not restricted to, table data sources, outline view items, notification observers, and miscellaneous targets and delegates. In most cases, the weak-referenced object is aware of the other object’s weak reference to it, as is the case for circular references, and is responsible for notifying the other object when it deallocates.

johne 21.07.2009 08:06

Лучше использовать nil вместо NULL, потому что NULL не освободит память.

Naveen Shan 10.10.2011 09:47

@NaveenShan nil == NULL. Они точно такие же, за исключением того, что nil - это id, а NULL - это void *. Ваше утверждение не соответствует действительности.

user142019 25.10.2011 17:38

@WTP да, nil == NULL, но использование nil явно является предпочтительным способом, если вы просматриваете фрагменты кода примеров яблок, они везде используют nil, и, как вы сказали, nil - это идентификатор, что делает его предпочтительнее, чем void * , в тех случаях, когда вы отправляете идентификаторы, то есть.

Ahti 23.11.2011 17:15

@Ahti точно, а Nil (в верхнем регистре) относится к типу Class*. Несмотря на то, что все они равны, использование неправильного может привести к небольшим неприятным ошибкам, особенно в Objective-C++.

user142019 23.11.2011 17:54

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

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

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

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

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

В ПОРЯДКЕ. Теперь, когда вас предупредили, игнорируйте «не делайте этого». Но проявляйте крайнюю сдержанность.

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

Kendall Helmstetter Gelner 01.10.2008 10:45

Я просто хотел бы выразить свою поддержку методов категорий с пространством имен. Это кажется правильным поступком.

Michael Buckley 01.10.2008 11:43

+1 хотя бы для римских цифр. Я бы полностью это сделал!

Brian Postow 31.03.2010 23:58

Контрпункт: последние полтора года я придерживался прямо противоположной политики: «Если это можно реализовать в категории, сделайте это». В результате мой код стал намного более кратким, выразительным и легким для чтения, чем подробный пример кода, который предоставляет Apple. Я потерял в общей сложности около 10 минут на один конфликт пространств имен и, вероятно, выиграл человеко-месяцы благодаря эффективности, которую я создал для себя. Каждому - свое, но я принял эту политику, зная о рисках, и очень рад, что сделал это.

cduhn 06.04.2010 12:05

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

mxcl 04.11.2010 03:06

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

Что это за маленькие советы и хитрости Xcode, о которых вы хотели бы знать 2 года назад?.

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

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

Какие тестовые среды вы рекомендуете?

melfar 13.01.2009 12:06

Xcode включает OCUnit, платформу модульного тестирования Objective-C и поддержку запуска пакетов модульных тестов как части процесса сборки.

Chris Hanson 14.01.2009 09:50

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

Например, в Java вы часто используете экземпляры анонимных подклассов *Listener, а в .NET вы часто используете свои подклассы EventArgs. В Какао вы этого не делаете - вместо этого используется target-action.

Иначе известный как «Композиция по наследованию».

Andrew Ebling 10.03.2011 16:14

Не пишите Objective-C, как если бы это были Java / C# / C++ / и т. д.

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

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

Как Java-разработчик, который написал абстрактную фабрику на Objective-C, я нахожу это интригующим. Не могли бы вы объяснить еще немного, как это работает - возможно, на примере?

teabot 13.07.2009 16:51

Вы все еще верите, что нам не нужны абстрактные фабричные классы после того, как вы опубликовали этот ответ?

kirk.burleson 29.07.2010 00:35

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

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

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

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

Я бы сказал, вообще не используйте setSomething: / something - вместо этого используйте свойства. На данный момент мало людей, которым действительно нужно нацеливаться на Tiger (единственная причина не использовать свойства)

Kendall Helmstetter Gelner 01.10.2008 20:14

Свойства по-прежнему генерируют для вас методы доступа, а атрибуты getter = / setter = в свойстве позволяют указывать имена методов. Кроме того, вы можете использовать синтаксис [foo something] вместо синтаксиса foo.something со свойствами. Так что именование аксессуаров по-прежнему актуально.

Chris Hanson 02.10.2008 02:44

Это отличный справочник для тех, кто работает с C++, где я сделал большую часть того, что вы не советуете.

Clinton Blackmore 01.08.2009 03:17

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

John Smith 07.12.2009 22:53

Установщик не должен приводить к сохранению чего-либо в базе данных. Есть причина, по которой в Core Data есть метод -save: в NSManagedObjectContext, а не для того, чтобы сеттеры генерировали немедленные обновления.

Chris Hanson 18.12.2009 12:28

в моем случае это был не вариант. Метод основных данных не мог работать. Иногда советы из учебников приходится отвергать.

John Smith 09.01.2010 13:54

Я сомневаюсь, что это был не вариант, однако, возможно, потребовалось пересмотреть архитектуру вашего приложения. (Для ясности: я не говорю: «Вам следовало использовать Core Data». Я говорю: «Установщики не должны сохранять в базу данных»). Наличие контекста для управления графом объектов, а не сохранение в нем отдельных объектов , практически всегда возможно и является лучшим решением.

Chris Hanson 12.01.2010 23:51

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

NSResponder 23.04.2010 12:56

По общему признанию, я новичок в iOS, но в документации Apple есть места, где они, кажется, используют «переменную-член» и «переменную экземпляра» взаимозаменяемо (например, bit.ly/hR8RGI), поэтому я не считаю это жестким правилом. .

Brandon DuRette 26.03.2011 09:53

Кроме того, если вы хотите настроить таргетинг на старые системы Mac OS X (до 10.5), у вас нет другого выбора, кроме как использовать методы доступа.

dreamlax 28.03.2011 09:04

Я знаю, что упустил это из виду, когда впервые начал программировать на Какао.

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

Это неправда. Несете ли вы ответственность за выпуск объектов верхнего уровня, зависит от того, от какого класса вы наследуете и какую платформу вы используете. См., Среди прочего, developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgm‌ t /….

mmalc 03.10.2008 20:10

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

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

Теперь есть версия страницы Отладка Magic для iOS.

Jeethu 27.08.2011 13:05

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

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

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

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

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

IBOutlets

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

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

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

неужели загрузка пера не сохранит его дважды? (один раз в пере, второй по назначению свойству). Должен ли я выпустить их в Dealloc?

Kornel 17.06.2009 13:40

Вы должны обнулить выходы в viewDidUnload (iPhone OS 3.0+) или в пользовательском методе setView:, чтобы избежать утечек. Очевидно, вы также должны выпустить в dealloc.

Frank Szczerba 10.07.2009 22:15

Имейте в виду, что не все согласны с этим стилем: weblog.bignerdranch.com/?p=95

Michael 17.08.2009 11:48

Так поступает и Apple. «Начало разработки iPhone 3» также упоминает об этом изменении по сравнению с предыдущими версиями.

ustun 14.10.2009 22:04

Я упомянул об этом в другом комментарии, но должен был разместить его здесь: Как только начнется динамический синтез ivar для приложений iOS (если / когда?), Вы будете рады, что поместили IBOutlet в свойство вместо ivar!

Joe D'Andrea 30.08.2010 19:48

@mmalc: у вас есть доказательства этому? голоса, кажется, тебе верят, но я скептик.

Marcel Falliere 10.12.2010 12:27

@Michael: сообщение, на которое вы ссылаетесь, не согласна с созданием IBOutlets retain, а не с прикреплением IBOutlet к собственности вместо ivar.

tc. 22.06.2011 06:38

Заявленные свойства

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

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

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

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

Вы используете Статический анализатор Clang, что неудивительно, чтобы проанализировать свой код C и Objective-C (еще не C++) в Mac OS X 10.5. Установить и использовать несложно:

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

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

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

У меня были проблемы с тем, чтобы это работало, пока я не выполнил следующие инструкции: oiledmachine.com/posts/2009/01/06/…

bbrown 12.05.2009 03:36

В XCode 3.2.1 для Snow Leopard он уже встроен. Вы можете либо запустить его вручную, используя Выполнить -> Сборка и анализ, либо включить его для всех сборок с помощью параметра сборки «Запуск статического анализатора». Обратите внимание, что этот инструмент в настоящее время поддерживает только C и Objective-C, но не C++ / Objective-C++.

oefe 18.10.2009 22:03

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

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

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

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

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

    NSLog(@"%@", aString);

Меня это уже кусало.

Adam Ernst 06.10.2008 21:03

Это хороший совет для любого языка программирования.

Tom Fobear 27.05.2011 00:30

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

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

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

Избегайте автоматического выпуска

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

Таким образом, а не:

aVariable = [AClass convenienceMethod];

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

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

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

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

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

можно было написать:

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

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

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

Похоже, что ссылка "Соглашение об именах Какао" перемещена. Попробуйте developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgm‌ t /…

slothbear 07.05.2009 22:10

Эти ошибки с автоматическим выпуском укусили меня много-много раз за мою короткую карьеру разработчика iPhone. Сознательное избегание ситуаций могло бы значительно смягчить.

bbrown 14.05.2009 21:26

Я считаю, что преимущества нет с использованием autorelease перевешивают его затраты (то есть больше ошибок утечки памяти). Код в основном потоке в любом случае должен быть довольно коротким (иначе пользовательский интерфейс будет зависать), а для более длительного фонового кода, интенсивно использующего память, вы всегда можете обернуть интенсивно потребляющие память части в локальные пулы автозапуска.

adib 05.07.2010 03:27

Я не согласен. По возможности следует использовать автоматически выпущенные объекты. Если они слишком увеличивают объем памяти, вам следует использовать другой NSAutoreleasePool. Но только после того, как вы подтвердите, что это действительно проблема. Преждевременная оптимизация и все такое ...

Sven 05.09.2010 17:17

Я трачу меньше 40 сек. день, набрав [someObject release] и прочитав «лишнюю строку» при создании экземпляра нового объекта, но однажды я потратил 17 часов на то, чтобы найти ошибку автозапуска, которая проявлялась только в особых случаях и не давала внятной ошибки в консоли. Так что я согласен с Адибом, когда он говорит: «Я считаю, что преимущества неиспользования автоспуска перевешивают его затраты».

RickiG 08.12.2010 13:48

Нет ничего плохого в использовании AutoreleasePool, если вы получаете право собственности на объект; в вашем примере я бы использовал свойства: self.aVariable = [AClass comfortMethod]; фактически, объекты с автоматическим выпуском являются самой причиной использования при возврате из методов; это совет, данный Apple и Стэнфордским курсом iPhone.

Özgür 10.12.2010 08:00

Я согласен со Свеном. Основная цель должна заключаться в ясности кода и сокращении ошибок кодирования с оптимизацией памяти только там, где это необходимо. Ввод [[[Foo alloc] init] autorelease] выполняется быстро, и вы сразу же решаете проблему выпуска этого нового объекта. При чтении кода вам не нужно искать соответствующий выпуск, чтобы убедиться, что он не просочился.

Mike Weller 17.12.2010 21:42

Жизненный цикл автоматически выпущенных объектов четко определен и определяется на достаточном уровне.

eonil 29.03.2011 21:12

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

mmalc 07.04.2011 09:24

Синтаксис autoreleased обеспечивает гораздо лучшую читаемость кода, чем дополнительные вызовы функций alloc init и дополнительная строка для выпуска. Если ваш объект не освобождается после цикла выполнения, это означает, что объект удерживается чем-то еще и не будет освобожден, даже если вы освобождали его «вручную», проблема не будет в «какой-то ошибке автоматического освобождения». .

Zaky German 10.06.2011 18:35

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

brian 23.06.2011 19:22

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

occulus 14.02.2012 18:31

Подумайте о нулевых значениях

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

У меня такой: #define SXRelease(o); o = nil и такой же на CFRelease и free. Это все упрощает.

user142019 25.10.2011 17:45

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

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

Я бы посоветовал вам поместить частные методы в продолжение класса. (например, @interface MyClass () ... @end в вашем .m)

Jason Medeiros 08.02.2009 01:52

Вместо #PRAGMA вы можете использовать комментарий // Mark: [Section], который более переносим и работает идентично.

aleemb 19.06.2009 16:26

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

Marc Charbonneau 22.06.2009 19:21

Вам нужно использовать прописные буквы "// MARK: ...", чтобы он отображался в раскрывающемся списке.

Rhult 21.11.2009 11:50

Что касается Finish what you start, вы также можете использовать // TODO: для отметки кода для завершения, который будет отображаться в раскрывающемся списке.

iwasrobbed 12.07.2010 22:58

Как только ivars будут динамически синтезированы в будущем (для приложений iOS), вы будете рады, что разместили IBOutlets в свойствах!

Joe D'Andrea 30.08.2010 19:46

@iWasRobbed или #warning, который будет отображаться в выводе компилятора.

user142019 25.10.2011 17:40

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

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

Stephan Eggermont 15.08.2010 18:15

Ой глаза !!!!! Я не могу поверить в то, что увидел.

eonil 29.03.2011 21:19

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

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

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

jkp 06.06.2010 16:01

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

tc. 23.09.2010 05:37

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

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

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

И, если можете, включите «Обрабатывать предупреждения как ошибки». Не позволяйте предупреждению существовать.

Peter Hosey 19.10.2009 03:14

Удобный скрипт для настройки вашего проекта с рекомендуемыми предупреждениями доступен здесь: rentzsch.tumblr.com/post/237349423/hoseyifyxcodewarnings-scp‌ t

Johan Kool 28.11.2009 10:52

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

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

Вы даже можете настроить Tab на отступ, а затем использовать Cmd-A и Tab.

Plumenator 15.07.2010 10:31

Простой, но о котором часто забывают. Согласно спецификации:

In general, methods in different classes that have the same selector (the same name) must also share the same return and argument types. This constraint is imposed by the compiler to allow dynamic binding.

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

@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's 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;
}   

это легко забыть. Тем не менее важно

Brock Woolf 28.08.2010 10:06

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

Nikolai Ruhe 31.08.2010 01:21

Если мы будем следовать рекомендациям Apple по соглашению об именах, такой ситуации не будет :)

eonil 29.03.2011 21:17

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

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

  1. Есть разделение изменчивости. Используйте классы неизменный в качестве первичных, а изменяемый объект в качестве вторичных. Например, используйте в первую очередь NSArray и используйте NSMutableArray только тогда, когда вам нужно.

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

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

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

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

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

Что касается 3), я предлагаю противоположный подход: используйте ручное сохранение / освобождение везде, где это возможно! Кто знает, как этот код будет использоваться - и если он будет использоваться в жестком цикле, это может без надобности взорвать ваше использование памяти.

Eiko 19.05.2011 02:58

@Eiko Это просто Преждевременная оптимизация, не может быть общим руководством.

eonil 19.05.2011 06:34

Я думаю, что это больше связано с дизайном, особенно при работе с классами моделей. Я считаю рост памяти побочным эффектом, и это не то, о чем я хочу часто появляться. Хуже того, у другого разработчика, использующего мой код, нет шансов, кроме как обернуть дорогостоящие вызовы в пулы автозапуска (если это вообще возможно - мои объекты могут быть отправлены в какой-то другой код библиотеки). И эти проблемы трудно диагностировать позже, но их дешево избежать в первую очередь. Если вы копируете / автоматически выпускаете переданные объекты, вы можете потеряться, если они намного больше, чем вы ожидали. Однако я более расслаблен с кодом графического интерфейса.

Eiko 19.05.2011 12:49

@Eiko Я согласен, что autorelease будет держать память дольше в целом, а ручной retain/release может уменьшить потребление памяти в этом случае. Однако это должно быть руководством для оптимизации в особых случаях (даже если вы чувствуете себя всегда!), Не может быть причиной обобщения преждевременной оптимизации как упражняться. И на самом деле ваше предложение не противоречит моему. Я упомянул это как случай очень нужно :)

eonil 19.05.2011 13:48

Освободите только имущество в методе освободить. Если вы хотите освободить память, которую удерживает имущество, просто установите ее как nil:

self.<property> = nil;

Обратите внимание, что по этому поводу ведутся большие споры. Использование установщика в dealloc может привести к ошибке, если вы не освобождаете свойства в правильном порядке. Однако то же самое верно и при прямом использовании release - могут появиться другие ошибки. Apple рекомендует использовать release в dealloc, но они используют сеттер в своей реализации (например, выпуск delegate в [UITableView dealloc])

Sulthan 07.01.2012 21:53

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

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

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


@synthesize property = property_;

Причина 1: вы обнаружите ошибки, вызванные забыванием «я». при передаче собственности. Причина 2: Судя по моим экспериментам, у Leak Analyzer in Instruments есть проблемы с обнаружением утечки с именем по умолчанию.

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

Взгляды

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

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

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

4 / Освободить все IBOutlets в viewDidUnload

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

объем памяти

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

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

Комментарии

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

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

Отступ

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


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

return self;


if (!self) {
   return nil;
}

//... long initialization code ...

return self;

Понять C-код, в основном C-структуры

Обратите внимание, что Obj-C - это только легкий слой ООП над языком 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 / C++ и наших собственных дополнений. Задокументируйте свой код, используйте стандартные стандартные отступы, пробелы и пустые строки в нужных местах и ​​т. Д.

#import "MyClass.h"

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

@implementation MyClass

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