@@ -145,7 +145,7 @@ static inline void setIdProperty(ParseModelBase *self, NSString* property, id va
145
145
146
146
#pragma mark - PROPERTY INTROSPECTION:
147
147
148
- + (NSSet *) propertyNames {
148
+ + (NSSet *) propertyNames {
149
149
static NSMutableDictionary * classToNames;
150
150
if (!classToNames)
151
151
classToNames = [[NSMutableDictionary alloc ] init ];
@@ -203,27 +203,37 @@ static BOOL getPropertyInfo(Class cls,
203
203
BOOL setter,
204
204
Class *declaredInClass,
205
205
const char * *propertyType) {
206
- // Find the property declaration:
207
206
const char *name = [propertyName UTF8String ];
208
207
objc_property_t property = class_getProperty (cls, name);
209
208
210
209
if (!property) {
211
- if (![propertyName hasPrefix: @" primitive" ]) { // Ignore "primitiveXXX" KVC accessors
212
- NSLog (@" %@ has no dynamic property named '%@ ' -- failure likely" , cls, propertyName);
210
+
211
+ // If we can't find the property in the class, it may be in a protocol...
212
+ // Though it should be in the class that conforms to the protocol, sometimes
213
+ // it does not appear there. This seems to be strange behavior.
214
+ property = checkForPropertyInProtocols (cls, name, declaredInClass);
215
+
216
+ if (!property) {
217
+ if (![propertyName hasPrefix: @" primitive" ]) { // Ignore "primitiveXXX" KVC accessors
218
+ NSLog (@" %@ has no dynamic property named '%@ ' -- failure likely" , cls, propertyName);
219
+ }
220
+ *propertyType = NULL ;
221
+ return NO ;
213
222
}
214
- *propertyType = NULL ;
215
- return NO ;
216
223
}
217
-
218
- // Find the class that introduced this property, as cls may have just inherited it:
219
- do {
220
- *declaredInClass = cls;
221
- cls = class_getSuperclass (cls);
222
- } while (class_getProperty (cls, name) == property);
223
224
225
+ // Find the class that introduced this property, as cls may have just inherited it:
226
+ if (*declaredInClass == NULL ) {
227
+ do {
228
+ *declaredInClass = cls;
229
+ cls = class_getSuperclass (cls);
230
+ } while (class_getProperty (cls, name) == property);
231
+ }
232
+
224
233
// Get the property's type:
225
234
BOOL isSettable;
226
235
*propertyType = getPropertyType (property, &isSettable);
236
+
227
237
if (setter && !isSettable) {
228
238
// Asked for a setter, but property is readonly:
229
239
*propertyType = NULL ;
@@ -232,6 +242,50 @@ static BOOL getPropertyInfo(Class cls,
232
242
return YES ;
233
243
}
234
244
245
+ static objc_property_t checkForPropertyInProtocols (Class aClass,
246
+ const char *propertyName,
247
+ Class *declaredInClass)
248
+ {
249
+ // For speed, check the immediate class first...
250
+ uint protocolCount = 0 ;
251
+ __unsafe_unretained Protocol **protocolArray = class_copyProtocolList (aClass, &protocolCount);
252
+ for (uint i = 0 ; i < protocolCount; i++) {
253
+
254
+ uint protocolPropertyCount = 0 ;
255
+ objc_property_t *properties = protocol_copyPropertyList (protocolArray[i], &protocolPropertyCount);
256
+ for (uint j = 0 ; j < protocolPropertyCount; j++) {
257
+
258
+ // If we found the property...
259
+ if (strcmp (propertyName, property_getName (properties[j])) == 0 ) {
260
+ *declaredInClass = aClass;
261
+ return properties[j];
262
+ }
263
+ }
264
+ }
265
+
266
+ // Check super classes...
267
+ Class superClass = aClass;
268
+ while ((superClass = class_getSuperclass (superClass))) {
269
+ protocolCount = 0 ;
270
+ __unsafe_unretained Protocol **protocolArray = class_copyProtocolList (superClass, &protocolCount);
271
+ for (uint i = 0 ; i < protocolCount; i++) {
272
+
273
+ uint protocolPropertyCount = 0 ;
274
+ objc_property_t *properties = protocol_copyPropertyList (protocolArray[i], &protocolPropertyCount);
275
+ for (uint j = 0 ; j < protocolPropertyCount; j++) {
276
+
277
+ // If we found the property...
278
+ if (strcmp (propertyName, property_getName (properties[j])) == 0 ) {
279
+ *declaredInClass = superClass;
280
+ return properties[j];
281
+ }
282
+ }
283
+ }
284
+ }
285
+
286
+ return NULL ;
287
+ }
288
+
235
289
static Class classFromType (const char * propertyType) {
236
290
size_t len = strlen (propertyType);
237
291
if (propertyType[0 ] != _C_ID || propertyType[1 ] != ' "' || propertyType[len-1 ] != ' "' )
@@ -241,7 +295,7 @@ static Class classFromType(const char* propertyType) {
241
295
return objc_getClass (className);
242
296
}
243
297
244
- + (Class ) classOfProperty : (NSString *)propertyName {
298
+ + (Class )classOfProperty : (NSString *)propertyName {
245
299
Class declaredInClass;
246
300
const char * propertyType;
247
301
if (!getPropertyInfo (self, propertyName, NO , &declaredInClass, &propertyType))
0 commit comments