2012-05-11 87 views
5

所以基本上我實現了使用window.location =「myobj:mymethod:myarg:myotherarg」處理objc中的JavaScript調用的典型方法,但是,我想知道是否有辦法將參數數組應用於一種方法,類似於您在JavaScript中可以使用的方法。JavaScript中是否有類似於objective-c中的方法?

通常我一直在做

-(void) mymethod:(NSArray*) arr{ 
    //method knows how many arguments it takes and what they mean at each index 
} 

我喜歡做的事:

-(void) mymethod:(NSString*) myarg myOtherArg: (NSString*) myotherarg{ 
    //do stuff 
} 

,並有這樣的方法:

+(void) callMethod:(NSString*)selectorName withArgs: (NSArray*)args onObject:(id) obj{ 
    //implementation 
} 
[JEHelpers callMethod:selector withArgs:someArrayOfArgs onObject:myapp] 

這可能嗎?

回答

2

如果您知道沒有任何方法需要兩個以上的參數,則可以使用performSelector:withObject:withObject:來執行這些調用。如果該方法少於兩個參數,則未使用的withObject:字段將被忽略。

+ (id)callMethod:(NSString *)selectorName withArgs:(NSArray *)args onObject:(id)obj { 
    id arg1 = nil, arg2 = nil; 
    if([args count]) { 
     arg1 = [args objectAtIndex:0]; 
     if([args count] > 1]) 
      arg2 = [args objectAtIndex:1]; 
    } 
    return [obj performSelector:NSSelectorFromString(selectorName) 
        withObject:arg1 withObject:arg2]; 
} 

如果可能有兩個以上的參數,您將不得不使用NSInvocation。這個類允許你通過傳遞各種參數並定義選擇器和對象來構造消息,然後發送消息並獲得結果。

+ (id)callMethod:(NSString *)selectorName withArgs:(NSArray *)args onObject:(id)obj { 
    SEL sel = NSSelectorFromString(selectorName); 
    NSMethodSignature *signature = [obj methodSignatureForSelector:sel]; 
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; 
    [invocation setSelector:sel]; 
    [invocation setTarget:obj]; 
    NSUInteger index = 2; 
    for(id arg in args) { 
     [invocation setArgument:&arg atIndex:index]; 
     ++index; 
    } 
    id result; 
    [invocation setReturnValue:&result]; 
    [invocation invoke]; 
    return result; 
} 
+0

是的......但重點是能夠以與JS應用函數相同的方式將一組動態參數應用於方法,以在WebView JS函數調用與本機Objective- C方法。所以基本上我可以有一個名爲JSFunctionMethods的另一個Objective-C類,它將鏡像我在我的webview中實現的JS API中的JS調用的API。感謝您的意見,我希望我能更好地澄清。 –

+0

@Jesse我只記得如何使用'NSInvocation'。看到我的增加(或@安德魯的答案)。 – ughoavgfhw

+0

哦,這太棒了!謝謝! –

2

我不確定我完全理解了這個問題(我不太瞭解JavaScript)。但是,您可以使用NSInvocation向任何對象發送任意消息。像這樣:

+(void) callMethod:(NSString*)selectorName withArgs: (NSArray*)args onObject:(id) obj 
{ 
    SEL selector = NSSelectorFromString(selectorName); 
    if (![obj respondsToSelector:selector]) { 
     // Object doesn't respond to selector, so do something else/handle the error 
    } 
    NSMethodSignature *methodSignature = [obj methodSignatureForSelector:selector]; 
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; 
    [invocation setTarget:obj]; 
    [invocation setSelector:selector]; 
    for (NSUInteger i=0; i<[args count]; i++) { 
     id argument = [args objectAtIndex:i]; 
     [invocation setArgument:&argument atIndex:i+2]; // Arg 0 is self, arg 1 is _cmd 
    } 
    id result; 
    [invocation setReturnValue:&result]; 
    [invocation invoke]; 
} 
+0

謝謝安德魯......這正是我所需要的。 –

1

你可能想看看NSInvocation。具體而言,您想要使用selectorName的方法簽名(NSObject -methodSignatureForSelector :)構建NSInvocation,然後設置選擇器,目標和參數。請記住:你應該檢查參數類型(NSMethodSignature -getArgumentTypeAtIndex:是否等於'@'),並且傳遞的參數是從2開始索引的(因爲0和1是對象的self和方法選擇器)。

我不是說這是個好主意,順便說一句;有很多情況下,這種方法是有保證的。

+0

我認爲我的用途很適合。非常感謝! –

0

這是一個有點笨拙,但它是可能的:

- (id)method:(NSString *)arg1, ... { 
    va_list args; 
    va_start(args, arg1); 
    for (NSString *a = arg1; a!= nil; a= va_arg(args, NSString*)) { 
    // do stuff 
    } 
} 

傳統arg1將是定義的數據類型和額外的參數號的字符串。

你會這樣稱呼它:

[self method:@"5", @"4", @"3", @"2", @"1"]; 

你的陣列方法可能對於大多數的目的更加清晰。

+0

嗯耶...這就是我想要避免的......我基本上在尋找一個鏡像API在我的JS和OBJC代碼,用一些橋接翻譯的方法。謝謝。 –

+0

認爲你更喜歡NSInvocation方法,但同樣認爲值得證明有另一種方法可以做到這一點。 (如果你添加一個包裝器,這在C中而不是在Objective-C中幾乎是一樣的。) –

相關問題