Skip to content

Commit 7c89c56

Browse files
author
Andrew Goodale
committed
Refactored GAScriptObject to use GAScriptEngine instead of UIWebView directly. This simplified much of the code, and helped fix memory management issues for block-based callbacks. UIWebView category exposes more built-in objects now.
1 parent d033b32 commit 7c89c56

13 files changed

Lines changed: 329 additions & 270 deletions

File tree

Classes/GAScriptBlockObject.h

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2011 Andrew Goodale. All rights reserved.
2+
Copyright (c) 2011-2012 Andrew Goodale. All rights reserved.
33
44
Redistribution and use in source and binary forms, with or without modification, are
55
permitted provided that the following conditions are met:
@@ -27,19 +27,23 @@
2727
*/
2828

2929
#import <Foundation/Foundation.h>
30-
#import "GAScriptObject.h"
30+
#import "GAScriptEngine.h"
3131

3232
typedef void (^GAScriptBlock)(NSArray *);
3333

3434
/**
35-
* Wraps a block so it can be called from JavaScript. Not public right now,
36-
* but it could be useful for allowing people to use in their own classes.
35+
* Wraps a block so it can be called from JavaScript. This opbject can be used to pass
36+
* blocks as arguments to JavaScript function calls.
3737
*/
3838
@interface GAScriptBlockObject : NSObject
3939
{
40-
GAScriptBlock _blockObject;
40+
NSString* m_blockId;
41+
GAScriptBlock m_block;
4142
}
4243

44+
@property (nonatomic, readonly) NSString* blockId;
45+
@property (nonatomic, readonly) GAScriptBlock block;
46+
4347
+ (id)scriptBlockWithBlock:(GAScriptBlock)block;
4448

4549
- (id)initWithBlock:(GAScriptBlock)block;
@@ -52,13 +56,8 @@ typedef void (^GAScriptBlock)(NSArray *);
5256
* Add support for functions that are proxies to a block. When the function is called from JavaScript,
5357
* the block will be invoked.
5458
*/
55-
@interface GAScriptObject (Blocks)
59+
@interface GAScriptEngine (Blocks)
5660

57-
/**
58-
* Creates a JavaScript function that will invoke the given block when called. The block will be copied
59-
* and a reference managed by this script object instance. Make sure your block is on the heap if it's
60-
* needed after this script object is deallocated.
61-
*/
62-
- (void)setFunctionForKey:(NSString *)key withBlock:(void(^)(NSArray* arguments))block;
61+
- (void)addBlockCallback:(GAScriptBlockObject *)blockObject;
6362

6463
@end

Classes/GAScriptBlockObject.m

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2011 Andrew Goodale. All rights reserved.
2+
Copyright (c) 2011-2012 Andrew Goodale. All rights reserved.
33
44
Redistribution and use in source and binary forms, with or without modification, are
55
permitted provided that the following conditions are met:
@@ -30,6 +30,9 @@ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
3030

3131
@implementation GAScriptBlockObject
3232

33+
@synthesize blockId = m_blockId,
34+
block = m_block;
35+
3336
+ (id)scriptBlockWithBlock:(GAScriptBlock)block
3437
{
3538
return [[[GAScriptBlockObject alloc] initWithBlock:block] autorelease];
@@ -39,15 +42,17 @@ - (id)initWithBlock:(GAScriptBlock)block
3942
{
4043
if ((self = [super init]))
4144
{
42-
_blockObject = [block copy];
45+
m_block = [block copy];
46+
m_blockId = [[NSString alloc] initWithFormat:@"block-%u", [self hash]];
4347
}
4448

4549
return self;
4650
}
4751

4852
- (void)dealloc
4953
{
50-
[_blockObject release];
54+
[m_blockId release];
55+
[m_block release];
5156

5257
[super dealloc];
5358
}
@@ -58,33 +63,11 @@ - (void)dealloc
5863
*/
5964
- (NSString *)stringForJavaScript
6065
{
61-
NSAssert(_blockObject, @"Block for callback cannot be NULL!");
62-
// NSLog(@"ScriptBlockObject: function () { GAJavaScript.invocation(%p, arguments); }", (void *)_blockObject);
66+
NSAssert(m_block, @"Block for callback cannot be NULL!");
67+
GADebugStr(@"ScriptBlockObject: function () { GAJavaScript.invocation('%@', arguments); }", m_blockId);
6368

64-
return [NSString stringWithFormat:@"function () { GAJavaScript.invocation(%p, arguments); }", (void *)_blockObject];
69+
return [NSString stringWithFormat:@"function () { GAJavaScript.invocation('%@', arguments); }", m_blockId];
6570
}
6671

6772
@end
6873

69-
#pragma mark GAScriptObject (Blocks)
70-
71-
@implementation GAScriptObject (Blocks)
72-
73-
- (void)setFunctionForKey:(NSString *)key withBlock:(void(^)(NSArray* arguments))block
74-
{
75-
GAScriptBlockObject* myBlock = [[GAScriptBlockObject alloc] initWithBlock:block];
76-
77-
[self setValue:myBlock forKey:key];
78-
79-
// Save the block object so that we can keep the block alive while this object is used.
80-
// The block might be stack-based, which would likely go out-of-scope before the callback
81-
// is received.
82-
//
83-
if (m_blocks == nil)
84-
m_blocks = [[NSMutableSet alloc] initWithCapacity:4];
85-
86-
[m_blocks addObject:myBlock];
87-
[myBlock release];
88-
}
89-
90-
@end

Classes/GAScriptEngine.h

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2011 Andrew Goodale. All rights reserved.
2+
Copyright (c) 2011-2012 Andrew Goodale. All rights reserved.
33
44
Redistribution and use in source and binary forms, with or without modification, are
55
permitted provided that the following conditions are met:
@@ -28,6 +28,8 @@
2828

2929
#import <UIKit/UIKit.h>
3030

31+
static NSString* const GAJavaScriptErrorDomain;
32+
3133
@class GAScriptObject;
3234

3335
/**
@@ -39,11 +41,11 @@
3941
@private
4042
UIWebView* m_webView;
4143
id<UIWebViewDelegate> m_delegate;
42-
43-
GAScriptObject* m_document;
44-
GAScriptObject* m_window;
45-
44+
4645
NSMutableArray* m_receivers;
46+
47+
/* A dictionary of NSString->Block */
48+
NSMutableDictionary* m_blocks;
4749
}
4850

4951
/**
@@ -52,19 +54,14 @@
5254
@property (nonatomic, readonly) UIWebView* webView;
5355

5456
/**
55-
* A reference to the "document" object for this UIWebView.
57+
* An array of objects that take callbacks from JavaScript code.
5658
*/
57-
@property (nonatomic, readonly) GAScriptObject* documentObject;
59+
@property (nonatomic, retain) NSMutableArray* receivers;
5860

5961
/**
60-
* A reference to the "window" object for thi UIWebView.
62+
* Access the script engine attached to the given view
6163
*/
62-
@property (nonatomic, readonly) GAScriptObject* windowObject;
63-
64-
/**
65-
* An array of objects that take callbacks from JavaScript code.
66-
*/
67-
@property (nonatomic, retain) NSMutableArray* receivers;
64+
+ (GAScriptEngine *)scriptEngineForView:(UIWebView *)webView;
6865

6966
/**
7067
* The designated initializer.
@@ -79,7 +76,7 @@
7976
- (id)initWithSuperview:(UIView *)superview delegate:(id<UIWebViewDelegate>)delegate;
8077

8178
/*
82-
* Creates a new (empty) object
79+
* Creates a new Object instance.
8380
*/
8481
- (GAScriptObject *)newScriptObject;
8582

@@ -90,7 +87,7 @@
9087

9188
/*
9289
* Returns a script object bound to the given reference. The script object will have
93-
* a "weak" reference to the JavaScript object
90+
* a "weak" reference to the JavaScript object (i.e. it won't prevent the object from being collected).
9491
*/
9592
- (GAScriptObject *)scriptObjectWithReference:(NSString *)reference;
9693

@@ -104,4 +101,14 @@
104101
*/
105102
- (id)callFunction:(NSString *)functionName withObject:(id)argument;
106103

104+
/*
105+
* Call a function at global scope with multiple arguments.
106+
*/
107+
- (id)callFunction:(NSString *)functionName withArguments:(NSArray *)arguments;
108+
109+
/*
110+
* Generic evaluation of script
111+
*/
112+
- (id)evalWithFormat:(NSString *)script, ...;
113+
107114
@end

0 commit comments

Comments
 (0)