简体   繁体   中英

Inheriting properties, setter not synthetized when readwrite in inherited property from readonly

I discovered a strange behaviour when working with a property, that was inherited as readonly and than redeclared in the inherited class as readwrite

In Ah

@interface A : NSObject

@property (nonatomic, strong, readonly) NSObject * someProperty;

@end

In Bh

@interface B : A

// no matter if here
// @property (nonatomic, strong, readwrite) NSObject * someProperty;

- (void)foo;

@end

In Bm

@interface B()

// no matter if here
@property (nonatomic, strong, readwrite) NSObject * someProperty;

@end

@implementation B

- (void)foo {

    NSLog(@"%@", self.someProperty);

    // crash here with unrecognized selector setSomeProperty:
    self.someProperty = [NSObject new];
}

@end

calling

self.someProperty = [NSObject new];

causes the code to crash on unrecognized selector "setSomeProperty:"

investigation showed, that it looks like the setter did not get synthetized, even when declared as readwrite

Why is this happening? The compiler didnt indicate any warning for this to happen, nor i found anywhere this behaviour documented

Add a @synthesize directive to the Bm file and the crash will go away:

@synthesize someProperty = _someProperty;

The problem is that since in the parent class you declared the property as readonly there is no setter synthesized for it. And the subclasses inherit this behavior. Even if you redeclare the property to be readwrite in the subclass. The @synthesize command will instruct the compiler to generate the accessor methods for class B again.

Hope this helps!

在此输入图像描述

I cannot give you an official reference, but this is what I experienced: For a property inherited from a superclass , the compiler does not generate any accessor methods.

In your case, the property is declared as readonly in class A, so that the compiler creates only a getter method. The re-declaration in class B does not create any additional accessor methods. The reason might be that class B does not know "how" the property is realised in class A (it need not be an instance variable).

So the property declaration in the subclass is only a "promise" to the compiler that getter and setter functions will be available at runtime (similar to a @dynamic declaration). If there is no setter then you will get a runtime exception.

So a use case of re-declaring the property in the subclass would be if the superclass declares the property as read-only in the public interface, but as read-write in the ( private ) class extension:

// A.h
@interface A : NSObject
@property (nonatomic, strong, readonly) NSObject * someProperty;
@end

// A.m
@interface A()
@property (nonatomic, strong, readwrite) NSObject * someProperty;
@end

@implementation A
@end

In this case, both setter and getter are created in the class A, and class B can re-declare the property as read-write in its implementation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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