@@ -134,6 +134,17 @@ - (void)addStub:(OCMInvocationStub *)aStub
134134 }
135135}
136136
137+ - (OCMInvocationStub *)stubForInvocation : (NSInvocation *)anInvocation
138+ {
139+ @synchronized (stubs)
140+ {
141+ for (OCMInvocationStub *stub in stubs)
142+ if ([stub matchesInvocation: anInvocation])
143+ return stub;
144+ return nil ;
145+ }
146+ }
147+
137148- (void )addExpectation : (OCMInvocationExpectation *)anExpectation
138149{
139150 @synchronized (expectations)
@@ -150,6 +161,21 @@ - (void)assertInvocationsArrayIsPresent
150161 }
151162}
152163
164+ - (void )addInvocation : (NSInvocation *)anInvocation
165+ {
166+ @synchronized (invocations)
167+ {
168+ // We can't do a normal retain arguments on anInvocation because its target/arguments/return
169+ // value could be self. That would produce a retain cycle self->invocations->anInvocation->self.
170+ // However we need to retain everything on anInvocation that isn't self because we expect them to
171+ // stick around after this method returns. Use our special method to retain just what's needed.
172+ // This still doesn't completely prevent retain cycles since any of the arguments could have a
173+ // strong reference to self. Those will have to be broken with manual calls to -stopMocking.
174+ [anInvocation retainObjectArgumentsExcludingObject: self ];
175+ [invocations addObject: anInvocation];
176+ }
177+ }
178+
153179
154180#pragma mark Public API
155181
@@ -374,37 +400,15 @@ - (void)forwardInvocation:(NSInvocation *)anInvocation
374400- (BOOL )handleInvocation : (NSInvocation *)anInvocation
375401{
376402 [self assertInvocationsArrayIsPresent ];
377- @synchronized (invocations)
378- {
379- // We can't do a normal retain arguments on anInvocation because its target/arguments/return
380- // value could be self. That would produce a retain cycle self->invocations->anInvocation->self.
381- // However we need to retain everything on anInvocation that isn't self because we expect them to
382- // stick around after this method returns. Use our special method to retain just what's needed.
383- // This still doesn't completely prevent retain cycles since any of the arguments could have a
384- // strong reference to self. Those will have to be broken with manual calls to -stopMocking.
385- [anInvocation retainObjectArgumentsExcludingObject: self ];
386- [invocations addObject: anInvocation];
387- }
403+ [self addInvocation: anInvocation];
388404
389- OCMInvocationStub *stub = nil ;
390- @synchronized (stubs)
391- {
392- for (stub in stubs)
393- {
394- // If the stub forwards its invocation to the real object, then we don't want to do
395- // handleInvocation: yet, since forwarding the invocation to the real object could call a
396- // method that is expected to happen after this one, which is bad if expectationOrderMatters
397- // is YES
398- if ([stub matchesInvocation: anInvocation])
399- break ;
400- }
401- // Retain the stub in case it ends up being removed from stubs and expectations, since we still
402- // have to call handleInvocation on the stub at the end
403- [stub retain ];
404- }
405+ OCMInvocationStub *stub = [self stubForInvocation: anInvocation];
405406 if (stub == nil )
406407 return NO ;
407408
409+ // Retain the stub in case it ends up being removed because we still need it at the end for handleInvocation:
410+ [stub retain ];
411+
408412 BOOL removeStub = NO ;
409413 @synchronized (expectations)
410414 {
@@ -418,8 +422,7 @@ - (BOOL)handleInvocation:(NSInvocation *)anInvocation
418422 }
419423
420424 // We can't check isSatisfied yet, since the stub won't be satisfied until we call
421- // handleInvocation:, and we don't want to call handleInvocation: yes for the reason in the
422- // comment above, since we'll still have the current expectation in the expectations array, which
425+ // handleInvocation: since we'll still have the current expectation in the expectations array, which
423426 // will cause an exception if expectationOrderMatters is YES and we're not ready for any future
424427 // expected methods to be called yet
425428 if (![(OCMInvocationExpectation *)stub isMatchAndReject ])
@@ -437,9 +440,12 @@ - (BOOL)handleInvocation:(NSInvocation *)anInvocation
437440 }
438441 }
439442
440- @try {
443+ @try
444+ {
441445 [stub handleInvocation: anInvocation];
442- } @finally {
446+ }
447+ @finally
448+ {
443449 [stub release ];
444450 }
445451
0 commit comments