Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to get data asynchronously and transfer to javascript #41

Closed
chenfengbri opened this issue Jun 5, 2013 · 10 comments
Closed

How to get data asynchronously and transfer to javascript #41

chenfengbri opened this issue Jun 5, 2013 · 10 comments

Comments

@chenfengbri
Copy link

I used AFNetWorking to fetch data from remote service API, when the data ready, I tried to transfer the data back to javascript, but it raise an error. Any advice is appreciate. My code look like this.

^(id data, WVJBResponseCallback responseCallback) {
            NSLog(@"data: %@", data);
            NSString *service = [data objectForKey:@"service"];
            BOOL needLogin = [[data objectForKey:@"needLogin"] boolValue];
            NSDictionary *businessParams = [data objectForKey:@"businessParams"];

            [[AHAPIClient sharedClient] consumeRemoteService:service
                                                   needLogin:needLogin
                                              withParameters:businessParams
                                                     success:^(id JSON) {
                                                         responseCallback(JSON);
                                                     }
                                                     failure:^(NSError *error) {
                                                         responseCallback(error.userInfo);
                                                     }];
}
@marcuswestin
Copy link
Owner

I'll need more info to be able to help. For example, you should always post the error you are getting when asking for help. Please post code which I can easily run, e.g a tar file with an example Xcode project which exhibits the error.

​Cheers,
Marcus 


Sent from Mailbox for iPad

On Tue, Jun 4, 2013 at 10:20 PM, 陈锋 [email protected] wrote:

I used AFNetWorking to fetch data from remote service API, when the data ready, I tried to transfer the data back to javascript, but it raise an error. Any advice is appreciate. My code look like this.

^(id data, WVJBResponseCallback responseCallback) {
            NSLog(@"data: %@", data);
            NSString *service = [data objectForKey:@"service"];
            BOOL needLogin = [[data objectForKey:@"needLogin"] boolValue];
            NSDictionary *businessParams = [data objectForKey:@"businessParams"];

            [[AHAPIClient sharedClient] consumeRemoteService:service
                                                   needLogin:needLogin
                                              withParameters:businessParams
                                                     success:^(id JSON) {
                                                         responseCallback(JSON);
                                                     }
                                                     failure:^(NSError *error) {
                                                         responseCallback(error.userInfo);
                                                     }];
}
---
Reply to this email directly or view it on GitHub:
https://github.com/marcuswestin/WebViewJavascriptBridge/issues/41

@chenfengbri
Copy link
Author

Sorry, here is the exception stack and I already put the demo project at https://github.com/chenfengbri/WVJB_ASYN_DEMO.git

Thanks for your help.

(lldb) bt
* thread #1: tid = 0x1c03, 0x012f509b libobjc.A.dylib`objc_msgSend + 15, stop reason = EXC_BAD_ACCESS (code=2, address=0x8)
    frame #0: 0x012f509b libobjc.A.dylib`objc_msgSend + 15
    frame #1: 0x00e14b82 Foundation`_writeJSONValue + 85
    frame #2: 0x00e19251 Foundation`___writeJSONObject_block_invoke_0 + 272
    frame #3: 0x01dcacdf CoreFoundation`__NSDictionaryEnumerate + 991
    frame #4: 0x01dca87d CoreFoundation`-[NSDictionary enumerateKeysAndObjectsWithOptions:usingBlock:] + 45
    frame #5: 0x01dca7c5 CoreFoundation`-[NSDictionary enumerateKeysAndObjectsUsingBlock:] + 53
    frame #6: 0x00e18e2a Foundation`_writeJSONObject + 458
    frame #7: 0x00e14d5d Foundation`_writeJSONValue + 560
    frame #8: 0x00e14aed Foundation`-[_NSJSONWriter dataWithRootObject:options:error:] + 125
    frame #9: 0x00e17ecc Foundation`+[NSJSONSerialization dataWithJSONObject:options:error:] + 370
    frame #10: 0x00040f21 WVJB_ASYN_DEMO`-[WebViewJavascriptBridgeAbstract(self=0x082a0950, _cmd=0x00045667, message=0x0758e980) _serializeMessage:] + 129 at WebViewJavascriptBridgeAbstract.m:148
    frame #11: 0x0003ffb9 WVJB_ASYN_DEMO`-[WebViewJavascriptBridgeAbstract(self=0x082a0950, _cmd=0x00045477, message=0x0758e980) _dispatchMessage:] + 217 at WebViewJavascriptBridgeAbstract.m:74
    frame #12: 0x0003feda WVJB_ASYN_DEMO`-[WebViewJavascriptBridgeAbstract(self=0x082a0950, _cmd=0x00045658, message=0x0758e980) _queueMessage:] + 154 at WebViewJavascriptBridgeAbstract.m:69
    frame #13: 0x00040d86 WVJB_ASYN_DEMO`__64-[WebViewJavascriptBridgeAbstract(.block_descriptor=0x072a6dc0, responseData=0x072c56f0) _flushMessageQueue]_block_invoke + 230 at WebViewJavascriptBridgeAbstract.m:116
    frame #14: 0x000035db WVJB_ASYN_DEMO`__29-[ViewController viewDidLoad]_block_invoke_3(.block_descriptor=0x080d16b0, operation=0x072c0440, responseObject=0x072c56f0) + 123 at ViewController.m:35
    frame #15: 0x000193d9 WVJB_ASYN_DEMO`__64-[AFJSONRequestOperation setCompletionBlockWithSuccess:failure:]_block_invoke93() + 41 at AFJSONRequestOperation.m:140
    frame #16: 0x017d053f libdispatch.dylib`_dispatch_call_block_and_release + 15
    frame #17: 0x017e2014 libdispatch.dylib`_dispatch_client_callout + 14
    frame #18: 0x017d27d5 libdispatch.dylib`_dispatch_main_queue_callback_4CF + 296
    frame #19: 0x01d83af5 CoreFoundation`__CFRunLoopRun + 1925
    frame #20: 0x01d82f44 CoreFoundation`CFRunLoopRunSpecific + 276
    frame #21: 0x01d82e1b CoreFoundation`CFRunLoopRunInMode + 123
    frame #22: 0x021707e3 GraphicsServices`GSEventRunModal + 88
    frame #23: 0x02170668 GraphicsServices`GSEventRun + 104
    frame #24: 0x00227ffc UIKit`UIApplicationMain + 1211
    frame #25: 0x00002d3d WVJB_ASYN_DEMO`main(argc=1, argv=0xbffff374) + 141 at main.m:16
    frame #26: 0x00002c65 WVJB_ASYN_DEMO`start + 53

@marcuswestin
Copy link
Owner

That's helpful - thanks!

The error appears to happen when attempting to JSON serialize the arguments
you are passing through. Make sure that you are sending serializable
values. Have you tried setting a breakpoint in your success handler and
stepping through the code? My guess is that id JSON is nil or something.
One way to check is to try

[[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject :JSON options:0 error:nil] encoding:NSUTF8StringEncoding]

before calling responseCallback(JSON).

On Wed, Jun 5, 2013 at 1:04 AM, 陈锋 [email protected] wrote:

Sorry, here is the exception stack and I already put the demo project at
https://github.com/chenfengbri/WVJB_ASYN_DEMO.git

Thanks for your help.

(lldb) bt* thread #1: tid = 0x1c03, 0x012f509b libobjc.A.dylibobjc_msgSend + 15, stop reason = EXC_BAD_ACCESS (code=2, address=0x8) frame #0: 0x012f509b libobjc.A.dylibobjc_msgSend + 15
frame #1: 0x00e14b82 Foundation_writeJSONValue + 85 frame #2: 0x00e19251 Foundation___writeJSONObject_block_invoke_0 + 272
frame #3: 0x01dcacdf CoreFoundation__NSDictionaryEnumerate + 991 frame #4: 0x01dca87d CoreFoundation-[NSDictionary enumerateKeysAndObjectsWithOptions:usingBlock:] + 45
frame #5: 0x01dca7c5 CoreFoundation-[NSDictionary enumerateKeysAndObjectsUsingBlock:] + 53 frame #6: 0x00e18e2a Foundation_writeJSONObject + 458
frame #7: 0x00e14d5d Foundation_writeJSONValue + 560 frame #8: 0x00e14aed Foundation-[_NSJSONWriter dataWithRootObject:options:error:] + 125
frame #9: 0x00e17ecc Foundation+[NSJSONSerialization dataWithJSONObject:options:error:] + 370 frame #10: 0x00040f21 WVJB_ASYN_DEMO-[WebViewJavascriptBridgeAbstract(self=0x082a0950, _cmd=0x00045667, message=0x0758e980) _serializeMessage:] + 129 at WebViewJavascriptBridgeAbstract.m:148
frame #11: 0x0003ffb9 WVJB_ASYN_DEMO-[WebViewJavascriptBridgeAbstract(self=0x082a0950, _cmd=0x00045477, message=0x0758e980) _dispatchMessage:] + 217 at WebViewJavascriptBridgeAbstract.m:74 frame #12: 0x0003feda WVJB_ASYN_DEMO-[WebViewJavascriptBridgeAbstract(self=0x082a0950, _cmd=0x00045658, message=0x0758e980) _queueMessage:] + 154 at WebViewJavascriptBridgeAbstract.m:69
frame #13: 0x00040d86 WVJB_ASYN_DEMO__64-[WebViewJavascriptBridgeAbstract(.block_descriptor=0x072a6dc0, responseData=0x072c56f0) _flushMessageQueue]_block_invoke + 230 at WebViewJavascriptBridgeAbstract.m:116 frame #14: 0x000035db WVJB_ASYN_DEMO__29-[ViewController viewDidLoad]_block_invoke_3(.block_descriptor=0x080d16b0, operation=0x072c0440, responseObject=0x072c56f0) + 123 at ViewController.m:**35
frame #15: 0x000193d9 WVJB_ASYN_DEMO__64-[AFJSONRequestOperation setCompletionBlockWithSuccess:failure:]_block_invoke93() + 41 at AFJSONRequestOperation.m:140 frame #16: 0x017d053f libdispatch.dylib_dispatch_call_block_and_release + 15
frame #17: 0x017e2014 libdispatch.dylib_dispatch_client_callout + 14 frame #18: 0x017d27d5 libdispatch.dylib_dispatch_main_queue_callback_4CF + 296
frame #19: 0x01d83af5 CoreFoundation__CFRunLoopRun + 1925 frame #20: 0x01d82f44 CoreFoundationCFRunLoopRunSpecific + 276
frame #21: 0x01d82e1b CoreFoundationCFRunLoopRunInMode + 123 frame #22: 0x021707e3 GraphicsServicesGSEventRunModal + 88
frame #23: 0x02170668 GraphicsServicesGSEventRun + 104 frame #24: 0x00227ffc UIKitUIApplicationMain + 1211
frame #25: 0x00002d3d WVJB_ASYN_DEMOmain(argc=1, argv=0xbffff374) + 141 at main.m:16 frame #26: 0x00002c65 WVJB_ASYN_DEMOstart + 53


Reply to this email directly or view it on GitHubhttps://github.com//issues/41#issuecomment-18961119
.

@chenfengbri
Copy link
Author

I think the error occurs because callbackId is released when I call responseback in the success handler.
When I hard code the callbackId like '123456789' both in the javascript file and WebViewJavascriptBridgeAbstract.m, it worked! The code in file WebViewJavascriptBridgeAbstract.m at line 115

if (callbackId) {
                responseCallback = ^(id responseData) {
                    NSDictionary* message = @{ @"responseId":callbackId, @"responseData":responseData };
                    [self _queueMessage:message];
                };
            } else {

@oakho
Copy link
Collaborator

oakho commented Jun 6, 2013

Hey guys,

It seems there's some issues while calling WWJB responseCallback inside another block (those from AFNetworking in this case)

After some testing on the demo project I managed to make it work by changing the line :

__block NSString* callbackId = message[@"callbackId"];

Into :

NSString* callbackId = message[@"callbackId"];

That being said, I don't really have an understanding of why this fix the problem so I'm gonna dig the subject a little more before making a pull request or something.

Cheers !

@marcuswestin
Copy link
Owner

Thanks Antoine!
-- while mobile

On Thu, Jun 6, 2013 at 5:25 AM, Antoine Lagadec [email protected]
wrote:

Hey guys,
It seems there's some issues while calling WWJB responseCallback inside another block (those from AFNetworking in this case)
After some testing on the demo project I managed to make it work by changing the line :
__block NSString* callbackId = message[@"callbackId"];

Into :
NSString* callbackId = message[@"callbackId"];
That being said, I don't really have an understanding of why this fix the problem so I'm gonna dig the subject a little more before making a pull request or something.

Cheers !

Reply to this email directly or view it on GitHub:
#41 (comment)

@chenfengbri
Copy link
Author

I checked the Apple documentation , maybe this will explain why it work after removing the __block identifier.

__block variables live in storage that is shared between the lexical scope of the variable and all blocks and block copies declared or created within the variable’s lexical scope. Thus, the storage will survive the destruction of the stack frame if any copies of the blocks declared within the frame survive beyond the end of the frame (for example, by being enqueued somewhere for later execution). Multiple blocks in a given lexical scope can simultaneously use a shared variable.

@marcuswestin
Copy link
Owner

Reading the cited documentation, my understanding is that using __block strictly keeps the variable around longer (at least as long as it would have otherwise).

​I don't see how keeping a variable around would cause reference issues.

Now, the cited documentation may not be the whole story, but just looking at that paragraph it seems to me that removing __block should cause issues.

​Antoine, any news from you?

Cheers!
Marcus 

-- while mobile

On Thu, Jun 6, 2013 at 8:28 PM, 陈锋 [email protected] wrote:

I checked the Apple documentation , maybe this will explain why it work after removing the __block identifier.

__block variables live in storage that is shared between the lexical scope of the variable and all blocks and block copies declared or created within the variable’s lexical scope. Thus, the storage will survive the destruction of the stack frame if any copies of the blocks declared within the frame survive beyond the end of the frame (for example, by being enqueued somewhere for later execution). Multiple blocks in a given lexical scope can simultaneously use a shared variable.

Reply to this email directly or view it on GitHub:
#41 (comment)

@marcuswestin
Copy link
Owner

Ah, here's some more color from http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/Blocks/Articles/bxVariables.html:

4. Variables local to the enclosing lexical scope declared with the __block storage modifier are provided by reference and so are mutable.

Any changes are reflected in the enclosing lexical scope, including any other blocks defined within the same enclosing lexical scope. These are discussed in more detail in “The __block Storage Type.”

I think the key here is that it is mutable. How about this theory:

If message gets discarded, it takes the @"callbackId" property with it. Thus referencing the callbackId variable gives a memory access error.

Sooo... Without a __block we get:

3. Stack (non-static) variables local to the enclosing lexical scope are captured as const variables.
Their values are taken at the point of the block expression within the program. In nested blocks, the value is captured from the nearest enclosing scope.

This seems more like what we want - a const variable. Will do a little more digging before committing.

@marcuswestin
Copy link
Owner

It looks like I added the __block reference in 4ab41bb, and I think I had no idea what I was doing. (not that I know what I'm doing these days either, but...)

Making the change. Thanks for the patience @chenfengbri, and detective work @oakho.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants