在Objective-c中,我试图使用以下代码获取包含大约14个属性的某些Object的属性:
-(NSDictionary*) getPropertiesOfClass:(Class) clazz
{
NSMutableDictionary* dict = [NSMutableDictionary dictionary];
unsigned int outCount, i;
objc_property_t *properties = class_copyPropertyList(clazz, &outCount);
for(i = 0; i < outCount; i++)
{
objc_property_t _property = properties[i];
const char *propName = property_getName(_property);
if(propName)
{
const char *propType = getPropertyType(_property);
NSString *propertyName = [NSString stringWithCString:propName encoding:NSUTF8StringEncoding];
NSString *propertyType = [NSString stringWithCString:propType encoding:NSUTF8StringEncoding];
[dict setValue:propertyType forKey:propertyName];
}
}
free(properties);
return dict;
}
static const char *getPropertyType(objc_property_t property)
{
const char *attributes = property_getAttributes(property);
char buffer[1 + strlen(attributes)];
strcpy(buffer, attributes);
char *state = buffer, *attribute;
while ((attribute = strsep(&state, ",")) != NULL)
{
if (attribute[0] == 'T')
{
return (const char *)[[NSData dataWithBytes:(attribute + 3) length:strlen(attribute) - 4] bytes];
}
}
return "@";
}
但是我得到了一个例外(见下文)但是,当我尝试使用相同的代码来获取小对象(具有3或4个属性的对象)的属性列表时,代码无任何例外地工作并获得准确的结果。
那么,如何处理这个错误!! 感谢。
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSConcreteData initWithBytes:length:copy:freeWhenDone:bytesAreVM:]: absurd length: 4294967294, maximum size: 2147483648 bytes'
*** Call stack at first throw:
(
0 CoreFoundation 0x0101e5a9 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x01172313 objc_exception_throw + 44
2 CoreFoundation 0x00fd6ef8 +[NSException raise:format:arguments:] + 136
3 CoreFoundation 0x00fd6e6a +[NSException raise:format:] + 58
4 Foundation 0x00800b6b -[NSConcreteData initWithBytes:length:copy:freeWhenDone:bytesAreVM:] + 135
5 Foundation 0x00811801 -[NSData(NSData) initWithBytes:length:] + 72
6 solit 0x00033449 -[ObjectMapper(private) getPropertiesOfClass:] + 489
7 solit 0x00031fa5 -[ObjectMapper objectFromDictionary:object:] + 197
8 solit 0x000327b3 -[ObjectMapper objectFromDictionary:object:] + 2259
9 solit 0x00033913 -[NSDictionary(ObjectMapper) toObject:withTypes:] + 243
10 solit 0x00031474 -[JsonWSCaller call:types:error:] + 196
11 solit 0x0003f4c2 +[SummaryWSCaller getFastData:] + 354
12 solit 0x00006fd9 -[PartSearchResultView tableView:didSelectRowAtIndexPath:] + 233
13 UIKit 0x00110b68 -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 1140
14 UIKit 0x00106b05 -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 219
15 Foundation 0x0082079e __NSFireDelayedPerform + 441
16 CoreFoundation 0x00fff8c3 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 19
17 CoreFoundation 0x01000e74 __CFRunLoopDoTimer + 1220
18 CoreFoundation 0x00f5d2c9 __CFRunLoopRun + 1817
19 CoreFoundation 0x00f5c840 CFRunLoopRunSpecific + 208
20 CoreFoundation 0x00f5c761 CFRunLoopRunInMode + 97
21 GraphicsServices 0x012561c4 GSEventRunModal + 217
22 GraphicsServices 0x01256289 GSEventRun + 115
23 UIKit 0x000a7c93 UIApplicationMain + 1160
24 solit 0x00002289 main + 121
25 solit 0x00002205 start + 53
)
答案 0 :(得分:4)
这与班级的规模和财产的数量无关。
这可能是因为你的记忆力有问题。当没有太多属性时,用于检索const char*
变量中的属性名称和类型的内存仍然存在,但是当您开始有太多属性要循环时,这些内存区域将被新值擦除因此崩溃。
这可能与strsep
不可重入的事实有关,因此多次循环和使用它会每次使用相同的内部字符缓冲区。
您应该使getPropertyType
方法直接返回NSData对象而不是const char*
字节,并使用NSString
的{{1}}方法从中构建字符串(或者将此initWithData:encoding:
调用直接移至initWithData:encoding:
,并使其直接返回getPropertyType
对象。这样您就可以避免管理指向即将自动释放的内存区域的指针。
但是你的问题可能是在尝试访问此缓冲区中的字节之前忘记检查NSString
缓冲区的有效性,尤其是其长度!
特别是您使用的是attribute
而未检查[NSData dataWithBytes:(attribute + 3) length:strlen(attribute) - 4]
是否至少有4个字符!
这就是为什么对attribute
(内部调用dataWithBytes:length:
)的调用因initWithBytes:length:copy:freeWhenDone:bytesAreVM:
而崩溃,告诉您将其传递给NSInvalidArgumentException
的荒谬长度({ {1}}如果解释为有符号整数)