@@ -87,8 +87,11 @@ - (void)stopMocking
87
87
88
88
- (void )stopMockingClassMethods
89
89
{
90
- OCMSetAssociatedMockForClass (nil , mockedClass);
91
- object_setClass (mockedClass, originalMetaClass);
90
+ @synchronized (mockedClass)
91
+ {
92
+ OCMSetAssociatedMockForClass (nil , mockedClass);
93
+ object_setClass (mockedClass, originalMetaClass);
94
+ }
92
95
originalMetaClass = nil ;
93
96
/* created meta class will be disposed later because partial mocks create another subclass depending on it */
94
97
}
@@ -119,48 +122,49 @@ - (void)prepareClassForClassMethodMocking
119
122
if (otherMock != nil )
120
123
[otherMock stopMockingClassMethods ];
121
124
122
- OCMSetAssociatedMockForClass (self, mockedClass);
123
125
124
126
/* dynamically create a subclass and use its meta class as the meta class for the mocked class */
125
127
classCreatedForNewMetaClass = OCMCreateSubclass (mockedClass, mockedClass);
126
128
originalMetaClass = object_getClass (mockedClass);
127
129
id newMetaClass = object_getClass (classCreatedForNewMetaClass);
128
-
129
130
/* create a dummy initialize method */
130
131
Method myDummyInitializeMethod = class_getInstanceMethod ([self mockObjectClass ], @selector (initializeForClassObject ));
131
132
const char *initializeTypes = method_getTypeEncoding (myDummyInitializeMethod);
132
133
IMP myDummyInitializeIMP = method_getImplementation (myDummyInitializeMethod);
133
134
class_addMethod (newMetaClass, @selector (initialize ), myDummyInitializeIMP, initializeTypes);
134
-
135
- object_setClass (mockedClass, newMetaClass); // only after dummy initialize is installed (iOS9)
136
-
137
- /* point forwardInvocation: of the object to the implementation in the mock */
138
- Method myForwardMethod = class_getInstanceMethod ([self mockObjectClass ], @selector (forwardInvocationForClassObject: ));
139
- IMP myForwardIMP = method_getImplementation (myForwardMethod);
140
- class_addMethod (newMetaClass, @selector (forwardInvocation: ), myForwardIMP, method_getTypeEncoding (myForwardMethod));
141
-
142
- /* adding forwarder for most class methods (instance methods on meta class) to allow for verify after run */
143
- NSArray *methodBlackList = @[
144
- @" class" , @" forwardingTargetForSelector:" , @" methodSignatureForSelector:" , @" forwardInvocation:" , @" isBlock" ,
145
- @" instanceMethodForwarderForSelector:" , @" instanceMethodSignatureForSelector:" , @" resolveClassMethod:"
146
- ];
147
- void (^setupForwarderFiltered)(Class , SEL ) = ^(Class cls, SEL sel) {
148
- if ((cls == object_getClass ([NSObject class ])) || (cls == [NSObject class ]) || (cls == object_getClass (cls)))
149
- return ;
150
- if (OCMIsApplePrivateMethod (cls, sel))
151
- return ;
152
- if ([methodBlackList containsObject: NSStringFromSelector (sel)])
153
- return ;
154
- @try
155
- {
156
- [self setupForwarderForClassMethodSelector: sel];
157
- }
158
- @catch (NSException *e)
159
- {
160
- // ignore for now
161
- }
162
- };
163
- [NSObject enumerateMethodsInClass: originalMetaClass usingBlock: setupForwarderFiltered];
135
+ @synchronized (mockedClass)
136
+ {
137
+ object_setClass (mockedClass, newMetaClass); // only after dummy initialize is installed (iOS9)
138
+ OCMSetAssociatedMockForClass (self, mockedClass);
139
+
140
+ /* point forwardInvocation: of the object to the implementation in the mock */
141
+ Method myForwardMethod = class_getInstanceMethod ([self mockObjectClass ], @selector (forwardInvocationForClassObject: ));
142
+ IMP myForwardIMP = method_getImplementation (myForwardMethod);
143
+ class_addMethod (newMetaClass, @selector (forwardInvocation: ), myForwardIMP, method_getTypeEncoding (myForwardMethod));
144
+
145
+ /* adding forwarder for most class methods (instance methods on meta class) to allow for verify after run */
146
+ NSArray *methodBlackList = @[
147
+ @" class" , @" forwardingTargetForSelector:" , @" methodSignatureForSelector:" , @" forwardInvocation:" , @" isBlock" ,
148
+ @" instanceMethodForwarderForSelector:" , @" instanceMethodSignatureForSelector:" , @" resolveClassMethod:"
149
+ ];
150
+ void (^setupForwarderFiltered)(Class , SEL ) = ^(Class cls, SEL sel) {
151
+ if ((cls == object_getClass ([NSObject class ])) || (cls == [NSObject class ]) || (cls == object_getClass (cls)))
152
+ return ;
153
+ if (OCMIsApplePrivateMethod (cls, sel))
154
+ return ;
155
+ if ([methodBlackList containsObject: NSStringFromSelector (sel)])
156
+ return ;
157
+ @try
158
+ {
159
+ [self setupForwarderForClassMethodSelector: sel];
160
+ }
161
+ @catch (NSException *e)
162
+ {
163
+ // ignore for now
164
+ }
165
+ };
166
+ [NSObject enumerateMethodsInClass: originalMetaClass usingBlock: setupForwarderFiltered];
167
+ }
164
168
}
165
169
166
170
@@ -184,15 +188,18 @@ - (void)setupForwarderForClassMethodSelector:(SEL)selector
184
188
- (void )forwardInvocationForClassObject : (NSInvocation *)anInvocation
185
189
{
186
190
// in here "self" is a reference to the real class, not the mock
187
- OCClassMockObject *mock = OCMGetAssociatedMockForClass ((Class )self, YES );
188
- if (mock == nil )
189
- {
190
- [NSException raise :NSInternalInconsistencyException format: @" No mock for class %@ " , NSStringFromClass ((Class )self )];
191
- }
192
- if ([mock handleInvocation: anInvocation] == NO )
191
+ @synchronized (self)
193
192
{
194
- [anInvocation setSelector: OCMAliasForOriginalSelector ([anInvocation selector ])];
195
- [anInvocation invoke ];
193
+ OCClassMockObject *mock = OCMGetAssociatedMockForClass ((Class )self, YES );
194
+ if (mock == nil )
195
+ {
196
+ [anInvocation invoke ];
197
+ }
198
+ else if ([mock handleInvocation: anInvocation] == NO )
199
+ {
200
+ [anInvocation setSelector: OCMAliasForOriginalSelector ([anInvocation selector ])];
201
+ [anInvocation invoke ];
202
+ }
196
203
}
197
204
}
198
205
0 commit comments