簡體   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