0

タイトルが言ったように: 私は ObjcClass を持って -(void)test1:xxx -(void)test2:xxx argu:yyy います。

[dispatchArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
      [obj test2:xxx argu:yyy];
 }];

例:

 - (void)test:(NSString *)argument1 {
    NSArray *dispatchArray = @[];//If the array is initialized with multiple objects
//I want each object to call the "test:" method unlike the following
//    [dispatchArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
//        [obj performSelector:@selector(test:) withObject:argument1];
//        // or [obj test:argument1];
//    }];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [_services enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL * stop) {
        if ([obj respondsToSelector:_cmd]) {
            [obj application:application didFinishLaunchingWithOptions:launchOptions];
        }
    }];

    return YES;
}

このように ,UIApplicationDelegate にはいくつかのメソッドがあります ,書きたくない [obj application:application didFinishLaunchingWithOptions:launchOptions]; または[obj applicationWillResignActive:application]; どのメソッドでも、逆に [obj RespondsToSelector:_cmd] のようなメソッド、[obj invokeWithMethod:_cmd arguments:_VA_LIST] のような一般的なメソッドとして提案できることを願ってますこれらのメソッドは異なるメソッドに対して同じことを行うため、最適化できるかどうか

4

2 に答える 2

1

アプリでデリゲートするメソッドが実装されているので、以前と同様に実装する必要があります。UIApplicationDelegateアプリのデリゲートが実装していないプロトコルのメソッドに対して、メッセージ転送を使用して目標を達成できます。アプリ デリゲートのメッセージ転送メソッドを次のようにオーバーライドします。

- (BOOL)respondsToSelector:(SEL)aSelector {
    struct objc_method_description desc = protocol_getMethodDescription(objc_getProtocol("UIApplicationDelegate"), aSelector, NO, YES);
    if (desc.name != nil) {
        return YES;
    }
    return [super respondsToSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    SEL selector = [anInvocation selector];
    struct objc_method_description desc = protocol_getMethodDescription(objc_getProtocol("UIApplicationDelegate"), selector, NO, YES);
    if (desc.name != nil) {
        [_services enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([obj respondsToSelector:selector]) {
                [anInvocation invokeWithTarget:obj];
            }
        }];
    }
}

戻り値を取得します。

NSMutableArray *returnValues = [NSMutableArray array];
[_services enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    id returnValue = [NSNull null];
    if ([obj respondsToSelector:selector]) {
        [anInvocation invokeWithTarget:obj];

        const char *returnType = anInvocation.methodSignature.methodReturnType;

        if( !strcmp(returnType, @encode(void)) ){
            //If the return value is `void`, just set returnValue = [NSNull null]
        } else if( !strcmp(returnType, @encode(id)) ){
            // if the return type is derived data types(`id`)
            [anInvocation getReturnValue:&returnValue];
        }else{
            //if the return value is basicdata type
            NSUInteger length = [anInvocation.methodSignature methodReturnLength];
            void *buffer = (void *)malloc(length);
            [anInvocation getReturnValue:buffer];
            if( !strcmp(returnType, @encode(BOOL)) ) {
                returnValue = [NSNumber numberWithBool:*((BOOL*)buffer)];  
            } else if( !strcmp(returnType, @encode(NSInteger)) ){
                returnValue = [NSNumber numberWithInteger:*((NSInteger*)buffer)];  
            }  
            returnValue = [NSValue valueWithBytes:buffer objCType:returnType];
        }
    }
    // If the `obj` can not responds to selector, or the return value is void(nil), we set the `returnValue = [NSNull null]`
    [returnValues addObject:returnValue];
}]
于 2016-07-29T03:53:09.793 に答える
0

配列内のオブジェクトをループしたいだけのようです。これはあまり型安全ではありません。すべてのオブジェクトは「テスト」メソッドを提供する必要があります。それらがすべて同じクラスである場合、NSObject を使用するよりも優れています。

for (NSObject *obj in dispatchArray) {
        [obj performSelector:@selector(test:) withObject:argument1];
}
于 2016-07-29T03:31:26.760 に答える