Arton
Arton

Reputation: 453

objc variadic arguments with primary type and objects

I have a set of lower-layer api, as below:

- (NSDictionary*) startRecord;
- (NSDictionary*) stopRecord;
- (NSDictionary*) switchMicrophone;
- (NSDictionary*) enableAutoRecord:(BOOL)enable;
- (NSDictionary*) deleteFile:(NSString*)filename;
- (NSDictionary*) enableDatetimeStampOverlay:(BOOL)enable;
- (NSDictionary*) setVideoResolution:(RESOLUTION_PARA)param;
- (NSDictionary*) setExposureValue:(EXPOSURE_VALUE_PARA)param;
- (NSDictionary*) setVolume:(VOLUME_PARA)param;
- (NSDictionary*) setWifiConfigWithSsid:(NSString*)ssid AndPassword:(NSString*)password;
- (NSDictionary*) formatSDCard;
// ... the # of parameters are at most 3

I would like to create a higher-layer api to wrap lower-layer api, one of it is like below:

- (void) enableAutoRecord:(BOOL)isEnable
{
    ...
    dispatch_async( self.mySerialQueue, ^{
        ...
        NSDictionary *response = [self.lowerLayer enableAutoRecord:isEnable];
        ...
    });
}

For the higher-layer, I found that there are so many copy&pastes. I hope I can rewrite it as below:

- (void) enableAutoRecord:(BOOL)isEnable
{
     [self wrap_lower_layer_command:@"enableAutoRecord:", isEnable];
}

How to write a "wrap_lower_layer_command"? I have studied nsinvocation, objc_sendMsg, and variadic arguments. But I am stuck on the type problem. Take invocation for example:

T arg = p1;
[invocation setArgument:&arg atIndex:2];

I don't know what the type p1 is. It maybe an id, or a BOOL, or a int, or something else. Is there a better way to refactor the copy&paste code in the higher-layer api? Any hint is appreciated!

Upvotes: 0

Views: 72

Answers (1)

Jeffery Thomas
Jeffery Thomas

Reputation: 42588

You need to look into Message Forwarding.

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    if ([self.lowerLayer respondsToSelector:[anInvocation selector]]) {
        [anInvocation retainArguments]; // Thanks newacct
        dispatch_async(self.mySerialQueue, ^{
            …
            [anInvocation invokeWithTarget:self.lowerLayer];

            void *returnValue;
            [invocation getReturnValue:&returnValue];
            NSDictionary *response = (__bridge NSDictionary *)returnValue;
            …
        });
    } else {
        [super forwardInvocation:anInvocation];
    }
}

I forgot to include the part about the return value.


Added -retainArguments.

Upvotes: 2

Related Questions