aboutsummaryrefslogtreecommitdiffhomepage
path: root/objectivec/GPBRootObject.m
diff options
context:
space:
mode:
Diffstat (limited to 'objectivec/GPBRootObject.m')
-rw-r--r--objectivec/GPBRootObject.m21
1 files changed, 14 insertions, 7 deletions
diff --git a/objectivec/GPBRootObject.m b/objectivec/GPBRootObject.m
index 4570716f..585d205a 100644
--- a/objectivec/GPBRootObject.m
+++ b/objectivec/GPBRootObject.m
@@ -184,11 +184,10 @@ static id ExtensionForName(id self, SEL _cmd) {
dispatch_semaphore_wait(gExtensionSingletonDictionarySemaphore,
DISPATCH_TIME_FOREVER);
id extension = (id)CFDictionaryGetValue(gExtensionSingletonDictionary, key);
- if (extension) {
- // The method is getting wired in to the class, so no need to keep it in
- // the dictionary.
- CFDictionaryRemoveValue(gExtensionSingletonDictionary, key);
- }
+ // We can't remove the key from the dictionary here (as an optimization),
+ // two threads could have gone into +resolveClassMethod: for the same method,
+ // and ended up here; there's no way to ensure both return YES without letting
+ // both try to wire in the method.
dispatch_semaphore_signal(gExtensionSingletonDictionarySemaphore);
return extension;
}
@@ -212,9 +211,17 @@ BOOL GPBResolveExtensionClassMethod(Class self, SEL sel) {
#pragma unused(obj)
return extension;
});
- if (class_addMethod(metaClass, sel, imp, encoding)) {
- return YES;
+ BOOL methodAdded = class_addMethod(metaClass, sel, imp, encoding);
+ // class_addMethod() is documented as also failing if the method was already
+ // added; so we check if the method is already there and return success so
+ // the method dispatch will still happen. Why would it already be added?
+ // Two threads could cause the same method to be bound at the same time,
+ // but only one will actually bind it; the other still needs to return true
+ // so things will dispatch.
+ if (!methodAdded) {
+ methodAdded = GPBClassHasSel(metaClass, sel);
}
+ return methodAdded;
}
return NO;
}