Support for block-based callbacks. Fixed a couple bugs with delegates. · DinosaurDad/GAJavaScript@86fac26 · GitHub
Skip to content

Commit 86fac26

Browse files
Andrew GoodaleAndrew Goodale
authored andcommitted
Support for block-based callbacks. Fixed a couple bugs with delegates.
1 parent 5f31326 commit 86fac26

11 files changed

Lines changed: 178 additions & 21 deletions

Classes/GAScriptEngine.m

Lines changed: 51 additions & 9 deletions

Classes/GAScriptEnginePrivate.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//
2+
// GAScriptEnginePrivate.h
3+
// GAJavaScript
4+
//
5+
// Created by Andrew Goodale on 6/6/11.
6+
// Copyright 2011 Wingspan Technology, Inc. All rights reserved.
7+
//
8+
9+
#import <Foundation/Foundation.h>
10+
#import "GAScriptEngine.h"
11+
12+
@interface GAScriptEngine (Private)
13+
14+
/**
15+
* Saves (retains) the given argument if it's needed for an asynchronous callback.
16+
*/
17+
- (void)retainCallArgumentIfNecessary:(id)argument;
18+
19+
@end
20+
21+
#pragma mark -
22+
23+
/**
24+
* Wraps a block so it can be called from JavaScript. Not public right now,
25+
* but it could be useful for allowing people to use in their own classes.
26+
*/
27+
@interface GAScriptBlockObject : NSObject
28+
{
29+
id _blockObject;
30+
NSArray* _arguments;
31+
}
32+
33+
- (id)initWithBlock:(void(^)(NSArray* arguments))block;
34+
35+
- (void)setArgumentsFromJavaScript:(NSArray *)arguments;
36+
37+
- (void)invoke;
38+
39+
@end

Classes/GAScriptMethodSignatures.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,6 @@
2929

3030
- (id)getElementsByTagName:(NSString *)tagName;
3131

32+
- (id)item:(NSInteger)index;
33+
3234
@end

Classes/GAScriptMethodSignatures.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,9 @@ - (id)getElementsByTagName:(NSString *)tagName
5454
return nil;
5555
}
5656

57+
- (id)item:(NSInteger)index
58+
{
59+
return nil;
60+
}
61+
5762
@end

Classes/GAScriptObject.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,11 @@ static NSString* const GAJavaScriptErrorDomain;
9191
- (id)valueForKeyPath:(NSString *)keyPath;
9292

9393
@end
94+
95+
#pragma mark -
96+
97+
@interface GAScriptObject (Blocks)
98+
99+
- (void)setFunctionForKey:(NSString *)key withBlock:(void(^)(NSArray* arguments))block;
100+
101+
@end

Classes/GAScriptObject.m

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
2828

2929
#import "GAScriptObject.h"
3030
#import "GAScriptMethodSignatures.h"
31+
#import "GAScriptEnginePrivate.h"
3132
#import "NSObject+GAJavaScript.h"
3233

3334
typedef struct /* GAScriptObjectEnumState */
@@ -54,6 +55,8 @@ - (NSArray *)arrayFromJavaScript:(NSString *)result reference:(NSString *)refere
5455

5556
- (NSError *)errorFromJavaScript:(NSString *)result;
5657

58+
- (id)convertArgument:(NSInvocation *)invocation atIndex:(NSInteger)index;
59+
5760
@end
5861

5962
#pragma mark -
@@ -231,6 +234,18 @@ - (id)valueForUndefinedKey:(NSString *)key
231234
return nil;
232235
}
233236

237+
#pragma mark Blocks
238+
239+
- (void)setFunctionForKey:(NSString *)key withBlock:(void(^)(NSArray* arguments))block
240+
{
241+
GAScriptBlockObject* myBlock = [[GAScriptBlockObject alloc] initWithBlock:block];
242+
243+
id scriptEngine = m_webView.delegate;
244+
[scriptEngine retainCallArgumentIfNecessary:myBlock];
245+
246+
[self setValue:myBlock forKey:key];
247+
}
248+
234249
#pragma mark Private
235250

236251
- (id)convertScriptResult:(NSString *)result reference:(NSString *)reference
@@ -384,19 +399,16 @@ - (void)forwardInvocation:(NSInvocation *)anInvocation
384399
}
385400
else if (numberOfArgs == 3)
386401
{
387-
id singleArg; // TODO: Handle non-Object types
388-
389-
[anInvocation getArgument:&singleArg atIndex:2];
402+
id singleArg = [self convertArgument:anInvocation atIndex:2];
390403
retVal = [self callFunction:functionName withObject:singleArg];
391404
}
392405
else if (numberOfArgs > 3)
393406
{
394-
id singleArg;
395407
NSMutableArray* arguments = [[NSMutableArray alloc] initWithCapacity:numberOfArgs];
396408

397409
for (int i = 2; i < numberOfArgs; ++i)
398410
{
399-
[anInvocation getArgument:&singleArg atIndex:i];
411+
id singleArg = [self convertArgument:anInvocation atIndex:i];
400412
[arguments addObject:singleArg];
401413
}
402414

@@ -410,4 +422,20 @@ - (void)forwardInvocation:(NSInvocation *)anInvocation
410422
[anInvocation setReturnValue:&retVal];
411423
}
412424

425+
- (id)convertArgument:(NSInvocation *)invocation atIndex:(NSInteger)index
426+
{
427+
void* argValue;
428+
[invocation getArgument:&argValue atIndex:index];
429+
430+
const char* type = [[invocation methodSignature] getArgumentTypeAtIndex:index];
431+
432+
if (*type == 'c')
433+
return [NSNumber numberWithBool:(int)argValue];
434+
435+
if (*type == 'i')
436+
return [NSNumber numberWithInt:(int)argValue];
437+
438+
return (id) argValue;
439+
}
440+
413441
@end

Classes/NSObject+GAJavaScript.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ - (NSString *)stringForJavaScript
4444
const char* propName = property_getName(propList[i]);
4545
id propValue = [self valueForKey:[NSString stringWithCString:propName encoding:NSASCIIStringEncoding]];
4646

47+
if (propValue == self) // To prevent endless recursion, check for property values that are us!
48+
continue;
49+
4750
if (i > 0)
4851
[target appendFormat:@"%c", ','];
4952

GAJavaScript.xcodeproj/project.pbxproj

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
/* Begin PBXBuildFile section */
1010
2D5994871382B0F0006B728D /* TScriptEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D5994861382B0F0006B728D /* TScriptEngine.m */; };
11+
2D81DF5F139D796900CA599F /* GAScriptEnginePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D81DF5D139D796900CA599F /* GAScriptEnginePrivate.h */; };
1112
2D8500AE1381647F00758EA2 /* GAScriptEngine.h in Headers */ = {isa = PBXBuildFile; fileRef = 2D8500AC1381647F00758EA2 /* GAScriptEngine.h */; };
1213
2D8500AF1381647F00758EA2 /* GAScriptEngine.m in Sources */ = {isa = PBXBuildFile; fileRef = 2D8500AD1381647F00758EA2 /* GAScriptEngine.m */; };
1314
2D8500B213816B2100758EA2 /* TestWebViewContent.html in Resources */ = {isa = PBXBuildFile; fileRef = 2D8500B113816B2100758EA2 /* TestWebViewContent.html */; };
@@ -20,7 +21,6 @@
2021
493386AD12B582A300FBE23C /* NSObject+GAJavaScript.m in Sources */ = {isa = PBXBuildFile; fileRef = 493386AB12B582A300FBE23C /* NSObject+GAJavaScript.m */; };
2122
4933871412B58C9E00FBE23C /* TWebView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4933870F12B58C5700FBE23C /* TWebView.m */; };
2223
4983385F13782DFC0006B26A /* ApplicationDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4983385E13782DFC0006B26A /* ApplicationDelegate.m */; };
23-
49839832138C7CFA003A23D6 /* TScriptObjectBlocks.m in Sources */ = {isa = PBXBuildFile; fileRef = 49839831138C7CFA003A23D6 /* TScriptObjectBlocks.m */; };
2424
498A2C5013928F6600B95CC9 /* GAScriptMethodSignatures.h in Headers */ = {isa = PBXBuildFile; fileRef = 498A2C4E13928F6600B95CC9 /* GAScriptMethodSignatures.h */; };
2525
498A2C5113928F6600B95CC9 /* GAScriptMethodSignatures.m in Sources */ = {isa = PBXBuildFile; fileRef = 498A2C4F13928F6600B95CC9 /* GAScriptMethodSignatures.m */; };
2626
49F1DBDE12A3F64A004C8736 /* GAScriptObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 49F1DBDA12A3F64A004C8736 /* GAScriptObject.h */; };
@@ -46,6 +46,7 @@
4646
/* Begin PBXFileReference section */
4747
2D5994851382B0F0006B728D /* TScriptEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TScriptEngine.h; path = Tests/TScriptEngine.h; sourceTree = "<group>"; };
4848
2D5994861382B0F0006B728D /* TScriptEngine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TScriptEngine.m; path = Tests/TScriptEngine.m; sourceTree = "<group>"; };
49+
2D81DF5D139D796900CA599F /* GAScriptEnginePrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GAScriptEnginePrivate.h; path = Classes/GAScriptEnginePrivate.h; sourceTree = "<group>"; };
4950
2D8500AC1381647F00758EA2 /* GAScriptEngine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GAScriptEngine.h; path = Classes/GAScriptEngine.h; sourceTree = "<group>"; };
5051
2D8500AD1381647F00758EA2 /* GAScriptEngine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GAScriptEngine.m; path = Classes/GAScriptEngine.m; sourceTree = "<group>"; };
5152
2D8500B113816B2100758EA2 /* TestWebViewContent.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = TestWebViewContent.html; path = Tests/TestWebViewContent.html; sourceTree = "<group>"; };
@@ -62,8 +63,6 @@
6263
4933870F12B58C5700FBE23C /* TWebView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TWebView.m; path = Tests/TWebView.m; sourceTree = "<group>"; };
6364
4983385D13782DFC0006B26A /* ApplicationDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ApplicationDelegate.h; path = Tests/ApplicationDelegate.h; sourceTree = "<group>"; };
6465
4983385E13782DFC0006B26A /* ApplicationDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ApplicationDelegate.m; path = Tests/ApplicationDelegate.m; sourceTree = "<group>"; };
65-
49839830138C7CFA003A23D6 /* TScriptObjectBlocks.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TScriptObjectBlocks.h; path = Tests/TScriptObjectBlocks.h; sourceTree = "<group>"; };
66-
49839831138C7CFA003A23D6 /* TScriptObjectBlocks.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TScriptObjectBlocks.m; path = Tests/TScriptObjectBlocks.m; sourceTree = "<group>"; };
6766
498A2C4E13928F6600B95CC9 /* GAScriptMethodSignatures.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GAScriptMethodSignatures.h; path = Classes/GAScriptMethodSignatures.h; sourceTree = "<group>"; };
6867
498A2C4F13928F6600B95CC9 /* GAScriptMethodSignatures.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GAScriptMethodSignatures.m; path = Classes/GAScriptMethodSignatures.m; sourceTree = "<group>"; };
6968
49F1DBDA12A3F64A004C8736 /* GAScriptObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GAScriptObject.h; path = Classes/GAScriptObject.h; sourceTree = "<group>"; };
@@ -141,6 +140,7 @@
141140
49F1DBDB12A3F64A004C8736 /* GAScriptObject.m */,
142141
498A2C4E13928F6600B95CC9 /* GAScriptMethodSignatures.h */,
143142
498A2C4F13928F6600B95CC9 /* GAScriptMethodSignatures.m */,
143+
2D81DF5D139D796900CA599F /* GAScriptEnginePrivate.h */,
144144
493386AA12B582A300FBE23C /* NSObject+GAJavaScript.h */,
145145
493386AB12B582A300FBE23C /* NSObject+GAJavaScript.m */,
146146
49F1DC8D12A3F7E2004C8736 /* UIWebView+GAJavaScript.h */,
@@ -168,8 +168,6 @@
168168
2D5994861382B0F0006B728D /* TScriptEngine.m */,
169169
4933848412B4373600FBE23C /* TScriptObject.h */,
170170
4933848512B4373600FBE23C /* TScriptObject.m */,
171-
49839830138C7CFA003A23D6 /* TScriptObjectBlocks.h */,
172-
49839831138C7CFA003A23D6 /* TScriptObjectBlocks.m */,
173171
4933870E12B58C5700FBE23C /* TWebView.h */,
174172
4933870F12B58C5700FBE23C /* TWebView.m */,
175173
493383A012B4338200FBE23C /* GAJavaScriptTests-Info.plist */,
@@ -191,6 +189,7 @@
191189
493386AC12B582A300FBE23C /* NSObject+GAJavaScript.h in Headers */,
192190
2D8500AE1381647F00758EA2 /* GAScriptEngine.h in Headers */,
193191
498A2C5013928F6600B95CC9 /* GAScriptMethodSignatures.h in Headers */,
192+
2D81DF5F139D796900CA599F /* GAScriptEnginePrivate.h in Headers */,
194193
);
195194
runOnlyForDeploymentPostprocessing = 0;
196195
};
@@ -280,7 +279,6 @@
280279
4933871412B58C9E00FBE23C /* TWebView.m in Sources */,
281280
4983385F13782DFC0006B26A /* ApplicationDelegate.m in Sources */,
282281
2D5994871382B0F0006B728D /* TScriptEngine.m in Sources */,
283-
49839832138C7CFA003A23D6 /* TScriptObjectBlocks.m in Sources */,
284282
);
285283
runOnlyForDeploymentPostprocessing = 0;
286284
};

Tests/TScriptEngine.m

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
2828

2929
#import "TScriptEngine.h"
3030
#import "GAScriptEngine.h"
31+
#import "GAScriptObject.h"
3132

3233
@implementation TScriptEngine
3334

@@ -84,6 +85,30 @@ - (void)testCallbackAsArgument
8485
[self waitForStatus:kGHUnitWaitStatusSuccess timeout:1.0];
8586
}
8687

88+
- (void)testCallbackWithBlock
89+
{
90+
[self prepare];
91+
92+
__block id rightNow = nil;
93+
94+
void (^nowBlock)(NSArray*) = ^ (NSArray* arguments)
95+
{
96+
rightNow = [NSDate date];
97+
// NSLog(@"The date and time is %@", rightNow);
98+
99+
[self notify:kGHUnitWaitStatusSuccess];
100+
};
101+
102+
GAScriptObject* jsObject = [_engine newScriptObject];
103+
104+
[jsObject setFunctionForKey:@"nowBlock" withBlock:nowBlock];
105+
106+
[jsObject callFunction:@"nowBlock"];
107+
[jsObject release];
108+
109+
[self waitForStatus:kGHUnitWaitStatusSuccess timeout:1.0];
110+
}
111+
87112
- (void)callbackNoArgs
88113
{
89114
// NSLog(@"Callback() from JavaScript");

Tests/TScriptObject.m

Lines changed: 4 additions & 1 deletion

0 commit comments

Comments
 (0)