解决方法
如果没有访问类的主要实现块,或者至少包含它的编译单元,则无法更改此属性的功能,因为您无法访问该单元外的ivar.即使你要在一个类别中为类添加一个setter,你也不可能完全影响类的存储,而不是完全在类之外.
但是,您可以使用KVC. setValue:forKey:如果可以找到一个,它将绕过setter并直接进入ivar.您可以使用它来设置您喜欢的任何值,即使是已经声明为readonly的属性,前提是您知道其名称的后备存储.
它是这样的:
- //Passaquisset.h
- #import <Foundation/Foundation.h>
- @interface Passaquisset : NSObject
- @property (copy,readonly,nonatomic) NSString * vanadium;
- @end
- //Passaquisset.m
- #import "Passaquisset.h"
- @implementation Passaquisset
- @synthesize vanadium;
- - (id) init {
- self = [super init];
- if( !self ) return nil;
- vanadium = @"Number 23";
- return self;
- }
- @end
- //Elsewhere...
- #import <Foundation/Foundation.h>
- #import "Passaquisset.h"
- int main(int argc,const char * argv[])
- {
- @autoreleasepool {
- Passaquisset * pq = [Passaquisset new];
- NSLog(@"%@",[pq vanadium]);
- [pq setValue:@"Number 24" forKey:@"vanadium"];
- NSLog(@"%@",[pq vanadium]);
- }
- return 0;
- }
就像我说的那样,这会失败 – 实际上会引发一个异常 – 如果既没有一个setter也没有一个同名的ivar(或者附加一个下划线_vanadium(KVC非常聪明),比如该属性的值是完全计算的:
- //Passaquisset.m
- #import "Passaquisset.h"
- @implementation Passaquisset
- /** KVC will fail with this version! **/
- - (NSString *)vanadium
- {
- return @"Number 23";
- }
- @end
为了完整起见,我要提一下,如果该属性由一个完全不同名称的ivar支持(例如@synthesize vanadium = erythronium;),您需要知道ivar的名称才能使用KVC.