Каковы лучшие практики, которые вы используете при написании Objective-C и какао?
Я знаю о HIG (что очень удобно!), Но какие методы программирования вы используете при написании Objective-C, а более конкретно при использовании Cocoa (или CocoaTouch).
33 ответа
Я начал делать несколько вещей, которые я не считаю стандартными:
1) С появлением свойств я больше не использую "_" для префикса "закрытых" переменных класса. В конце концов, если переменная может быть доступна другим классам, не должно ли быть свойство для нее? Мне всегда не нравился префикс "_" для того, чтобы сделать код более уродливым, и теперь я могу его опустить.
2) Говоря о личных вещах, я предпочитаю размещать определения частных методов в файле.m в расширении класса следующим образом:
#import "MyClass.h"
@interface MyClass ()
- (void) someMethod;
- (void) someOtherMethod;
@end
@implementation MyClass
Почему беспорядок в файле.h с вещами посторонним не должен волновать? Empty () работает для закрытых категорий в файле.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-секундный таймер, который сбрасывается при каждой новой отправке. Когда он истекает, мы отправляем COMMIT;, что заставляет все ваши записи идти в один большой кусок. SQLite хранит данные транзакций на диске, и такое оборачивание начала / конца позволяет избежать создания множества файлов транзакций, группируя все транзакции в один файл.
Кроме того, SQL заблокирует ваш графический интерфейс, если он находится в вашем основном потоке. Если у вас очень длинный запрос, рекомендуется хранить ваши запросы в виде статических объектов и запускать SQL в отдельном потоке. Обязательно оберните все, что изменяет базу данных для строк запроса в @synchronize() {}
блоки. Для коротких запросов просто оставьте вещи в главном потоке для удобства.
Здесь приведены дополнительные советы по оптимизации SQLite, хотя документ выглядит устаревшим, многие из пунктов, вероятно, все еще хороши;
http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html
Не используйте неизвестные строки как строки формата
Когда методы или функции принимают аргумент строки формата, вы должны убедиться, что у вас есть контроль над содержимым строки формата.
Например, при регистрации строк заманчиво передать строковую переменную в качестве единственного аргумента NSLog
:
NSString *aString = // get a string from somewhere;
NSLog(aString);
Проблема в том, что строка может содержать символы, которые интерпретируются как строки формата. Это может привести к ошибочному выводу, сбоям и проблемам безопасности. Вместо этого вы должны подставить строковую переменную в строку формата:
NSLog(@"%@", aString);
Используйте стандартные соглашения и терминологию именования и форматирования Какао, а не то, к чему вы привыкли из другой среды. Есть много разработчиков Какао, и когда другой из них начнет работать с вашим кодом, будет гораздо более доступным, если он будет выглядеть и чувствовать себя похожим на другой код Какао.
Примеры того, что нужно делать, а что нет:
- Не объявляй
id m_something;
в интерфейсе объекта и назовите егопеременной или полем члена; использованиеsomething
или же_something
для его имени и назовите его переменной экземпляра. - Не называй добытчика
-getSomething
; правильное имя какао просто-something
, - Не называйте сеттера
-something:
; так должно быть-setSomething:
- Имя метода перемежается с аргументами и включает двоеточия; его
-[NSObject performSelector:withObject:]
неNSObject::performSelector
, - Используйте заглавные буквы (CamelCase) в именах методов, параметрах, переменных, именах классов и т. Д. Вместо подчеркивания (подчеркивания).
- Имена классов начинаются с заглавной буквы, имена переменных и методов начинаются со строчных.
Что бы вы ни делали, не используйте венгерские обозначения в стиле Win16/Win32. Даже Microsoft отказалась от этого, перейдя на платформу.NET.
IBOutlets
Исторически сложилось, что управление памятью торговых точек было плохим. В настоящее время рекомендуется объявлять торговые точки как свойства:
@interface MyClass :NSObject {
NSTextField *textField;
}
@property (nonatomic, retain) IBOutlet NSTextField *textField;
@end
Использование свойств делает семантику управления памятью понятной; это также обеспечивает непротиворечивый образец, если вы используете синтез переменных экземпляра.
Используйте статический анализатор LLVM/Clang
ПРИМЕЧАНИЕ. В Xcode 4 это теперь встроено в IDE.
Вы используете Clang Static Analyzer для того, чтобы - что неудивительно - анализировать ваш код на C и Objective-C (пока нет C++) в Mac OS X 10.5. Тривиально установить и использовать:
- Загрузите последнюю версию с этой страницы.
- Из командной строки
cd
в каталог вашего проекта. - казнить
scan-build -k -V xcodebuild
,
(Существуют некоторые дополнительные ограничения и т. Д., В частности, вы должны проанализировать проект в его конфигурации "Отладка" - подробности см. http://clang.llvm.org/StaticAnalysisUsage.html но это более или менее к чему это сводится.)
Затем анализатор создает для вас набор веб-страниц, на которых показано вероятное управление памятью и другие основные проблемы, которые компилятор не может обнаружить.
Это тонкий, но удобный. Если вы передаете себя в качестве делегата другому объекту, сбросьте делегат этого объекта перед 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;
@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"
Таким образом, они являются частью реального класса - и НЕ (частной) категории в дополнение к классу. Тонкое, но важное отличие.
Избегайте авто-релиза
Поскольку вы обычно (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;
}
Поскольку имя метода начинается с "new", потребители вашего API знают, что они ответственны за освобождение полученного объекта (см., Например, NSObjectController's newObject
метод).
(1) Вы можете получить контроль, используя свои собственные локальные пулы автоматического выпуска. Для получения дополнительной информации об этом см. Автозапуск пулов.
Некоторые из них уже упоминались, но вот что я могу придумать из головы:
- Следуйте правилам именования KVO. Даже если вы не используете KVO сейчас, по моему опыту часто это все еще полезно в будущем. И если вы используете KVO или привязки, вы должны знать, что все работает так, как они должны. Это относится не только к методам доступа и переменным экземпляра, но и ко многим отношениям, валидации, авто-уведомлению зависимых ключей и так далее.
- Поместите частные методы в категорию. Не только интерфейс, но и реализация. Хорошо иметь концептуальную дистанцию между частными и не приватными методами. Я включаю все в мой файл.m.
- Поместите фоновые методы потока в категорию. То же, что и выше. Я обнаружил, что хорошо сохранять четкий концептуальный барьер, когда вы думаете о том, что находится в главном потоке, а что нет.
- использование
#pragma mark [section]
, Обычно я группирую свои собственные методы, переопределения каждого подкласса и любую информацию или формальные протоколы. Это значительно облегчает переход к тому, что я ищу. По той же теме, сгруппируйте похожие методы (например, методы делегатов табличного представления) вместе, а не просто их где-то склеивайте. - Префикс частных методов & ivars с _. Мне нравится, как это выглядит, и я реже использую ивар, когда имею в виду собственность случайно.
- Не используйте методы / свойства мутатора в init & dealloc. У меня никогда не было ничего плохого из-за этого, но я могу видеть логику, если вы измените метод, чтобы сделать что-то, что зависит от состояния вашего объекта.
- Положите IBOutlets в свойствах. Я на самом деле только что прочитал это здесь, но я собираюсь начать делать это. Независимо от каких-либо преимуществ памяти, это кажется лучше стилистически (по крайней мере для меня).
- Избегайте написания кода, который вам не нужен. Это действительно охватывает много вещей, таких как создание иваров, когда
#define
будет делать, или кэшировать массив вместо сортировки каждый раз, когда данные необходимы. Я могу многое сказать по этому поводу, но суть в том, что не пишите код, пока он вам не понадобится, или профайлер не скажет вам об этом. Это делает вещи намного легче поддерживать в долгосрочной перспективе. - Завершите то, что вы начали. Имея много недоделанного, глючного кода - это самый быстрый способ убить мертвый проект. Если вам нужен метод-заглушка, это нормально, просто укажите его, поставив
NSLog( @"stub" )
внутри, или как вы хотите следить за вещами.
Написать юнит-тесты. Вы можете протестировать много вещей в Какао, которые могут быть сложнее в других средах. Например, с помощью кода пользовательского интерфейса вы можете в общем убедиться, что все подключено так, как должно быть, и поверить, что они будут работать при использовании. И вы можете легко настроить состояние и вызывать методы делегата для их проверки.
У вас также нет видимости открытых и защищенных и закрытых методов, мешающих написанию тестов для ваших внутренних объектов.
Золотое правило: если вы alloc
затем вы release
!
ОБНОВЛЕНИЕ: если вы не используете ARC
Не пишите Objective-C, как если бы это был Java/C#/C++/ и т. Д.
Однажды я видел, как команда разработчиков веб-приложений на Java EE пыталась написать настольное приложение Cocoa. Как будто это было веб-приложение Java EE. Вокруг было много AbstractFooFactory, FooFactory, IFoo и Foo, когда все, что им действительно нужно, это класс Foo и, возможно, протокол Fooable.
Частью гарантии того, что вы этого не сделаете, является истинное понимание различий в языке. Например, вам не нужны абстрактные фабричные и фабричные классы, описанные выше, потому что методы класса Objective C отправляются так же динамически, как методы экземпляра, и могут быть переопределены в подклассах.
Убедитесь, что вы добавили в закладки страницу " Отладка магии". Это должно быть вашей первой остановкой, когда вы будете биться головой о стену, пытаясь найти источник ошибки Какао.
Например, он расскажет вам, как найти метод, в котором вы сначала выделили память, которая позже вызывает сбои (например, во время завершения приложения).
Старайтесь избегать того, что я сейчас решил назвать Newbiecategoryaholism. Когда новички в Objective-C обнаруживают категории, они часто теряют самообладание, добавляя полезные маленькие категории к каждому существующему классу ("Что? Я могу добавить метод для преобразования числа в римские цифры в NSNumber"!).
Не делай этого.
Ваш код будет более переносимым и легким для понимания без использования десятков небольших методов категорий, разбросанных поверх двух десятков базовых классов.
Большую часть времени, когда вы действительно думаете, что вам нужен метод категории, чтобы помочь упростить некоторый код, вы обнаружите, что вы никогда не будете использовать этот метод повторно.
Есть и другие опасности, если только вы не используете пространство имен для методов вашей категории (и кто, помимо совершенно безумного ддрибина?), Есть вероятность, что Apple, или плагин, или что-то еще, работающее в вашем адресном пространстве, также определит ту же категорию. метод с тем же именем с немного другим побочным эффектом....
ХОРОШО. Теперь, когда вы были предупреждены, игнорируйте "не делайте эту часть". Но проявляйте крайнюю сдержанность.
Сортировка строк по желанию пользователя
Когда вы сортируете строки для представления пользователю, вы не должны использовать простые compare:
метод. Вместо этого вы всегда должны использовать локализованные методы сравнения, такие как localizedCompare:
или же localizedCaseInsensitiveCompare:
,
Для получения дополнительной информации см. Поиск, сравнение и сортировка строк.
Сопротивляйтесь подклассификации мира. В Какао многое делается с помощью делегирования и использования базовой среды выполнения, которая в других средах выполняется с помощью подклассов.
Например, в Java вы используете экземпляры анонимных *Listener
подклассы много и в.NET вы используете свой EventArgs
подклассов много. В Какао вы тоже этого не делаете - вместо этого используется цель-действие.
Объявленные свойства
Обычно вы должны использовать функцию объявленных свойств Objective-C 2.0 для всех ваших свойств. Если они не являются общедоступными, добавьте их в расширение класса. Использование объявленных свойств позволяет сразу же очистить семантику управления памятью и упростить вам проверку вашего метода dealloc - если вы сгруппируете объявления своих свойств вместе, вы можете быстро отсканировать их и сравнить с реализацией вашего метода dealloc.
Вы должны хорошо подумать, прежде чем помечать свойства как "неатомные". Как отмечается в Руководстве по языку программирования Objective C, свойства по умолчанию являются атомарными и требуют значительных затрат. Более того, простое превращение всех ваших свойств в атомарные не делает ваше приложение поточно-ориентированным. Также обратите внимание, что, если вы не указываете "неатомные" и реализуете свои собственные методы доступа (а не синтезируете их), вы должны реализовать их атомарным способом.
Подумайте о нулевых значениях
Как отмечает этот вопрос, сообщения nil
действительны в Objective-C. Хотя это часто является преимуществом - приводит к более чистому и более естественному коду - эта функция может иногда приводить к специфическим и трудно выявляемым ошибкам, если вы получаете nil
значение, когда вы не ожидали этого.
Используйте NSAssert и друзей. Я все время использую nil в качестве допустимого объекта... особенно отправка сообщений в nil совершенно допустима в Obj-C. Однако, если я действительно хочу убедиться в состоянии переменной, я использую NSAssert и NSParameterAssert, которые помогают легко отследить проблемы.
Простой, но часто забытый. Согласно спецификации:
В общем случае методы в разных классах, которые имеют один и тот же селектор (одно и то же имя), также должны иметь одинаковые типы возврата и аргумента. Это ограничение накладывается компилятором, чтобы разрешить динамическое связывание.
в этом случае все одинаковые именованные селекторы, даже если они находятся в разных классах, будут рассматриваться как имеющие идентичные типы возврата / аргумента. Вот простой пример.
@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;
}
Если вы используете Leopard (Mac OS X 10.5) или более позднюю версию, вы можете использовать приложение Instruments для поиска и отслеживания утечек памяти. После сборки вашей программы в XCode выберите "Выполнить"> "Начать с Performance Tool"> "Утечки".
Даже если ваше приложение не показывает утечек, вы можете хранить объекты слишком долго. В Инструментах вы можете использовать инструмент ObjectAlloc для этого. Выберите инструмент ObjectAlloc в документе "Инструменты" и откройте сведения об инструменте (если он еще не отображается), выбрав "Вид"> "Детали" (рядом с ним должна стоять галочка). В разделе "Срок действия выделения" в подробностях ObjectAlloc убедитесь, что вы выбрали переключатель рядом с "Создан и еще жив".
Теперь, когда вы прекратите запись своего приложения, выбор инструмента ObjectAlloc покажет вам, сколько ссылок есть на каждый еще живущий объект в вашем приложении в столбце "# Net". Убедитесь, что вы смотрите не только на свои собственные классы, но и на классы объектов верхнего уровня ваших файлов NIB. Например, если у вас нет окон на экране, и вы видите ссылки на еще живое NSWindow, возможно, вы не выпустили его в своем коде.
Убирайся в деилок.
Это одна из самых простых вещей, которую нужно забыть - особенно. при кодировании на 150 миль в час. Всегда, всегда, всегда очищайте ваши атрибуты / переменные-члены в dealloc.
Мне нравится использовать атрибуты Objc 2 - с новой точечной нотацией - так что это делает очистку безболезненной. Часто так просто, как:
- (void)dealloc
{
self.someAttribute = NULL;
[super dealloc];
}
Это позаботится о выпуске и установит для атрибута значение NULL (что я считаю защитным программированием - в случае, если другой метод, расположенный ниже в dealloc, снова получит доступ к переменной-члену - редко, но может произойти).
С включенным GC в 10.5, это больше не нужно, но вам может понадобиться очистить другие ресурсы, которые вы создаете, вы можете сделать это в методе finalize.
Все эти комментарии великолепны, но я действительно удивлен, что никто не упомянул руководство по стилю Google Objective-C, которое было опубликовано некоторое время назад. Я думаю, что они проделали очень тщательную работу.
Также, полу-связанная тема (с местом для большего количества ответов!):
Что это за маленькие советы и хитрости Xcode, о которых вы хотели бы знать около 2 лет назад?,
Не забывайте, что NSWindowController и NSViewController будут освобождать объекты верхнего уровня файлов NIB, которыми они управляют.
Если вы вручную загружаете файл NIB, вы несете ответственность за освобождение объектов верхнего уровня этой NIB по завершении работы с ними.
Один довольно очевидный для новичка: использовать функцию авто-отступа Xcode для вашего кода. Даже если вы копируете / вставляете из другого источника, после того, как вы вставили код, вы можете выбрать весь блок кода, щелкнуть по нему правой кнопкой мыши, а затем выбрать опцию для повторного отступа всего в этом блоке.
Xcode на самом деле проанализирует этот раздел и сделает отступ с помощью скобок, циклов и т. Д. Это намного эффективнее, чем нажатие клавиши пробела или клавиши табуляции для каждой строки.
Включите все предупреждения GCC, а затем отключите те, которые регулярно вызываются заголовками Apple, для уменьшения шума.
Также часто запускайте статический анализ Clang; Вы можете включить его для всех сборок с помощью параметра сборки "Запустить статический анализатор".
Напишите модульные тесты и запускайте их с каждой сборкой.
Переменные и свойства
1/ Поддержание чистоты ваших заголовков, скрытие реализации
Не включайте переменные экземпляра в свой заголовок. Закрытые переменные помещаются в продолжение класса как свойства. Открытые переменные объявляются как открытые свойства в вашем заголовке. Если это должно быть только чтение, объявите это как только для чтения и переписайте это как readwrite в продолжении класса. В основном я не использую переменные вообще, только свойства.
2 / Дайте вашим свойствам имя переменной не по умолчанию, например:
@synthesize property = property_;
Причина 1: вы будете ловить ошибки, вызванные забыванием "я". при назначении имущества. Причина 2: из моих экспериментов, Leak Analyzer в инструментах имеет проблемы с обнаружением утечки свойства с именем по умолчанию.
3 / Никогда не используйте retain или release непосредственно в свойствах (или только в очень исключительных ситуациях). В вашем коллеже просто присвойте им ноль. Свойства сохранения предназначены для обработки сохранения / освобождения сами по себе. Вы никогда не знаете, если сеттер не добавляет, например, наблюдателей. Вы должны использовать переменную непосредственно только внутри ее установщика и получателя.
Просмотры
1/ Поместите каждое определение представления в xib, если можете (исключение обычно составляют параметры динамического содержимого и слоя). Это экономит время (это проще, чем написание кода), его легко изменить, и он сохраняет ваш код в чистоте.
2 / Не пытайтесь оптимизировать просмотры, уменьшая количество просмотров. Не создавайте UIImageView в вашем коде вместо xib только потому, что вы хотите добавить в него подпредставления. Вместо этого используйте UIImageView в качестве фона. Каркас представления может обрабатывать сотни представлений без проблем.
3 / IBOutlets не всегда должны быть сохранены (или сильны). Обратите внимание, что большинство ваших IBOutlets являются частью вашей иерархии представлений и, следовательно, неявно сохраняются.
4 / Освободить все IBOutlets в viewDidUnload
5 / Вызовите viewDidUnload из вашего метода dealloc. Это неявно называется.
объем памяти
1/ Автоселение объектов при их создании. Многие ошибки вызваны перемещением вашего вызова освобождения в одну ветку if-else или после оператора return. Release вместо autorelease следует использовать только в исключительных ситуациях - например, когда вы ожидаете цикл запуска и не хотите, чтобы ваш объект был автоматически освобожден слишком рано.
2 / Даже если вы используете автоматический подсчет ссылок, вы должны прекрасно понимать, как работают методы фиксированного выпуска. Использование retain-release вручную не сложнее, чем ARC, в обоих случаях вам приходится иметь дело с утечками и циклами сохранения. Подумайте об использовании retain-release вручную для больших проектов или сложных иерархий объектов.
Комментарии
1/ Сделайте ваш код с автодокументацией. Каждое имя переменной и имя метода должны сообщать, что они делают. Если код написан правильно (вам нужно много практиковаться в этом), вам не понадобятся комментарии к коду (не то же самое, что комментарии к документации). Алгоритмы могут быть сложными, но код должен быть всегда простым.
2 / Иногда вам понадобится комментарий. Обычно для описания неочевидного поведения кода или взлома. Если вы чувствуете, что должны написать комментарий, сначала попробуйте переписать код, чтобы он был проще и без комментариев.
вдавливание
1/ Не увеличивайте отступ слишком сильно. Большая часть кода вашего метода должна иметь отступ на уровне метода. Вложенные блоки (если и т. Д.) Снижают читабельность. Если у вас есть три вложенных блока, вы должны попытаться поместить внутренние блоки в отдельный метод. Четыре или более вложенных блока никогда не должны использоваться. Если большая часть кода вашего метода находится внутри if, отмените условие if, например:
if (self) {
//... long initialization code ...
}
return self;
if (!self) {
return nil;
}
//... long initialization code ...
return self;
Понимать код C, в основном структуры C
Обратите внимание, что Obj-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 Coding, стандартов Google Obj-C/C++ и наших собственных дополнений. Документируйте свой код, используйте стандартные стандартные отступы, пробелы и пустые строки в нужных местах и т. Д.
Я знаю, что упустил это из виду, когда впервые попал в программирование Какао.
Убедитесь, что вы понимаете обязанности по управлению памятью относительно файлов NIB. Вы несете ответственность за освобождение объектов верхнего уровня в любом загружаемом вами файле NIB. Прочитайте документацию Apple по этому вопросу.
Будь более функциональным.
Objective-C является объектно-ориентированным языком, но в функциональном стиле фреймворка Cocoa и во многих случаях разработан функциональный стиль.
Существует разделение изменчивости. Используйте неизменяемые классы в качестве основного и изменяемый объект в качестве дополнительного. Например, используйте в первую очередь NSArray, и используйте NSMutableArray только тогда, когда вам нужно.
Есть чистые функции. Не так уж и много, покупайте многие из API-интерфейсов, разработанных как чистые функции. Посмотрите на такие функции, как
CGRectMake()
или жеCGAffineTransformMake()
, Очевидно, форма указателя выглядит более эффективно. Однако косвенный аргумент с указателями не может предложить без побочных эффектов. Дизайн конструкций чисто как можно больше. Отделяйте даже государственные объекты. использование-copy
вместо-retain
при передаче значения другому объекту. Потому что разделяемое состояние может молча влиять на изменение значения в другом объекте. Так что не может быть без побочных эффектов. Если у вас есть значение из внешнего объекта, скопируйте его. Поэтому также важно, чтобы общее состояние было минимальным.
Однако не бойтесь использовать нечистые функции тоже.
Есть ленивая оценка. Увидеть что-то вроде
-[UIViewController view]
имущество. Представление не будет создано при создании объекта. Он будет создан при чтении звонящегоview
недвижимость в первый раз.UIImage
не будет загружен, пока не будет нарисован. Есть много реализаций, подобных этой конструкции. Подобные конструкции очень полезны для управления ресурсами, но если вы не знаете концепцию отложенной оценки, их поведение непросто понять.Есть закрытие. Используйте C-блоки как можно больше. Это значительно упростит вашу жизнь. Но прочитайте еще раз о блок-памяти управления, прежде чем использовать его.
Есть полуавтоматический GC. NSAutoreleasePool. использование
-autorelease
первична. Используйте руководство-retain/-release
второстепенный, когда вам действительно нужно. (например: оптимизация памяти, явное удаление ресурса)