Skip to content

Commit 56dd765

Browse files
committed
Added support for properties declared in super class protocols. Sometimes the obj-c runtime doesn't see these even if they are declared "dynamic" in the immediate class.
1 parent c32705e commit 56dd765

File tree

1 file changed

+67
-13
lines changed

1 file changed

+67
-13
lines changed

ParseModel/ParseModelBase.m

+67-13
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ static inline void setIdProperty(ParseModelBase *self, NSString* property, id va
145145

146146
#pragma mark - PROPERTY INTROSPECTION:
147147

148-
+ (NSSet*) propertyNames {
148+
+ (NSSet *) propertyNames {
149149
static NSMutableDictionary* classToNames;
150150
if (!classToNames)
151151
classToNames = [[NSMutableDictionary alloc] init];
@@ -203,27 +203,37 @@ static BOOL getPropertyInfo(Class cls,
203203
BOOL setter,
204204
Class *declaredInClass,
205205
const char* *propertyType) {
206-
// Find the property declaration:
207206
const char *name = [propertyName UTF8String];
208207
objc_property_t property = class_getProperty(cls, name);
209208

210209
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;
213222
}
214-
*propertyType = NULL;
215-
return NO;
216223
}
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);
223224

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+
224233
// Get the property's type:
225234
BOOL isSettable;
226235
*propertyType = getPropertyType(property, &isSettable);
236+
227237
if (setter && !isSettable) {
228238
// Asked for a setter, but property is readonly:
229239
*propertyType = NULL;
@@ -232,6 +242,50 @@ static BOOL getPropertyInfo(Class cls,
232242
return YES;
233243
}
234244

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+
235289
static Class classFromType(const char* propertyType) {
236290
size_t len = strlen(propertyType);
237291
if (propertyType[0] != _C_ID || propertyType[1] != '"' || propertyType[len-1] != '"')
@@ -241,7 +295,7 @@ static Class classFromType(const char* propertyType) {
241295
return objc_getClass(className);
242296
}
243297

244-
+ (Class) classOfProperty: (NSString*)propertyName {
298+
+ (Class)classOfProperty:(NSString *)propertyName {
245299
Class declaredInClass;
246300
const char* propertyType;
247301
if (!getPropertyInfo(self, propertyName, NO, &declaredInClass, &propertyType))

0 commit comments

Comments
 (0)