Именование экземпляра переменной переменной/метода в Objective C

В чем заключаются следующие соглашения для обозначения переменных экземпляра и аргументов метода, особенно когда аргументы метода используются для установки ivars (переменные экземпляра)?

В С++ я часто использовал префикс m_ для ivars. В С# я следовал за конвенцией о том, чтобы однозначно использовать this. для ivars. С тех пор я тоже принял эквивалент на С++ (this->).

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

Если кто-то не предложит что-то действительно приятное, я смирился с тем, что мне придется идти на компромисс (но, пожалуйста, не заставляйте меня использовать префикс the для args!), поэтому мне интересно узнать, что большинство говорят - особенно от тех, кто некоторое время использует ObjC.

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

Они дают мне некоторые идеи, но я все еще хочу услышать, что делают другие.

[править] Просто уточнить: конкретно, как вы отличаете ivars от аргументов метода, которые я ищу - будь то с помощью префиксов или какой-либо другой техники.

[edit 2] Спасибо за все ответы и обсуждения. Я не закрываю это, но просто скажу, что, как я указал в своих комментариях к принятому ответу, я пошел с соглашением о префиксах init args с the (и setter args с new, который я все равно). Кажется, это лучший баланс сил - даже если я не увлекаюсь эстетикой.

Ответы

Ответ 1

Как вы уже отмечали, стиль Cocoa должен использовать имена аргументов метода, такие как theValue, если имя аргумента будет конфликтовать с переменной экземпляра. Однако не должно быть много раз, что это происходит в коде стиля Objective-C 2.0. Предполагается, что вы не должны (обычно) напрямую обращаться к переменным экземпляра. В основном это происходит из-за того, что это обходит механизмы наблюдения за ключевыми значениями в Cocoa. Скорее, ожидается, что вы будете получать доступ и изменять свойства с помощью методов getter/setter. В Objective-C 2.0 легко объявить эти свойства и автоматически @synthesize геттеры/сеттеры, поэтому нет смысла оправдывать их использование. Фактически, в 64-битных системах среда выполнения автоматически создаст переменные экземпляра для вас, избавившись от необходимости объявлять их и уменьшая желание их использовать.

Единственный раз, когда вы непосредственно обращаетесь к переменным экземпляра, находится в методах -init и -dealloc:

@interface MyObject : NSObject 
{
  id ivar;
}

@property (retain,readwrite) id ivar; //or whatever retain/copy/assign and read/readwrite makes sense
@end

@implementation MyObject
@synthesize ivar;

- (id)initWithIvar:(id)theIvar {
  if(self = [super init]) {
    ivar = theIvar;
  }

  return self;
}

- (void)dealloc {
  [ivar release];
}

Причина, по которой ivar следует использовать непосредственно в этих случаях, является причиной того, что геттер/сеттер может иметь побочные эффекты, которые зависят от полностью инициализированного экземпляра, что делает их опасными в -init и -dealloc, где состояние объекта полностью инициализируется. Во всех остальных случаях вы должны использовать self.ivar (или [self ivar] и [self setIvar:newValue]).

Казалось бы, что методы, отличные от -initWithXX, не должны иметь конфликт имен. Если они это сделают, не должны ли они быть реорганизованы, чтобы не иметь этот параметр или для класса не иметь переменную экземпляра?

Это оставляет только методы -initWithXX, где вы часто находите конфликт между аргументами и ivars. В этом случае вы можете использовать любой из указанных вами подходов, если вы действительно не можете выдержать стиль Cocoa. Префикс с _ работает и относительно распространен (я полагаю, что настройки @synthesize 'd seters и getters будут автоматически делать правильные вещи в этом случае, но вам может потребоваться явно установить _ivar в качестве поддержки).

Ответ 3

Чтобы завершить все известные Objective-C стилегиды здесь, это версия Google. Они делают это, чтобы добавить символ подчеркивания после члена varname. Например BOOL isActive_;.
Поэтому сделайте выбор и придерживайтесь его. Я также предпочитаю префикс "_" для своих приложений.

Ответ 4

Пример кода, созданного Apple, обычно использует префикс "_". Я думаю, что я также видел некоторые, используя mFoo или m_foo. Некоторые вообще не беспокоятся о префиксах и просто используют нормальное имя, однако это путает позже. В общем случае при определении параметров метода соглашение об именах заключается в использовании префикса "a", "an", "the" или "new". Например:

@interface Foo : NSObject {
    id _bar;
}
@property (nonatomic, retain) id bar;

- (id) initWithBar:(id)aBar;

@end

@implementation Foo
@synthesize bar = _bar;

- (id) initWithBar:(id)aBar {
    self = [super init];
    if(self != nil) {
        _bar = aBar;
    }
    return self;
}

@end

Я нахожу, что это соглашение работает очень хорошо. Раньше я не беспокоился о префиксе, но иногда это приводило в замешательство. Использование префикса ясно указывает, что это переменная экземпляра. Соглашение @synthesize bar = _bar используется Apple в их образце кода (iPhone).

Обычно переменная экземпляра обычно не используется, поэтому, если вы находите, что префикс "_" раздражает, это не имеет значения, потому что вы использовали бы [self bar] (или self.bar, если вы входите в этот тип вещь) в любом случае.

Ответ 5

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

Вы также можете получить доступ к переменным в Obj-C через self. Поэтому, если у вас есть тест переменной экземпляра, вы можете получить к нему доступ через self- > test, это законно и всегда будет работать. Однако это не красиво в глазах большинства программистов Obj-C. Это отдает "секрет", что объекты на самом деле являются просто структурами (точнее, объектные ссылки являются указателями на структуры), а экземпляры vars на самом деле являются членами структуры. Не то чтобы это действительно секретно, но программисты Obj-C, похоже, предпочитают "скрывать" этот факт в своем коде.

Использование подчеркивания "_" в названии - очень плохая идея. Кто-то здесь указал, что Apple резервирует знак для своего кода, но на самом деле GCC уже резервирует знак подчеркивания для имен символов. Точнее, уже в стандарте ANSI-C указано, что переменные, начинающиеся с двух подчеркиваний или одного подчеркивания и буквы верхнего регистра, зарезервированы для внутреннего использования компилятора. Таким образом, использование одного подчеркивания теоретически справедливо, но случайно запустим имя с буквой в верхнем регистре и оно станет недействительным.

До сих пор я пытался использовать префикс my, myName вместо имени и использовать префикс self, selfName вместо имени; сначала выглядит как-то странно, но в огромном фрагменте кода он не выглядит слишком плохим. По крайней мере, сразу попадает в глаза как "разные". Я также просто попробовал один "i", iName вместо имени (или вместо имени), но я не был очень доволен этим решением.

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

- (NSImage *)loadImage:(int)imageNumber
{
  NSImage * res;

  // Some code that assigns a value to res
  // ...  

  // Re-use imageNumber for a different purpose
  for (imageNumber = 0; ...; ...) {
     // Some code
  }

  return res;
}

Я не вижу проблем с этим кодом. Почему мне нужно объявить вторую переменную стека для этого, если имя все еще имеет смысл (если я не повторяю образы по номеру в цикле for, это имя не имеет никакого смысла, в этом случае я бы использовал другая переменная для него - компилятор может фактически зарезервировать только один int для стека для обоих).