我有一个名为SuperClass的超类是一个只读属性。看起来像这样:
@property (nonatomic, strong, readonly) NSArray *arrayProperty;
在子类中,我需要一个初始化程序,它将SuperClass的一个实例作为参数:
- (instancetype)initWithSuperClass:(SuperClass *)superClass
我创建了一个GitHub示例项目,显示问题所在:https://github.com/marosoaie/Objc-test-project
我无法在初始化程序中执行_arrayProperty = superClass.arrayProperty
。
我想在SubClass中保持属性只读。
关于如何解决这个问题的任何想法?
我知道我可以在SubClass实现文件中的类扩展中将该属性声明为readwrite,但我希望有比这更好的解决方案。
编辑: SuperClass.h
#import <Foundation/Foundation.h>
@interface SuperClass : NSObject
- (instancetype)initWithDictionary:(NSDictionary *)dictionary;
@property (nonatomic, strong, readonly) NSString *stringProperty;
@property (nonatomic, strong, readonly) NSArray *arrayProperty;
@end
SuperClass.m
#import "SuperClass.h"
@implementation SuperClass
- (instancetype)initWithDictionary:(NSDictionary *)dictionary
{
self = [super init];
if (self) {
_arrayProperty = dictionary[@"array"];
_stringProperty = dictionary[@"string"];
}
return self;
}
@end
SubClass.h:
#import <Foundation/Foundation.h>
#import "SuperClass.h"
@interface SubClass : SuperClass
@property (nonatomic, strong, readonly) NSString *additionalStringProperty;
- (instancetype)initWithSuperClass:(SuperClass *)superClass;
@end
SubClass.m:
#import "SubClass.h"
@implementation SubClass
@synthesize additionalStringProperty = _additionalStringProperty;
- (NSString *)additionalStringProperty
{
if (!_additionalStringProperty) {
NSMutableString *mutableString = [[NSMutableString alloc] init];
for (NSString *string in self.arrayProperty) {
[mutableString appendString:string];
}
_additionalStringProperty = [mutableString copy];
}
return _additionalStringProperty;
}
- (instancetype)initWithSuperClass:(SuperClass *)superClass
{
self = [super init];
if (self) {
// Doesn't work
// _stringProperty = superClass.stringProperty;
// _arrayProperty = superClass.arrayProperty;
}
return self;
}
@end
答案 0 :(得分:3)
您已经公开了一个初始化程序,它写入该只读属性-initWithDictionary:
。在您的SubClass中调用它,而不是[super init]
:
- (instancetype)initWithSuperClass:(SuperClass *)superClass {
NSDictionary *dict = @{
@"array": superClass.arrayProperty,
@"string": superClass.stringProperty,
};
self = [super initWithDictionary:dict];
if (self) {
// Nothing here.
}
return self;
}
为只读属性设置初始化程序是很常见的,尽管使用字典不是一个好的解决方案。通常,我会创建:
- (instancetype)initWithArray:(NSArray *)array string:(NSString *)string;
答案 1 :(得分:1)
首先,您的测试设置中存在一个错误:- (instancetype)initWithDictionary:(NSDictionary *)dictionary
中的密钥为@"array"
,其中数组包含@"arrayProperty"
。
关于你的问题:
//...
@interface SuperClass : NSObject
{
@protected // this is what you want: a protected class property, accessible in subclasses, but no where else
NSString *_stringProperty;
NSArray *_arrayProperty;
}
@property (nonatomic, strong, readonly) NSString *stringProperty;
@property (nonatomic, strong, readonly) NSArray *arrayProperty;
- (instancetype)initWithDictionary:(NSDictionary *)dictionary;
@end
// SubClass.m
//...
@implementation SuperClass
- (instancetype)initWithDictionary:(NSDictionary *)dictionary
{
self = [super init];
if (self) {
_arrayProperty = dictionary[@"arrayProperty"]; // this was @"array", so could not work
_stringProperty = dictionary[@"stringProperty"]; // same here
}
return self;
}
@end
然后它有效。另外,我会写
@interface SubClass ()
@property (nonatomic, strong, readwrite) NSString *additionalStringProperty;
@end
@implementation SubClass
- (instancetype)initWithSuperClass:(SuperClass *)superClass
{
self = [super init];
if (self) {
_stringProperty = superClass.stringProperty;
_arrayProperty = superClass.arrayProperty;
}
return self;
}
因为我比readwrite
魔法更喜欢类扩展中的@synthesize
属性。但这是个人意见。
关于类设计的一个主要问题仍然存在:如果(类似于您的测试设置)超类的字典不包含密钥会发生什么?然后它不会被初始化,这不是一个好主意,因为你期望它们被初始化。因此,如果superclass.stringProperty不是nil,则应该检查子类,并为超类添加标准构造函数,以避免两个字典未初始化。
答案 2 :(得分:0)
在你的SuperClass.m中:
- (instancetype)initWithDictionary:(NSDictionary *)dictionary
{
self = [super init];
if (self) {
// these were always nil, check your dictionary keys
_arrayProperty = dictionary[@"arrayProperty"];
_stringProperty = dictionary[@"stringProperty"];
}
return self;
}
在你的SubClass.m中:
@interface SubClass ()
@property (strong, nonatomic) NSString * additionalStringProperty;
@property (strong, nonatomic) NSString * subClassString;
@property (strong, nonatomic) NSArray * subClassArray;
@end
@implementation SubClass
- (instancetype)initWithSuperClass:(SuperClass *)superClass
{
self = [super init];
if (self) {
_subClassString = superClass.stringProperty;
_subClassArray = superClass.arrayProperty;
}
return self;
}
答案 3 :(得分:0)
我在这里尝试了答案无济于事。最终为我工作的是this answer,它提到你应该直接访问成员变量(在声明它被保护之后),如下所示:
self->_stringProperty = @"some string";