繁体   English   中英

子类中的Objective-C只读属性

[英]Objective-C readonly properties in a subclass

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

超类

#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

子类.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

您已经暴露了一个初始化程序,该初始化程序写入该只读属性-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;

首先,测试设置中存在一个错误@"arrayProperty" - (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;
}

因为相比@synthesize魔术,我更喜欢类扩展中的readwrite属性。 但这是个人观点。

有关类设计的一个主要问题仍然存在:如果(类似于您的测试设置)超类的字典不包含键,将会发生什么? 然后它不会被初始化,这不是一个好主意,因为您希望它们被初始化。 因此,如果superclass.stringProperty不为nil,则应检查子类,并为超类添加标准构造函数,以避免两个字典未初始化。

在您的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;
}

我在这里尝试答案无济于事。 最终对我有用的是这个答案 ,它提到您应该直接访问成员变量(在将其声明为受保护后),如下所示:

self->_stringProperty = @"some string";

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM