Подтвердить что ты не робот

Каким образом частные и общественные члены будут внедрены в objective-c?

У меня было некоторое обсуждение, связанное с использованием свойств и переменных экземпляра на работе, поэтому я хотел бы найти для них ответ вики. Теперь я знаю, что в objective-c нет реального частного типа члена, все довольно широко. Тем не менее, я немного обеспокоен тем, как мы должны разрабатывать наши классы, а также соблюдать принципы ООП. Я хотел бы услышать мнения об этих трех подходах к разработке:

а. Согласно различным статьям и даже новым курсам развития iPhone в Стэнфордском университете, вы всегда должны использовать свойства везде, где можете. Однако IMHO, этот подход тормозит принципы проектирования ООП, поскольку в этом случае все участники становятся общедоступными. Зачем мне публиковать все внутренние/локальные переменные экземпляра снаружи? Кроме того, есть некоторые очень небольшие (но все же) накладные расходы, если вы используете синтезированные сеттеры через свойства, вместо этого используете локальный ivar напрямую. Здесь образец:

//==== header file =====//
@interface MyClass : NSObject

@property (nonatomic, retain) NSString *publicMemberWithProperty;
@property (nonatomic, retain) NSString *propertyForPrivateMember;

@end

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

//==== header file =====//
@interface MyClass : NSObject{
  NSString *_privateMember;
}

@property (nonatomic, retain) NSString *publicMemberWithProperty;

@end

С. Объявлять чистые свойства (без объявления относительных ivars) для публичных членов в файле заголовка и объявлять чистые свойства (без объявления относительных ivars) для частных членов в частном интерфейсе в файле реализации. Такой подход ИМХО более ясен, чем первый, но остается тот же вопрос: почему у нас должны быть свойства для внутренних/локальных членов? Здесь образец:

//==== header file =====//
@interface MyClass : NSObject

@property (nonatomic, retain) NSString *publicMemberWithProperty;

@end

//==== implementation file =====//
@interface MyClass()

@property (nonatomic, retain) NSString *propertyForPrivateMember;

@end

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

4b9b3361

Ответ 1

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

Синтаксис расширения класса прост:

Внутри .m файла, который имеет класс, создайте безымянную категорию:

.час

@interface OverlayViewController : UIViewController <VSClickWheelViewDelegate>
- (IBAction)moreButtonClicked:(id)sender;
- (IBAction)cancelButtonClicked:(id)sender;
@end

.m

#import "OverlayViewController.h"

@interface OverlayViewController ()
@property(nonatomic) NSInteger amount;
@property(retain,nonatomic)NSArray *colors;
@end

@implementation OverlayViewController
@synthesize amount = amount_;
@synthesize colors = colors_;

//…

@end

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

Обратите внимание, что этот код использует синтезированные ивары. Нет необходимости в объявлении ivar в заголовке.

Есть хорошая статья об этом подходе.

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


Поскольку LLVM 3 также возможно, объявить ivars в расширениях класса

@interface OverlayViewController (){
    NSInteger amount;
    NSArray *colors;
}
@end

или даже в блоке реализации

@implementation OverlayViewController{
    NSInteger amount;
    NSArray *colors;
}
//…
@end

см. "WWDC2011: Сессия 322 - Достижения Objective-C в глубине" (~ 03: 00)

Ответ 2

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

Время выполнения может (но не делает) сделать это различие с ivars и методами. Поддержка первого класса была бы лучшей, ИМО. До тех пор у нас есть некоторые абстракции:

Вариант A

Плохо - все видно. Я не согласен с тем, что это хороший подход, и это не OOD (IMO). Если все видно, то ваш класс должен либо:

  • поддерживает все случаи, когда клиент может использовать ваш класс (обычно необоснованный или нежелательный)
  • или вы предоставляете им массу правил через документацию (обновления doc, вероятно, останутся незамеченными)
  • или у аксессуаров не должно быть побочных эффектов (а не OOD и часто переводится как "не переопределять аксессоры" )

Вариант B

Имеют ли недостатки опции A, и как вариант A, члены могут быть доступны с помощью ключа.

Вариант C

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

Вариант D

Один из подходов к этому заключается в том, чтобы написать ваш класс как оболочку поверх типа реализации. Для этого вы можете использовать тип ObjC или тип С++. Вы можете одобрить С++, где скорость важна (это упоминалось в OP).

Простым подходом к этому может быть одна из форм:

// inner ObjC type
@class MONObjectImp;

@interface MONObject : NSObject
{
@private
 MONObjectImp * imp;
}
@end


// Inner C++ type - Variant A
class MONObjectImp { ... };

@interface MONObject : NSObject
{
@private
 MONObjectImp imp;
}
@end


// Inner C++ type - Variant B
class MONObjectImp;

@interface MONObject : NSObject
{
@private
 MON::t_auto_pointer<MONObjectImp> imp;
}
@end

(Примечание: поскольку это было изначально написано, появилась возможность объявлять ivars в блоке @implementation. Вы должны объявить свои типы С++ там, где нет необходимости поддерживать старые инструментальные цепочки или "хрупкие" 32- бит OS X ABI).

С++ Вариант A не является "безопасным", как другие, поскольку для него требуется объявление класса, видимое клиенту. В других случаях вы можете объявить и определить класс Imp в файле реализации, скрывая его от клиентов.

Затем вы можете открыть интерфейс, который вы выберете. Конечно, клиенты могут получить доступ к вашим членам, если они действительно хотят через среду выполнения. Для них было бы проще сделать безопасную работу с типом ObjC Imp - время выполнения objc не поддерживает семантику С++ для членов, поэтому клиенты будут запрашивать UB (IOW все это POD для среды выполнения).

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

Тип С++ практически не будет стоить ничего, кроме выделения (вариант B).

Вариант E

Другие подходы часто отделяют ivars от интерфейсов. Хотя это хорошо, это также очень необычно для типов ObjC. Типы/проекты ObjC часто поддерживают тесные отношения с их иварами и аксессуарами, поэтому вы столкнетесь с сопротивлением некоторых других разработчиков.

Ответ 3

Аналогично С++ Objective C предоставляет общедоступные, частные и защищенные области. Он также предоставляет область пакета, которая похожа на область пакета, определенную на Java. Публичные переменные классов могут быть ссылками в любом месте программы. Частные переменные могут ссылаться только на сообщения класса, объявляющего его. Он может использоваться в сообщениях, которые принадлежат к любому экземпляру того же класса. Объем пакета аналогичен области видимости в пределах одного и того же изображения, то есть исполняемого файла или библиотеки. Согласно документации Apple, на 64-битных архитектурах переменные области пакета, определенные в другом изображении, должны рассматриваться как частные. Область переменной определяется переменными @public, @private, @protected, @package. Эти модификаторы могут использоваться как способом, аналогичным С++ или Java. Все переменные, перечисленные в объявлении области, относятся к одной и той же области. Кроме того, переменные могут быть указаны в той же строке, где объявлена ​​область действия.

    @interface VariableScope : NSObject {
        @public
        int iVar0;
        @protected
        int iVar1;
        @private
        int iVar2;
        @package
        int iVar3;

@public int iVar01, iVar02;
@protected int iVar11, iVar12;
@private int iVar21, iVar22;
@package int iVar31, iVar32;
}
  @end

Для получения дополнительной информации используйте приведенную ниже ссылку

http://cocoacast.com/?q=node/100