Objective-C «сообщения» - как правильно читать?

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

[AttributeUsage (AttributeTargets::Class)]
public ref class ControlDescriptionAttribute : Attribute
{
public:
  ControlDescriptionAttribute (String ^name, String ^description) :
    _name (name),
    _description (description)
  {
  }

  property String ^Name
  {
    String ^get () { return _name; }
  }

  property String ^Description
  {
    String ^get () { return _description; }
  }

private:
  String
    ^ _name,
    ^ _description;
};

и я применяю его к классу как это:

[ControlDescription ("Pie Chart", "Displays a pie chart")]
public ref class PieControl sealed : UserControl
{
  // stuff
};

, который является тем, что сказали предыдущие плакаты.

Для использования атрибута редактор имеет Generic::List <Type> содержащий типы управления. Существует поле списка, от которого пользователь может перетащить и отбросить на страницу для создания экземпляра управления. Для заполнения поля списка я добираюсь ControlDescriptionAttribute для управления и заполняю запись в списке:

// done for each control type
array <Object ^>
  // get all the custom attributes
  ^attributes = controltype->GetCustomAttributes (true);

Type
  // this is the one we're interested in
  ^attributetype = ECMMainPageDisplay::ControlDescriptionAttribute::typeid;

// iterate over the custom attributes
for each (Object ^attribute in attributes)
{
  if (attributetype->IsInstanceOfType (attribute))
  {
    ECMMainPageDisplay::ControlDescriptionAttribute
      ^description = safe_cast <ECMMainPageDisplay::ControlDescriptionAttribute ^> (attribute);

    // get the name and description and create an entry in the list
    ListViewItem
      ^item = gcnew ListViewItem (description->Name);

    item->Tag = controltype->Name;
    item->SubItems->Add (description->Description);

    mcontrols->Items->Add (item);
    break;
  }
}

Примечание: вышеупомянутое является C++ / CLI, но не трудно преобразовать в C# (да, я знаю, C++ / CLI является отвращением, но это - то, что я должен работать с:-()

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

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

8
задан Jed Smith 9 November 2009 в 01:20
поделиться

5 ответов

Перво-наперво: в качестве стилистической заметки, соедините фигурные скобки:

[ Person alloc ]

должно быть

[Person alloc]

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

Person *p = [[Person alloc] init];

Чтобы почувствовать, как объявлять методы, требуется немного времени. Полезно изучить, как фреймворк называет свои методы. Для вашего конкретного примера, я думаю, вы слишком изобретательны. Вы ищете что-то вроде этого:

Person *john = [[Person alloc] initWithName:@"John"];
Person *kelly = [[Person alloc] initWithName:@"Kelly"];

[john greetPerson:kelly withGreeting:@"Hey babe."];
[kelly greetPerson:john withGreeting:@"Get bent."];

Обратите внимание, что я тоже не использовал заглавные буквы g в greetPerson . Это стилистическое соглашение Objective-C.

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

[john sendEmailToPerson:kelly withSubject:subject body:body attachments:nil];

Видите, как это происходит? И даже это оставляет желать лучшего, я еще не освоил это. Дайте ему время.

Очень полезный документ по этому поводу - это Apple Coding Guidelines for Cocoa .


Также выйдите из ловушки C. Вот как я бы написал всю вашу программу (я представляю кучу концепций, так что не ожидайте, что все это поймете):

#import <Foundation/Foundation.h>

@interface Person : NSObject {
    NSString *name;
}

@property (copy) NSString *name;

- (id)init;
- (id)initWithName:(NSString *)nm;
- (void)greetPerson:(Person *)who withGreeting:(NSString *)grt;

@end

@implementation Person
@synthesize name;

- (id)init {
    if (self = [super init]) {
        name = @"James Bond";          // not necessary, but default
    }                                  // values don't hurt.
    return self;
}
- (id)initWithName:(NSString *)nm {
    if (self = [self init]) {
       name = [nm copy];
    }
    return self;
}

- (void)greetPerson:(Person *)who withGreeting:(NSString *)grt {
    NSLog(@"%@ says '%@' to %@", self.name, grt, who.name);
}

- (void)dealloc {
    [name release];
    [super dealloc];
}

@end

int main(int argc, const char * argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    Person *john = [[Person alloc] initWithName:@"John"];
    Person *kelly = [[Person alloc] initWithName:@"Kelly"];

    [john greetPerson:kelly withGreeting:@"StackOverflow is great, isn't it?"];
    [kelly greetPerson:john withGreeting:@"Weren't we supposed to flirt?"];

    [john release];
    [kelly release];

    [pool drain];
    return 0;
}

Этот код полностью не протестирован, поэтому, если он работает без сбоев, я получить должное впечатление.

s Руководство по кодированию для Какао .


Также выйдите из ловушки C. Вот как я бы написал всю вашу программу (я представляю кучу концепций, так что не ожидайте, что вы все поймете):

#import <Foundation/Foundation.h>

@interface Person : NSObject {
    NSString *name;
}

@property (copy) NSString *name;

- (id)init;
- (id)initWithName:(NSString *)nm;
- (void)greetPerson:(Person *)who withGreeting:(NSString *)grt;

@end

@implementation Person
@synthesize name;

- (id)init {
    if (self = [super init]) {
        name = @"James Bond";          // not necessary, but default
    }                                  // values don't hurt.
    return self;
}
- (id)initWithName:(NSString *)nm {
    if (self = [self init]) {
       name = [nm copy];
    }
    return self;
}

- (void)greetPerson:(Person *)who withGreeting:(NSString *)grt {
    NSLog(@"%@ says '%@' to %@", self.name, grt, who.name);
}

- (void)dealloc {
    [name release];
    [super dealloc];
}

@end

int main(int argc, const char * argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    Person *john = [[Person alloc] initWithName:@"John"];
    Person *kelly = [[Person alloc] initWithName:@"Kelly"];

    [john greetPerson:kelly withGreeting:@"StackOverflow is great, isn't it?"];
    [kelly greetPerson:john withGreeting:@"Weren't we supposed to flirt?"];

    [john release];
    [kelly release];

    [pool drain];
    return 0;
}

Этот код полностью не протестирован, поэтому, если он работает без сбоев, я получить должное впечатление.

s Руководство по кодированию для Какао .


Также выйдите из ловушки C. Вот как я бы написал всю вашу программу (я представляю кучу концепций, так что не ожидайте, что все это поймете):

#import <Foundation/Foundation.h>

@interface Person : NSObject {
    NSString *name;
}

@property (copy) NSString *name;

- (id)init;
- (id)initWithName:(NSString *)nm;
- (void)greetPerson:(Person *)who withGreeting:(NSString *)grt;

@end

@implementation Person
@synthesize name;

- (id)init {
    if (self = [super init]) {
        name = @"James Bond";          // not necessary, but default
    }                                  // values don't hurt.
    return self;
}
- (id)initWithName:(NSString *)nm {
    if (self = [self init]) {
       name = [nm copy];
    }
    return self;
}

- (void)greetPerson:(Person *)who withGreeting:(NSString *)grt {
    NSLog(@"%@ says '%@' to %@", self.name, grt, who.name);
}

- (void)dealloc {
    [name release];
    [super dealloc];
}

@end

int main(int argc, const char * argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    Person *john = [[Person alloc] initWithName:@"John"];
    Person *kelly = [[Person alloc] initWithName:@"Kelly"];

    [john greetPerson:kelly withGreeting:@"StackOverflow is great, isn't it?"];
    [kelly greetPerson:john withGreeting:@"Weren't we supposed to flirt?"];

    [john release];
    [kelly release];

    [pool drain];
    return 0;
}

Этот код полностью не протестирован, поэтому, если он работает без сбоев, я получить должное впечатление.

20
ответ дан 5 December 2019 в 06:23
поделиться

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

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

Наиболее распространенный способ решения этой проблемы - сделать имя метода комбинацией «что он / делает» и метки для первого параметр. Пример:

 NSColor * color = [NSColor colorWithDeviceRed:0.5 green:0.5 blue:0.5 alpha:0.5];

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

Быстрый ответ состоит в том, что эти два имени предназначены для разные аудитории; один предназначен для пользователя метода, второй - автору метода. Снова рассмотрим приведенный выше пример. Объявление метода выглядит так:

+ (NSColor *)colorWithDeviceRed:(CGFloat)red
                          green:(CGFloat)green
                           blue:(CGFloat)blue
                          alpha:(CGFloat)alpha

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

Фактические имена параметров (части после типа) используются внутри ] определение метода, и как таковые существуют только для программиста, который пишет метод, поскольку это переменные, которые будут доступны в самом теле метода.

4
ответ дан 5 December 2019 в 06:23
поделиться

Первой «частью» метода является селектор , в вашем примере он включает -greet: toPerson: greetWith: , это фактическое имя метода.

Вторая «часть» - это параметры метода, в вашем примере они предназначены для приветствия.

Это похоже на что-то вроде C, где у вас было бы

int greet(string to, string greeting) {
    print(greeting, to);
}

Я также должен упомяните, вы, вероятно, захотите работать с NSString * вместо char * и NSLog () вместо printf () (не волнуйтесь, работает почти так же).

2
ответ дан 5 December 2019 в 06:23
поделиться

Вероятно, это было бы так:

[personJohn greetPerson:@"Kelly" withGreeting:@"hey babe"];

Объект person уже является Джоном, и он приветствует объект другого человека, который я бы не определил как строку, как вы, а вместо этого как другой экземпляр класса Person, а затем вы можете выполнить greetWithString .

[personJohn greetPerson:personKelly withGreeting:@"hey babe"];

Вы не определяете параметры дважды, вот где вы запутались. Если вы знаете C ++, у вас обычно есть:

void greetPerson(Person thePerson, string greeting);

в качестве, например, прототипа функции. Тогда вы бы назвали это так:

greetPerson(personKelly, "hey babe");

Все, что делает objective-c, облегчает вам задачу, будучи самодокументированным. Вместо того, чтобы просто помещать параметры в функции, вы называете их перед тем, как указывать их, поэтому приведенный выше вызов будет:

greetPerson(Person:personKelly, greeting:"hey babe");

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

0
ответ дан 5 December 2019 в 06:23
поделиться

Имя описанного выше метода - «Greet: toPerson: greetWith:». Двоеточие являются частью имени. Параметры (и их спецификаторы типа) - нет.

Примечание по стилю: не начинайте имя метода с символа верхнего регистра, если вы не ссылаетесь на аббревиатуру (например, «URL»).

0
ответ дан 5 December 2019 в 06:23
поделиться