Ошибка "свойство имеет предыдущее объявление" в расширении класса: ошибка или функция?

В Objective-C вы можете в целом повторно объявить свойство readonly как readwrite в расширении класса следующим образом:

@interface PubliclyImmutablePrivatelyMutableClass : NSObject

@property (readonly, nonatomic) SomeStateEnum someState;

@end

// In "PubliclyImmutablePrivatelyMutableClass+Private.h"
// or "PubliclyImmutablePrivatelyMutableClass.m"
@interface PubliclyImmutablePrivatelyMutableClass()

@property (readwrite, nonatomic) SomeStateEnum someState;

@end

// In "PubliclyImmutablePrivatelyMutableClass.m"
@implementation PubliclyImmutablePrivatelyMutableClass @end

Однако если я введу свойство в расширение класса как readonly и попытаюсь повторно объявить его как readwrite во втором, Xcode 10 Clang выдаст мне ошибку компилятора:

@interface ClassWithPrivateImmutableInternallyMutableProperty : NSObject

// any public API

@end


// In "ClassWithPrivateImmutableInternallyMutableProperty+Private.h"
@interface ClassWithPrivateImmutableInternallyMutableProperty()

@property (readonly, nonatomic) SomePrivateStateEnum somePrivateState;

@end


// In "ClassWithPrivateImmutableInternallyMutableProperty.m"
@interface ClassWithPrivateImmutableInternallyMutableProperty()

@property (readwrite, nonatomic) SomePrivateStateEnum somePrivateState; // error: property has a previous declaration

@end

@implementation ClassWithPrivateImmutableInternallyMutableProperty
// other API
@end

Теперь мне интересно:

  • Ошибка компилятора - это ошибка / регресс в Clang или преднамеренная функция?
  • Если это ошибка, есть ли другой обходной путь, кроме ручного внедрения установщика?
2
0
1 200
1

Ответы 1

Я считаю, что это правильное поведение компилятора.

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

Обратите внимание, что это отличается от первого примера, в котором свойство сначала объявляется в заголовок, а затем повторно объявляется в одной категории продолжения класса с именем ().

Если я прав, то ответ - пометить расширение класса '+ private' именем типа (Private) вместо ():

@interface ClassWithPrivateImmutableInternallyMutableProperty(Private)

А также, если у вас есть какая-либо реализация для частного расширения:

@implementation ClassWithPrivateImmutableInternallyMutableProperty(Private)

Надеюсь, это поможет!

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

danyowdee 01.11.2018 11:15

Если вы хотите использовать два продолжения класса, вы не можете объявить свойство с одинаковым именем в обоих. Возможно, используйте внутреннее имя в реализации, например _somePrivateState, а затем предоставьте геттер в продолжении + private класса, который предоставляет это поддерживающее свойство - (SomePrivateEnum)somePrivateState.

ncke 01.11.2018 11:45

Другие вопросы по теме