Error while getting properties types of large class in objective-C
In Objective-c, I am trying to get properties of some Objec开发者_如何学Pythont that contains about 14 property using the following code:
-(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 "@";
}
But I got an exception (see below) However, When I try to use the same code to get the properties list of small objects (objects with 3 or 4 properties), the code works without any exceptions and get accurate results.
So, How to handle this error!! Thanks.
*** 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
)
That's not related to the size of the class nor the number of properties.
This is probably because you have a problem in your memory mgmt. When there are not too much properties, the memory used to retrieve the property name and types in the const char*
variables are still there, but when you start having too much properties to loop thru, these memory zones are erased by new values, hence the crash.
This is probably related to the fact that strsep
is not reentrant too, so looping and using it multiple times uses the same internal char buffer each time.
You should make your getPropertyType
method directly return the NSData object instead of the const char*
bytes, and use NSString
's initWithData:encoding:
method to build the string from it (or move this initWithData:encoding:
call to getPropertyType
directly and make this return an NSString
object directly. This way you will avoid managing pointers to memory zones that are to be autoreleased soon.
But your problem is probably that you forgot to check the validity of the attribute
buffer and especially its length before trying to access the bytes in this buffer !
Especially you are using [NSData dataWithBytes:(attribute + 3) length:strlen(attribute) - 4]
without checking that attribute
is at least 4 characters long!
That's why the call to dataWithBytes:length:
(that internally calls initWithBytes:length:copy:freeWhenDone:bytesAreVM:
) crash with a NSInvalidArgumentException
, telling that you pass it an absurd length of 4294967294
(which is -2
if interpreted as signed integer)
精彩评论