Question

Excuse me for my crazy needs, but I'm creating a bunch of property-only protocols in a framework I'm writing.

@protocol SomePropertiesOfAnObjectThing <NSObject>

@property (nonatomic, strong) NSString *larry;
@property (nonatomic, strong) NSString *curly;
@property (nonatomic, strong) NSString *moe;

@end

Is there a way, more importantly an easy way, to "mock" out an object that implements this protocol?

id<SomePropertiesOfAnObjectThing> thingy = [ProtocolObject fromProtocol:@protocol(SomePropertiesOfAnObjectThing)];

thingy.larry = @"fizz";
thingy.curly = @"buzz";
thingy.moe = @"bar";

The 2 things I'm trying to avoid:

  1. Explicitly creating a new class
  2. 3rd party dependencies (such as OCMock)

I will shower anyone who can show me a clean and easy way with up votes (well, 1 at least).

Was it helpful?

Solution 2

My naïve solution is as follows:

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    return [[self class] instanceMethodSignatureForSelector:@selector(foo:)];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    NSString *argument;
    [anInvocation getArgument:&argument atIndex:2];
    if (argument) {
        NSString *setterName = NSStringFromSelector(anInvocation.selector);
        NSRange range = NSMakeRange(3, [setterName length]-4);
        NSString *propertyName = [[setterName substringWithRange:range] lowercaseString];
        [self performSelector:@selector(setFoo:value:) withObject:propertyName withObject:argument];
    } else {
        [self performSelector:@selector(foo:) withObject:argument];
    }
}

- (id)foo:(id)key
{
    return self.properties[key];
}

- (void)setFoo:(id)key value:(id)value
{
    self.properties[key] = value;
}

- (id)valueForKey:(NSString *)key
{
    return self.properties[key];
}

- (void)setValue:(id)value forKey:(NSString *)key
{
    self.properties[key] = value;
}

I will update with a cleaner version later as I optimize for value types and the such.

OTHER TIPS

The thing about protocols is you're only making a promise to the compiler that a certain Class will implement the methods defined in the protocol. It is up to you to create a Class that actually provides implementations for the methods. Properties defined in a protocol are not auto-synthesized by a Class that declares to conform to a protocol, you need to define the underlying ivar and implement setters and getters for each property defined in the protocol to fully conform to it.

In other words, thingy up there doesn't get these properties for free just because it conforms to the protocol.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top