2008-10-05 2 views
345

Я только что начал программировать Objective-C и, имея фон в Java, задаюсь вопросом, как люди, пишущие программы Objective-C, имеют дело с частными методами.Лучший способ определить частные методы для класса в Objective-C

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

Просьба включить аргумент в ваш подход при его публикации. Почему это хорошо? Какие недостатки у него есть (что вы знаете) и как вы с ними справляетесь?


Что касается моих выводов до сих пор.

Возможно использование categories [например. MyClass (Private)], определенный в файле MyClass.m, чтобы группировать частные методы.

Этот подход имеет 2 вопроса:

  1. Xcode (и компилятор?) Не проверяет, если вы определите все методы в частном категории в соответствующем блоке
  2. @implementation Вы должны поставить @interface объявляя ваш частный категория в начале MyClass.m файла, в противном случае Xcode жалуется с сообщением вроде «я не может ответить на сообщение„privateFoo“.

Первый вопрос можно решить с empty category [например MyClass()].
Второй меня беспокоит. Я бы хотел, чтобы частные методы были реализованы (и определены) ближе к концу файла; Я не знаю, возможно ли это.

+1

Люди могут найти этот вопрос интересным: http://stackoverflow.com/questions/2158660/why-doesnt-objective-c-support-private-methods – bbum 2010-03-03 18:35:50

+4

Почему бы просто [опустить объявление частного метода] (http://stackoverflow.com/questions/6767129/objective-c-should-i-declare-private-methods)? – ma11hew28 2011-07-20 19:06:43

ответ

37

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

+4

Это решение имеет то преимущество, что оно позволяет избежать избыточной структуры программы, чтобы избежать предупреждения о компиляторе. – 2010-06-23 03:06:19

+1

Я тоже делаю это, но также не являюсь экспертом Objective-C.Для экспертов существует ли какая-либо причина не делать это таким образом (кроме вопроса о заказе метода)? – 2010-11-10 17:16:18

+2

Метод упорядочения кажется второстепенной проблемой, но если вы переводите его на ** читаемость кода **, это может стать довольно важной проблемой, особенно при работе в команде. – borisdiakur 2012-09-05 20:33:01

48

В Objective-C нет особого «частного метода», если время выполнения может решить, какая реализация будет использовать его. Но это не означает, что нет методов, которые не являются частью документированного интерфейса. Для этих методов я считаю, что категория прекрасна. Вместо того, чтобы помещать @interface в начало файла .m как ваша точка 2, я бы поместил его в свой .h-файл. Соглашение, которое я придерживаюсь (и видел в другом месте, я думаю, что это соглашение Apple, поскольку Xcode теперь дает ему автоматическую поддержку) означает называть такой файл после его класса и категории с + разделяющим их, поэтому @interface GLObject (PrivateMethods) можно найти в GLObject+PrivateMethods.h. Причина предоставления файла заголовка заключается в том, что вы можете импортировать его в свои тестовые классы :-).

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

@implementation GLObject(PrivateMethods) 
- (void)secretFeature; 
@end 

или с расширением класса (то, что вы называете «пустой категорией»), просто определите эти методы последними. Методы Objective-C могут быть определены и использованы в любом порядке реализации, поэтому вам нечего мешать вам помещать «частные» методы в конец файла.

Даже с расширениями классов я часто создаю отдельный заголовок (GLObject+Extension.h), чтобы при необходимости использовать эти методы, имитируя видимость «друг» или «защищенный».

Поскольку этот ответ был изначально написан, компилятор clang начал выполнять два прохода для методов Objective-C. Это означает, что вы можете полностью отказаться от объявления своих «частных» методов, и будут ли они выше или ниже вызывающего сайта, они будут найдены компилятором.

1

Невозможно обойти проблему №2. Именно так работает компилятор C (и, следовательно, компилятор Objective-C). Если вы используете редактор XCode, всплывающее окно функции должно облегчить навигацию по @interface и @implementation блокам в файле.

14

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

//.h file 
@interface MyClass : Object 
{ 
    int test; 
} 
- (void) someMethod: anArg; 

@end 


//.m file  
@implementation MyClass 

static void somePrivateMethod (MyClass *myClass, id anArg) 
{ 
    fprintf (stderr, "MyClass (%d) was passed %p", myClass->test, anArg); 
} 


- (void) someMethod: (id) anArg 
{ 
    somePrivateMethod (self, anArg); 
} 

@end 
427

Существует нет, как уже говорили другие, такие как частный метод в Objective-C. Однако, начиная с Objective-C 2.0 (что означает Mac OS X Leopard, iPhone OS 2.0 и более поздние версии), вы можете создать категорию с пустым именем (т. Е. @interface MyClass()) под названием Расширение класса. Что уникально в расширении класса, так это то, что реализация метода должна идти в том же @implementation MyClass, что и общедоступные методы. Поэтому я структурировать мои классы, как это:

В файле .h:

@interface MyClass { 
    // My Instance Variables 
} 

- (void)myPublicMethod; 

@end 

И в файле .m:

@interface MyClass() 

- (void)myPrivateMethod; 

@end 

@implementation MyClass 

- (void)myPublicMethod { 
    // Implementation goes here 
} 

- (void)myPrivateMethod { 
    // Implementation goes here 
} 

@end 

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

2

Если вы хотите избежать блока @interface в верхней части, вы всегда можете помещать частные объявления в другой файл MyClassPrivate.h не идеально, но его не загромождать реализацию.

MyClass.h

interface MyClass : NSObject { 
@private 
    BOOL publicIvar_; 
    BOOL privateIvar_; 
} 

@property (nonatomic, assign) BOOL publicIvar; 
//any other public methods. etc 
@end 

MyClassPrivate.h

@interface MyClass() 

@property (nonatomic, assign) BOOL privateIvar; 
//any other private methods etc. 
@end 

MyClass.m

#import "MyClass.h" 
#import "MyClassPrivate.h" 
@implementation MyClass 

@synthesize privateIvar = privateIvar_; 
@synthesize publicIvar = publicIvar_; 

@end 
4

каждые объекты в Objective C соответствуют протоколу NSObject, который держит на performSelector : способ. Я также ранее искал способ создания некоторых «вспомогательных или частных» методов, которые мне не нужно было публиковать на публичном уровне. Если вы хотите создать частный метод без каких-либо накладных расходов и не указывая его в своем файле заголовка, тогда дайте этот снимок ...

-(void)myHelperMethod: (id) sender{ 
    // code here... 
} 

тогда, когда вам нужно ссылаться на метод просто назвать это как селектор ...

[self performSelector:@selector(myHelperMethod:)]; 

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

1

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

3

Вы можете использовать блоки?

@implementation MyClass 

id (^createTheObject)() = ^(){ return [[NSObject alloc] init];}; 

NSInteger (^addEm)(NSInteger, NSInteger) = 
^(NSInteger a, NSInteger b) 
{ 
    return a + b; 
}; 

//public methods, etc. 

- (NSObject) thePublicOne 
{ 
    return createTheObject(); 
} 

@end 

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

2

Еще одна вещь, которую я не видел здесь - Xcode поддерживает файлы .h с именем «_private» в названии. Предположим, у вас есть класс MyClass - у вас есть MyClass.m и MyClass.h, и теперь у вас также может быть MyClass_private.h. Xcode распознает это и включит его в список «Контрагенты» в редакторе помощников.

//MyClass.m 
#import "MyClass.h" 
#import "MyClass_private.h" 
17

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

В некоторых случаях вам необходимо объявить метод в продолжении класса (например, при использовании селектора между продолжением класса и @implementation).

static функции очень хороши для особо чувствительных или скоростных критических частных методов.

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

Именованные категории (например, @interface MONObject (PrivateStuff)) не являются особенно хорошей идеей из-за потенциальных конфликтов имен при загрузке. Они действительно полезны только для друзей или защищенных методов (что очень редко бывает хорошим выбором). Для того, чтобы убедиться, что вы предупреждены о неполной реализации категории, вы должны на самом деле осуществить это:

@implementation MONObject (PrivateStuff) 
...HERE... 
@end 

Вот немного аннотированный шпаргалка:

MONObject.h

@interface MONObject : NSObject 

// public declaration required for clients' visibility/use. 
@property (nonatomic, assign, readwrite) bool publicBool; 

// public declaration required for clients' visibility/use. 
- (void)publicMethod; 

@end 

MONObject.m

@interface MONObject() 
@property (nonatomic, assign, readwrite) bool privateBool; 

// you can use a convention where the class name prefix is reserved 
// for private methods this can reduce accidental overriding: 
- (void)MONObject_privateMethod; 

@end 

// The potentially good thing about functions is that they are truly 
// inaccessible; They may not be overridden, accidentally used, 
// looked up via the objc runtime, and will often be eliminated from 
// backtraces. Unlike methods, they can also be inlined. If unused 
// (e.g. diagnostic omitted in release) or every use is inlined, 
// they may be removed from the binary: 
static void PrivateMethod(MONObject * pObject) { 
    pObject.privateBool = true; 
} 

@implementation MONObject 
{ 
    bool anIvar; 
} 

static void AnotherPrivateMethod(MONObject * pObject) { 
    if (0 == pObject) { 
     assert(0 && "invalid parameter"); 
     return; 
    } 

    // if declared in the @implementation scope, you *could* access the 
    // private ivars directly (although you should rarely do this): 
    pObject->anIvar = true; 
} 

- (void)publicMethod 
{ 
    // declared below -- but clang can see its declaration in this 
    // translation: 
    [self privateMethod]; 
} 

// no declaration required. 
- (void)privateMethod 
{ 
} 

- (void)MONObject_privateMethod 
{ 
} 

@end 

Другой подход, который может быть неочевидным: тип C++ может быть ботом h очень быстро и обеспечивают гораздо более высокую степень контроля, минимизируя количество экспортированных и загруженных методов objc.

Смежные вопросы