Objective-C子类中的readonly属性

时间:2014-12-20 08:32:44

标签: ios objective-c

我有一个名为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

4 个答案:

答案 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";