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

IOS: подкласс UIView init или initWithFrame:?

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

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

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

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

4b9b3361

Ответ 1

Назначенный инициализатор - это тот, который должны вызвать все остальные инициализаторы. 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: в реализации.

Ответ 2

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

Ответ 3

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