[英]Dynamically setting unknown readonly property at runtime in Objective-C
我正在構建一個類,該類在運行時從plist動態設置子類的屬性,其工作方式如下:
您可以在子類中聲明屬性以匹配鍵的名稱:
#import "PlistModel.h"
@interface CustomModel : PlistModel
@property (strong, nonatomic) NSString * StringPropertyKey;
@property (strong, nonatomic) NSDate * DatePropertyKey;
@property (strong, nonatomic) NSArray * ArrayPropertyKey;
@property (strong, nonatomic) NSDictionary * DictionaryPropertyKey;
@property int IntPropertyKey;
@property BOOL BoolPropertyKey;
@property float FloatPropertyKey;
@end
而已! 這些值將在運行時自動填充,而無需任何其他代碼:
[CustomModel plistNamed:@"CustomModel" inBackgroundWithBlock:^(PlistModel *plistModel) {
CustomModel * customModel = (CustomModel *)plistModel;
NSLog(@"StringProperty: %@", customModel.StringPropertyKey);
NSLog(@"DateProperty: %@", customModel.DatePropertyKey);
NSLog(@"ArrayProperty: %@", customModel.ArrayPropertyKey);
NSLog(@"DictionaryProperty: %@", customModel.DictionaryPropertyKey);
NSLog(@"IntProperty: %i", customModel.IntPropertyKey);
NSLog(@"BoolProperty: %@", customModel.BoolPropertyKey ? @"YES" : @"NO");
NSLog(@"FloatProperty: %f", customModel.FloatPropertyKey);
}];
我在運行時設置屬性,方法是生成選擇器,並使用要設置的值調用它,如下所示:
SEL propertySetterSelector = NSSelectorFromString(@"set<#PropertyName#>:");
void (*func)(id, SEL, id) = (void *)imp;
func(self, propertySetterSelector, objectToSet);
但是,如果由於某種原因屬性是readonly
則選擇器將不存在,因此我正在尋找替代方法。 我在這里找到了一種識別屬性為只讀的方法:
- (NSMutableArray *) getPropertyNames {
// Prepare Package
NSMutableArray * propertyNames = [NSMutableArray array];
// Fetch Properties
unsigned count;
objc_property_t *properties = class_copyPropertyList([self class], &count);
// Parse Out Properties
for (int i = 0; i < count; i++) {
objc_property_t property = properties[i];
const char * name = property_getName(property);
// NSLog(@"Name: %s", name);
const char * attributes = property_getAttributes(property);
NSLog(@"Attributes: %s", attributes);
NSString * attributeString = [NSString stringWithUTF8String:attributes];
NSArray * attributesArray = [attributeString componentsSeparatedByString:@","];
if ([attributesArray containsObject:@"R"]) {
// is ReadOnly
NSLog(@"%s is read only", name);
// -- CAN I SET THE PROPERTY HERE? -- //
// property = @"Set"; ?
}
// Add to our array
[propertyNames addObject:[NSString stringWithUTF8String:name]];
}
// Free our properties
free(properties);
// Send it off
return propertyNames;
}
也許如果有一種方法可以直接設置objc_property_t
ref。
通過評論,我意識到有些困惑。 我認為我的問題的核心是,除了像我正在做的那樣調用選擇器之外,是否有可能在運行時設置未知屬性。
完整項目: 在這里!
提示此問題的CodeReview Post: 在這里!
我有一個只讀屬性:
@property (readonly) NSString * readOnlyProperty;
我在課堂上聲明:
+ (BOOL) accessInstanceVariablesDirectly {
return YES;
}
我稱之為:
[self setValue:@"HI" forKey:[NSString stringWithUTF8String:name]];
// -- OR -- //
[self setValue:@"HI" forKey:[NSString stringWithFormat:@"_%@",[NSString stringWithUTF8String:name]]];
無論哪種方式,值仍然為null。
如果目標類已將類方法accessInstanceVariablesDirectly
定義為返回YES
,並且該屬性將其值存儲在常規命名的實例變量中, 則可以嘗試將setValue:forKey:
用於readonly
屬性。 請參閱《 鍵值編碼編程指南 》中的“ setValue:forKey:的默認搜索模式” 。 如有必要,KVC會將原始值拆箱。
除非通過調用屬性的setter,否則無法設置屬性 ,因為將屬性定義為getter和(可選)setter。 您可以使用鍵-值編碼(KVC)的setValue:forKey:
方法,這比自己構造設置器名稱更簡單,更可靠,但是在隱藏之下仍然調用該屬性的設置器。
可以使用Objective-C運行時設置實例變量 。 查看class_getInstanceVariable
, object_setInstanceVariable
和object_setIvar
方法 。
您可以猜測屬性的值存儲在實例變量中,該實例變量的名稱是使用_
前綴命名的屬性。 但是,這只是一個約定。 編譯器將約定用於自動綜合屬性,但編譯器不強制執行約定。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.