Skip to content

Commit 117fe12

Browse files
committed
Add support for unretained and unsafeunretained arguments for stubs.
Allows marking an argument in a stub as being either 'unsafe' or 'unsafeunretained'. An unsafe object argument is retained by the stub, but not by invocations on the mock. An unsafe unretained object argument is not retained by the stub or by invocations on the mock. This allows for mocking of methods that do not retain their arguments. This should simplify testing of methods that are called in dealloc, and give people a way out of other retain-loop problems.
1 parent 10a7545 commit 117fe12

13 files changed

+312
-16
lines changed

Source/OCMock.xcodeproj/project.pbxproj

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,16 @@
279279
817EB15C1BD765130047E85A /* OCMBlockArgCaller.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA2891034E7B73AA3511D17 /* OCMBlockArgCaller.h */; };
280280
817EB15D1BD765130047E85A /* OCMArgAction.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FA2833B48908EAD36444671 /* OCMArgAction.h */; };
281281
817EB1661BD7674D0047E85A /* OCMFunctionsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 03F370CA1BAA1DE800CAD3E8 /* OCMFunctionsPrivate.h */; };
282+
8BF740142476E4B400B9A52C /* OCMUnretainedArgument.h in Headers */ = {isa = PBXBuildFile; fileRef = 8BF740122476E4B300B9A52C /* OCMUnretainedArgument.h */; };
283+
8BF740152476E4B400B9A52C /* OCMUnretainedArgument.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BF740132476E4B400B9A52C /* OCMUnretainedArgument.m */; };
284+
8BF740162476E59A00B9A52C /* OCMUnretainedArgument.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BF740132476E4B400B9A52C /* OCMUnretainedArgument.m */; };
285+
8BF740172476E59A00B9A52C /* OCMUnretainedArgument.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BF740132476E4B400B9A52C /* OCMUnretainedArgument.m */; };
286+
8BF740182476E59B00B9A52C /* OCMUnretainedArgument.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BF740132476E4B400B9A52C /* OCMUnretainedArgument.m */; };
287+
8BF740192476E59C00B9A52C /* OCMUnretainedArgument.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BF740132476E4B400B9A52C /* OCMUnretainedArgument.m */; };
288+
8BF7401A24771FD600B9A52C /* OCMUnretainedArgument.h in Headers */ = {isa = PBXBuildFile; fileRef = 8BF740122476E4B300B9A52C /* OCMUnretainedArgument.h */; };
289+
8BF7401B24771FD700B9A52C /* OCMUnretainedArgument.h in Headers */ = {isa = PBXBuildFile; fileRef = 8BF740122476E4B300B9A52C /* OCMUnretainedArgument.h */; };
290+
8BF7401C24771FD700B9A52C /* OCMUnretainedArgument.h in Headers */ = {isa = PBXBuildFile; fileRef = 8BF740122476E4B300B9A52C /* OCMUnretainedArgument.h */; };
291+
8BF7401D24771FD800B9A52C /* OCMUnretainedArgument.h in Headers */ = {isa = PBXBuildFile; fileRef = 8BF740122476E4B300B9A52C /* OCMUnretainedArgument.h */; };
282292
8DE97C5522B43EE60098C63F /* OCMockObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 03B3159E146333BF0052CD09 /* OCMockObject.m */; };
283293
8DE97C5622B43EE60098C63F /* OCClassMockObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 03B3158C146333BF0052CD09 /* OCClassMockObject.m */; };
284294
8DE97C5722B43EE60098C63F /* OCPartialMockObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 03B315AA146333BF0052CD09 /* OCPartialMockObject.m */; };
@@ -569,6 +579,8 @@
569579
3CFBDD751BB3DB200050D9C5 /* TestClassWithCustomReferenceCounting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestClassWithCustomReferenceCounting.h; sourceTree = "<group>"; };
570580
3CFBDD761BB3DB200050D9C5 /* TestClassWithCustomReferenceCounting.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestClassWithCustomReferenceCounting.m; sourceTree = "<group>"; };
571581
817EB1621BD765130047E85A /* OCMock.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OCMock.framework; sourceTree = BUILT_PRODUCTS_DIR; };
582+
8BF740122476E4B300B9A52C /* OCMUnretainedArgument.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OCMUnretainedArgument.h; sourceTree = "<group>"; };
583+
8BF740132476E4B400B9A52C /* OCMUnretainedArgument.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OCMUnretainedArgument.m; sourceTree = "<group>"; };
572584
8DE97CA022B43EE60098C63F /* OCMock.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OCMock.framework; sourceTree = BUILT_PRODUCTS_DIR; };
573585
A02926811CA0725A00594AAF /* TestObjects.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = TestObjects.xcdatamodel; sourceTree = "<group>"; };
574586
D31108AD1828DB8700737925 /* OCMockLibTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OCMockLibTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -867,6 +879,8 @@
867879
03B315A2146333BF0052CD09 /* OCMPassByRefSetter.m */,
868880
2FA2891034E7B73AA3511D17 /* OCMBlockArgCaller.h */,
869881
2FA283D58AA7569D8A5B0C57 /* OCMBlockArgCaller.m */,
882+
8BF740122476E4B300B9A52C /* OCMUnretainedArgument.h */,
883+
8BF740132476E4B400B9A52C /* OCMUnretainedArgument.m */,
870884
);
871885
name = "Argument Constraints and Actions";
872886
sourceTree = "<group>";
@@ -957,6 +971,7 @@
957971
03B315F5146333C00052CD09 /* OCMPassByRefSetter.h in Headers */,
958972
03B315FA146333C00052CD09 /* OCMRealObjectForwarder.h in Headers */,
959973
03B315FF146333C00052CD09 /* OCMObjectReturnValueProvider.h in Headers */,
974+
8BF740142476E4B400B9A52C /* OCMUnretainedArgument.h in Headers */,
960975
03B31604146333C00052CD09 /* OCObserverMockObject.h in Headers */,
961976
03B31609146333C00052CD09 /* OCPartialMockObject.h in Headers */,
962977
0368656D1D357317005E6BEE /* OCMQuantifier.h in Headers */,
@@ -1006,6 +1021,7 @@
10061021
817EB1661BD7674D0047E85A /* OCMFunctionsPrivate.h in Headers */,
10071022
03B31605146333C00052CD09 /* OCObserverMockObject.h in Headers */,
10081023
03B3160A146333C00052CD09 /* OCPartialMockObject.h in Headers */,
1024+
8BF7401A24771FD600B9A52C /* OCMUnretainedArgument.h in Headers */,
10091025
03B31614146333C00052CD09 /* OCProtocolMockObject.h in Headers */,
10101026
2FA28E1EB6B8536785258DF5 /* OCMInvocationMatcher.h in Headers */,
10111027
0322DA6A19118B4600CACAF1 /* OCMVerifier.h in Headers */,
@@ -1057,6 +1073,7 @@
10571073
817EB1591BD765130047E85A /* NSObject+OCMAdditions.h in Headers */,
10581074
817EB15A1BD765130047E85A /* NSValue+OCMAdditions.h in Headers */,
10591075
817EB15B1BD765130047E85A /* OCMFunctions.h in Headers */,
1076+
8BF7401C24771FD700B9A52C /* OCMUnretainedArgument.h in Headers */,
10601077
817EB15C1BD765130047E85A /* OCMBlockArgCaller.h in Headers */,
10611078
817EB15D1BD765130047E85A /* OCMArgAction.h in Headers */,
10621079
2FA28806443827E286F12F6F /* OCMNonRetainingObjectReturnValueProvider.h in Headers */,
@@ -1089,6 +1106,7 @@
10891106
8DE97C8C22B43EE60098C63F /* OCMBoxedReturnValueProvider.h in Headers */,
10901107
8DE97C8D22B43EE60098C63F /* OCMExceptionReturnValueProvider.h in Headers */,
10911108
8DE97C8E22B43EE60098C63F /* OCMIndirectReturnValueProvider.h in Headers */,
1109+
8BF7401D24771FD800B9A52C /* OCMUnretainedArgument.h in Headers */,
10921110
8DE97C8F22B43EE60098C63F /* OCMNotificationPoster.h in Headers */,
10931111
8DE97C9022B43EE60098C63F /* OCMObjectReturnValueProvider.h in Headers */,
10941112
8DE97C9122B43EE60098C63F /* OCMFunctionsPrivate.h in Headers */,
@@ -1146,6 +1164,7 @@
11461164
F0B951481B00810C00942C38 /* NSObject+OCMAdditions.h in Headers */,
11471165
F0B951491B00810C00942C38 /* NSValue+OCMAdditions.h in Headers */,
11481166
F0B9514A1B00810C00942C38 /* OCMFunctions.h in Headers */,
1167+
8BF7401B24771FD700B9A52C /* OCMUnretainedArgument.h in Headers */,
11491168
2FA28B7BDB3319A499E90525 /* OCMBlockArgCaller.h in Headers */,
11501169
2FA280E60213BA09F007C173 /* OCMArgAction.h in Headers */,
11511170
2FA28AFBD67EAB9DD1F23BF5 /* OCMNonRetainingObjectReturnValueProvider.h in Headers */,
@@ -1409,6 +1428,7 @@
14091428
03B315CA146333BF0052CD09 /* OCMBlockCaller.m in Sources */,
14101429
036865681D3572ED005E6BEE /* OCMQuantifier.m in Sources */,
14111430
03B315CF146333BF0052CD09 /* OCMBoxedReturnValueProvider.m in Sources */,
1431+
8BF740152476E4B400B9A52C /* OCMUnretainedArgument.m in Sources */,
14121432
03B315D4146333BF0052CD09 /* OCMConstraint.m in Sources */,
14131433
03B315D9146333BF0052CD09 /* OCMExceptionReturnValueProvider.m in Sources */,
14141434
03B315DE146333BF0052CD09 /* OCMIndirectReturnValueProvider.m in Sources */,
@@ -1451,6 +1471,7 @@
14511471
03B315CC146333BF0052CD09 /* OCMBlockCaller.m in Sources */,
14521472
036865691D3572ED005E6BEE /* OCMQuantifier.m in Sources */,
14531473
03B315D1146333BF0052CD09 /* OCMBoxedReturnValueProvider.m in Sources */,
1474+
8BF740162476E59A00B9A52C /* OCMUnretainedArgument.m in Sources */,
14541475
03DCED6D183406BC0059089E /* NSObject+OCMAdditions.m in Sources */,
14551476
03B315D6146333BF0052CD09 /* OCMConstraint.m in Sources */,
14561477
03B315DB146333BF0052CD09 /* OCMExceptionReturnValueProvider.m in Sources */,
@@ -1521,6 +1542,7 @@
15211542
817EB11F1BD765130047E85A /* OCMInvocationMatcher.m in Sources */,
15221543
0368656B1D3572ED005E6BEE /* OCMQuantifier.m in Sources */,
15231544
817EB1201BD765130047E85A /* OCMInvocationStub.m in Sources */,
1545+
8BF740182476E59B00B9A52C /* OCMUnretainedArgument.m in Sources */,
15241546
817EB1211BD765130047E85A /* OCMInvocationExpectation.m in Sources */,
15251547
817EB1221BD765130047E85A /* OCMRealObjectForwarder.m in Sources */,
15261548
817EB1231BD765130047E85A /* OCMBlockCaller.m in Sources */,
@@ -1563,6 +1585,7 @@
15631585
8DE97C5C22B43EE60098C63F /* OCMVerifier.m in Sources */,
15641586
8DE97C5D22B43EE60098C63F /* OCMInvocationMatcher.m in Sources */,
15651587
8DE97C5E22B43EE60098C63F /* OCMInvocationStub.m in Sources */,
1588+
8BF740192476E59C00B9A52C /* OCMUnretainedArgument.m in Sources */,
15661589
8DE97C5F22B43EE60098C63F /* OCMInvocationExpectation.m in Sources */,
15671590
8DE97C6022B43EE60098C63F /* OCMRealObjectForwarder.m in Sources */,
15681591
8DE97C6122B43EE60098C63F /* OCMBlockCaller.m in Sources */,
@@ -1633,6 +1656,7 @@
16331656
F0B951141B0080EC00942C38 /* OCMInvocationMatcher.m in Sources */,
16341657
0368656A1D3572ED005E6BEE /* OCMQuantifier.m in Sources */,
16351658
F0B951151B0080EC00942C38 /* OCMInvocationStub.m in Sources */,
1659+
8BF740172476E59A00B9A52C /* OCMUnretainedArgument.m in Sources */,
16361660
F0B951161B0080EC00942C38 /* OCMInvocationExpectation.m in Sources */,
16371661
F0B951171B0080EC00942C38 /* OCMRealObjectForwarder.m in Sources */,
16381662
F0B951181B0080EC00942C38 /* OCMBlockCaller.m in Sources */,

Source/OCMock/NSInvocation+OCMAdditions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
+ (NSInvocation *)invocationForBlock:(id)block withArguments:(NSArray *)arguments;
2222

23-
- (void)retainObjectArgumentsExcludingObject:(id)objectToExclude;
23+
- (void)retainObjectArgumentsExcludingObject:(id)objectToExclude excludingObjectsAtIndexes:(NSIndexSet *)indexes;
2424

2525
- (id)getArgumentAtIndexAsObject:(NSInteger)argIndex;
2626

Source/OCMock/NSInvocation+OCMAdditions.m

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ + (NSInvocation *)invocationForBlock:(id)block withArguments:(NSArray *)argument
5555

5656
static NSString *const OCMRetainedObjectArgumentsKey = @"OCMRetainedObjectArgumentsKey";
5757

58-
- (void)retainObjectArgumentsExcludingObject:(id)objectToExclude
58+
- (void)retainObjectArgumentsExcludingObject:(id)objectToExclude excludingObjectsAtIndexes:(NSIndexSet *)indexes;
5959
{
6060
if(objc_getAssociatedObject(self, OCMRetainedObjectArgumentsKey) != nil)
6161
{
@@ -80,7 +80,16 @@ - (void)retainObjectArgumentsExcludingObject:(id)objectToExclude
8080
for(NSUInteger index = 2; index < numberOfArguments; index++)
8181
{
8282
const char *argumentType = [[self methodSignature] getArgumentTypeAtIndex:index];
83-
if(OCMIsObjectType(argumentType))
83+
BOOL isObjectType = OCMIsObjectType(argumentType);
84+
if ([indexes containsIndex:index])
85+
{
86+
if (!isObjectType)
87+
{
88+
[NSException raise:NSInternalInconsistencyException format:@"Argument at %d is not an object", (int)index];
89+
}
90+
continue;
91+
}
92+
if (isObjectType)
8493
{
8594
id argument;
8695
[self getArgument:&argument atIndex:index];

Source/OCMock/OCMArg.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,22 @@
3232
+ (id)checkWithSelector:(SEL)selector onObject:(id)anObject;
3333
+ (id)checkWithBlock:(BOOL (^)(id obj))block;
3434

35+
// Unretained object arguments are not retained by invocations on the mock, but are retained by the
36+
// stub itself. A use case for this is when you are stubbing an argument to a method that does not
37+
// retain its argument using an `OCMArg` variant that you do not want to keep a reference to.
38+
// See `OCMOCK_ANY_UNRETAINED`.
39+
+ (id)unretainedObject:(id)anObject;
40+
41+
// Unsafe unretained object arguments are not retained by invocations on the mock or by the stub.
42+
// A potential use case for this is when you are stubbing methods that do not retain their
43+
// arguments and you want to verify dealloc conditions. An example of this would be verifying
44+
// KVO registration/deregistration that occurs in the init/dealloc of an object. If the object were
45+
// retained by the mocking system in any way you would never see the deregistration.
46+
// Note that you *must* keep a reference to anObject outside this call or you will crash.
47+
// Something like `[OCMArg unsafeUnretainedObject:[[Foo alloc] init]]` under ARC is a guaranteed
48+
// dangling pointer problem.
49+
+ (id)unsafeUnretainedObject:(id)anObject;
50+
3551
// manipulating arguments
3652

3753
+ (id *)setTo:(id)value;
@@ -49,6 +65,11 @@
4965

5066
#define OCMOCK_ANY [OCMArg any]
5167

68+
// See comments on [OCMArg unretainedObject] and [OCMArg unsafeUnretainedObject].
69+
#define OCMOCK_UNSAFE_UNRETAINED(x) [OCMArg unsafeUnretainedObject:(x)]
70+
#define OCMOCK_UNRETAINED(x) [OCMArg unretainedObject:(x)]
71+
#define OCMOCK_ANY_UNRETAINED OCMOCK_UNRETAINED(OCMOCK_ANY)
72+
5273
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
5374
#define OCMOCK_VALUE(variable) \
5475
({ __typeof__(variable) __v = (variable); [NSValue value:&__v withObjCType:@encode(__typeof__(__v))]; })

Source/OCMock/OCMArg.m

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#import <OCMock/OCMConstraint.h>
2020
#import "OCMPassByRefSetter.h"
2121
#import "OCMBlockArgCaller.h"
22+
#import "OCMUnretainedArgument.h"
2223

2324
@implementation OCMArg
2425

@@ -81,6 +82,16 @@ + (id)checkWithBlock:(BOOL (^)(id))block
8182
return [[[OCMBlockConstraint alloc] initWithConstraintBlock:block] autorelease];
8283
}
8384

85+
+ (id)unretainedObject:(id)anObject
86+
{
87+
return [[[OCMUnretainedArgument alloc] initWithObject:anObject safe:YES] autorelease];
88+
}
89+
90+
+ (id)unsafeUnretainedObject:(id)anObject
91+
{
92+
return [[[OCMUnretainedArgument alloc] initWithObject:anObject safe:NO] autorelease];
93+
}
94+
8495
+ (id *)setTo:(id)value
8596
{
8697
return (id *)[[[OCMPassByRefSetter alloc] initWithValue:value] autorelease];

Source/OCMock/OCMInvocationMatcher.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
NSInvocation *recordedInvocation;
2222
BOOL recordedAsClassMethod;
2323
BOOL ignoreNonObjectArgs;
24+
NSIndexSet *unretainedArgumentIndexes;
2425
}
2526

2627
- (void)setInvocation:(NSInvocation *)anInvocation;
@@ -34,4 +35,6 @@
3435
- (BOOL)matchesSelector:(SEL)aSelector;
3536
- (BOOL)matchesInvocation:(NSInvocation *)anInvocation;
3637

38+
- (NSIndexSet *)unretainedArgumentIndexes;
39+
3740
@end

Source/OCMock/OCMInvocationMatcher.m

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#import "NSInvocation+OCMAdditions.h"
2222
#import "OCMInvocationMatcher.h"
2323
#import "OCMFunctionsPrivate.h"
24+
#import "OCMUnretainedArgument.h"
2425

2526

2627
@interface NSObject(HCMatcherDummy)
@@ -33,17 +34,50 @@ @implementation OCMInvocationMatcher
3334
- (void)dealloc
3435
{
3536
[recordedInvocation release];
37+
[unretainedArgumentIndexes release];
3638
[super dealloc];
3739
}
3840

41+
- (NSIndexSet *)unretainedArgumentIndexes
42+
{
43+
return unretainedArgumentIndexes;
44+
}
45+
3946
- (void)setInvocation:(NSInvocation *)anInvocation
4047
{
48+
// Strip any "unretained arguments" from the invocation and record them.
49+
NSMutableIndexSet *unretainedIndexes = [NSMutableIndexSet indexSet];
50+
NSMutableIndexSet *unsafeUnretainedIndexes = [NSMutableIndexSet indexSet];
51+
NSMethodSignature *signature = [anInvocation methodSignature];
52+
NSUInteger n = [signature numberOfArguments];
53+
for(NSUInteger i = 2; i < n; i++)
54+
{
55+
const char *argType = [signature getArgumentTypeAtIndex:i];
56+
if (OCMIsObjectType(argType))
57+
{
58+
OCMUnretainedArgument *unretainedArg;
59+
[anInvocation getArgument:&unretainedArg atIndex:i];
60+
if ([unretainedArg isKindOfClass:[OCMUnretainedArgument class]])
61+
{
62+
[unretainedIndexes addIndex:i];
63+
if (![unretainedArg isSafe])
64+
{
65+
[unsafeUnretainedIndexes addIndex:i];
66+
}
67+
id realArg = [unretainedArg object];
68+
[anInvocation setArgument:&realArg atIndex:i];
69+
}
70+
}
71+
}
72+
[unretainedArgumentIndexes release];
73+
unretainedArgumentIndexes = [unretainedIndexes copy];
74+
4175
[recordedInvocation release];
4276
// Don't do a regular -retainArguments on the invocation that we use for matching. NSInvocation
4377
// effectively does an strcpy on char* arguments which messes up matching them literally and blows
4478
// up with anyPointer (in strlen since it's not actually a C string). Also on the off-chance that
4579
// anInvocation contains self as an argument, -retainArguments would create a retain cycle.
46-
[anInvocation retainObjectArgumentsExcludingObject:self];
80+
[anInvocation retainObjectArgumentsExcludingObject:self excludingObjectsAtIndexes:unsafeUnretainedIndexes];
4781
recordedInvocation = [anInvocation retain];
4882
}
4983

Source/OCMock/OCMUnretainedArgument.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright (c) 2015-2020 Erik Doernenburg and contributors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may
5+
* not use these files except in compliance with the License. You may obtain
6+
* a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
17+
#import <Foundation/Foundation.h>
18+
19+
// Do not use directly. See methods and comments in OCMArg.h for usage.
20+
@interface OCMUnretainedArgument : NSObject
21+
{
22+
id object;
23+
BOOL isSafe;
24+
}
25+
26+
- (instancetype)initWithObject:(id)anObject safe:(BOOL)safe;
27+
- (id)object;
28+
- (BOOL)isSafe;
29+
30+
@end

Source/OCMock/OCMUnretainedArgument.m

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright (c) 2015-2020 Erik Doernenburg and contributors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may
5+
* not use these files except in compliance with the License. You may obtain
6+
* a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
17+
#import "OCMUnretainedArgument.h"
18+
19+
20+
@implementation OCMUnretainedArgument
21+
22+
- (instancetype)initWithObject:(id)anObject safe:(BOOL)safe
23+
{
24+
if (anObject == nil)
25+
{
26+
[NSException raise:NSInvalidArgumentException format:@"Object must be non-nil for OCMUnretainedArgument"];
27+
}
28+
if ((self = [super init]))
29+
{
30+
object = anObject;
31+
isSafe = safe;
32+
if (isSafe)
33+
{
34+
object = [anObject retain];
35+
}
36+
}
37+
return self;
38+
}
39+
40+
- (void)dealloc
41+
{
42+
if (isSafe)
43+
{
44+
[object release];
45+
}
46+
[super dealloc];
47+
}
48+
49+
- (id)object
50+
{
51+
return object;
52+
}
53+
54+
- (BOOL)isSafe
55+
{
56+
return isSafe;
57+
}
58+
59+
@end

0 commit comments

Comments
 (0)