iOS: инициализация подкласса UIView или initWithFrame :? - PullRequest
37 голосов
/ 19 августа 2011

Я сделал подкласс UIView с фиксированным кадром. Итак, я могу просто переопределить init вместо initWithFrame:? E.g.:

- (id)init {
    if ((self = [super initWithFrame:[[UIScreen mainScreen] bounds]])) {
        self.backgroundColor = [UIColor clearColor];
    }
    return self;
}

Документация Xcode для -initWithFrame: гласит: «Если вы создаете объект представления программно, этот метод является назначенным инициализатором для класса UIView. Подклассы могут переопределить этот метод для выполнения любой пользовательской инициализации, но должны вызвать super в начале их реализации. "

Что означает «назначенный инициализатор»?

Ответы [ 3 ]

73 голосов
/ 20 августа 2011

Назначенный инициализатор - это тот, который должны вызывать все остальные инициализаторы.UIView и подклассы немного необычны тем, что у них фактически есть два таких инициализатора: -initWithFrame: и -initWithCoder:, в зависимости от того, как создается представление.Вам следует переопределить -initWithFrame:, если вы создаете экземпляр представления в коде, и -initWithCoder:, если вы загружаете его из пера.Или вы можете поместить свой код в третий метод и переопределить оба этих инициализатора так, чтобы они вызывали ваш третий метод.Фактически, это часто рекомендуемая стратегия.

Так, например, вы можете создать подкласс UIView, ClueCharacter, который имеет собственный метод инициализации: -initWithPerson:place:thing:.Затем вы создаете свой вид следующим образом:

Obj-C:

ClueCharacter *mustard = [[ClueCharacter alloc] initWithPerson:@"Col. Mustard"
                                                         place:kInTheStudy
                                                         thing:kTheRope];

Swift:

var mustard = ClueCharacter("Col. Mustard", place: kInTheStudy, thing: kTheRope)

Это хорошо, но для инициализацииUIView часть объекта, ваш метод должен вызвать указанный инициализатор:

Obj-C:

-(id)initWithPerson:(NSString*)name place:(CluePlace)place thing:(ClueWeapon)thing
{
    if ((self = [super initWithFrame:CGRectMake(0, 0, 150, 200)])) {
        // your init stuff here
    }
}

Swift:

func init(name: String, place : CluePlace, thing : ClueWeapon)
{
    if (self = super.init(CGRectMake(0, 0, 150, 200))) {
       // your init stuff here
    }
}

Если вы хотите вызвать инициализатор вашего подкласса -init, это нормально, пока вы вызываете -initWithFrame: в реализации.

23 голосов
/ 13 января 2013

в UIView вызов [super init] в точности равен [super initWithFrame:CGRectZero]

3 голосов
/ 20 августа 2011

В классе Objective-C с несколькими инициализаторами назначенный инициализатор выполняет значимую работу.Итак, часто у вас есть класс с несколькими инициализаторами, скажем:

- (id)initWithRect:(CGRect)someRect;

- (id)initWithRect:(CGRect)someRect setDefaultColour:(BOOL)setDefaultColour;

- (id)initWithRect:(CGRect)someRect setDefaultColour:(BOOL)setDefaultColour
             linkTo:(id)someOtherObject;

В этом случае вы обычно (но не всегда) говорите, что третий был назначенным инициализатором, и выполняете два других какнапример,

- (id)initWithRect:(CGRect)someRect
{
    return [self initWithRect:someRect setDefaultColour:NO];
}

- (id)initWithRect:(CGRect)someRect setDefaultColour:(BOOL)setDefaultColour
{
    return [self initWithRect:someRect setDefaultColour:setDefaultColour
                   linkTo:nil];
}

Если у класса есть только один инициализатор, то это назначенный инициализатор.

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

...