9

これで楽しい時間を過ごしてください。

1 つの WebView、ページで定義された WebScripting API、およびその API で定義された 1 つの NSObject を含む非常にシンプルな Cocoa アプリを作成しました。(埋め込まれた WebView で) デバッガー ツールをオンにすると、JavaScript ウィンドウ オブジェクトに API が表示され、その上に定義された "api" プロパティが表示されますが、API の "get" メソッドを呼び出すと、引数がシリアル化されていません。Obj-C メソッドが呼び出されたときに、引数が欠落しています。以下を参照してください。

ここに画像の説明を入力

私はドキュメントをくまなく調べ、(どうやら) 適切なメソッドを設定して、公開する必要があるすべてのものを公開しました。メソッドが呼び出されていることがわかります。私が見逃しているばかげた何かがあるに違いありませんが、この環境の比較的初心者として、私はそれを見ていません。

よろしくお願いします。

4

3 に答える 3

2

-[NSUserDefaults registerDefaults:] を送信するときに、デフォルトのユーザー デフォルトで WebKitDeveloperExtras を YES に設定しましたか?

于 2012-05-01T19:34:24.367 に答える
1

使用している Xcode のバージョンによっては、既知のエラーが発生する可能性があります。最新バージョン以外で LLDB を使用している場合、デバッガーで正しい変数が得られない可能性があります。解決策は、Apple が問題を修正するまで、LLDB の代わりに GDB を使用することでした。しかし、彼らは最新バージョンで問題を修正したと思います。GDB を使用するようにデバッガーを変更し、Xcode で正しい変数を取得しているかどうかを確認します。(製品 -> スキームの編集... -> 実行 -> デバッガー)。ただし、この問題は iOS で発生したため、OSX に適用できるかどうかはわかりません。とにかく試してみる価値があります。

私はもともとここで問題に遭遇しました: https://stackoverflow.com/a/9485349/1147934

于 2012-05-01T16:56:27.770 に答える
0

アプリ ディレクトリに保存されているローカル ファイルからアプリのメイン スレッドで JavaScript を処理します。実行している js 関数の開始トークンと終了トークン、および関数に変数が含まれているかどうかを確認します。

うまくいけば、これがあなたの問題に対する良いアイデアを与えることができます. js でアラートを実行して、アプリを実行したときに値が正しく送信されるかどうかを確認することもできます (すでに考えていると思いますが、言及する価値があります)。これが役立つことを願っています!

.h ファイルで次を定義します。

NSMutableString *processedCommand;
NSArray *commandArguments;

.m ファイル内:

// tokens
#define kOpenToken @"<%%"
#define kCloseToken @"%%>"

// this will throw
-(void)executeJScriptCommand:(NSString *)aCommand {

[self performSelectorOnMainThread:@selector(executeThisCommand:) withObject:aCommand waitUntilDone:YES];
}

// this will throw 
-(NSString *)executeCommand:(NSString *)command {

NSString *aCommand = [[[command stringByReplacingOccurrencesOfString:kOpenToken withString:@""] 
                       stringByReplacingOccurrencesOfString:kCloseToken withString:@""] 
                      stringByTrimmingLeadingAndTrailingWhitespaces];

if ([aCommand hasPrefix:@"="])
{
    // variable. get value
    [self getVariableFromCommand:aCommand]; 
}
else {
    [self executeThisCommand:aCommand];
}

NSString *returnValue = [NSString stringWithString:processedCommand];

self.processedCommand = nil;
self.commandArguments = nil;

return returnValue;
}

-(void)executeThisCommand:(NSString *)aCommand {

BOOL hasError = NO;

// clear result
self.processedCommand = nil;
self.commandArguments = nil;

BOOL isFromJS = NO;
NSString *function = nil;
NSMutableArray *commandParts = nil;

@try {
    // first, break the command into its parts and extract the function that needs to be called, and the (optional) arguments
    commandParts = [[NSMutableArray alloc] initWithArray:[aCommand componentsSeparatedByString:@":"]];
    if ([[[commandParts objectAtIndex:0] lowercaseString] isEqualToString:@"js-call"]) {
        isFromJS = YES;
        [commandParts removeObjectAtIndex:0];
    }

    // get our function, arguments
    function = [[commandParts objectAtIndex:0] retain];
    [commandParts removeObjectAtIndex:0];

    if ([commandParts count] > 0){
        if (isFromJS == YES) {
            NSString *arguments = [[commandParts objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
            if ([arguments length] > 0) {
                self.commandArguments = [arguments JSONValue];
            }
        }
        else {
            self.commandArguments = [NSArray arrayWithArray:commandParts];
        }
    }

    // build invoke
    SEL sel = NSSelectorFromString(function);

    if ([self respondsToSelector:sel]) {

        [self performSelectorOnMainThread:sel withObject:nil waitUntilDone:YES];

        // using invocation causes a SIGABORT because the try/catch block was not catching the exception.
        // using perform selector fixed the problem (i.e., the try/catch block now correctly catches the exception, as expected)

    }
    else {
        [appDelegate buildNewExceptionWithName:@"" andMessage:[NSString stringWithFormat:@"Object does not respond to selector %@", function]];
    }

}
@catch (NSException * e) {
    hasError = YES;
    [self updateErrorMessage:[NSString stringWithFormat:@"Error processing command %@: %@", aCommand,  [e reason]]];
}
@finally {
    [function release];
    [commandParts release];
}

if (hasError == YES) {
    [appDelegate buildNewExceptionWithName:@"executeThisCommand" andMessage:self.errorMessage];
}
}

// this can return nil
-(NSString *)getQueryStringValue:(NSString *)name {

NSString *returnValue = nil;
if (queryString != nil) {
    returnValue = [queryString objectForKey:[name lowercaseString]];
}

return returnValue;
}
于 2012-05-08T17:10:30.707 に答える