Closed MForever78 closed 9 years ago
There's no good way to do async stuff in coscript right now.
You should be able to create a modal window (perhaps with a cancel button to abort the network request, and maybe even a progress bar if you're really fancy) and then tell NSApp to "runModalForWindow" on it.
You need to put the NSURLConnection
in NSModalPanelRunLoopMode
mode or it won't work.
You can create a window with:
var window = [[NSWindow alloc] init]
[window setTitle:"Loading..."]
[window setFrame:NSMakeRect(0, 0, 290, 86) display:false]
And add some text to it:
var promptField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)]
[promptField setEditable:false]
[promptField setBordered:false]
[promptField setDrawsBackground:false]
[promptField setStringValue:"Please Wait"]
[promptField sizeToFit]
[promptField setFrame:NSMakeRect(20, 23, [promptField frame].size.width, [promptField frame].size.height)]
[[window contentView] addSubview:promptField]
Then fire off your NSURLConnection using something like:
var conn = [[NSURLConnection alloc] initWithRequest:requst delegate:self startImmediately:false]
[conn scheduleRunLoop:[NSRunLoop currentLoop] forMode:"NSModalPanelRunLoopMode"]
[conn start]
And finally go modal:
[NSApp runModalForWindow:window]
When the URL connection receives a response, you need to do:
[window orderOut:nil]
[NSApp stopModal]
(note: according to a stack overflow post from 4 years ago it's necessary to use abortModal
instead of stopModal
when you're working with NSURLConnection. That sounds like a bug to me, maybe it's fixed now)
@abhibeckert Thanks for the reply.
The problem is, although I can send a request and delegate it, I can't handle it afterward. That's because I didn't find a way to do something like:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Append the new data to receivedData.
// receivedData is an instance variable declared elsewhere.
[receivedData appendData:data];
}
I have spending the whole day to do this. I'm developing a sketch plugin that require a network request, and sync request is unaffordable. I'm even considering writing an Objective-C framework and let my plugin load it in the runtime. That's really a pain.
I also tried this:
var handler = function(res, data, err) {};
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:handler]
I'm seeing that my server did receive an request, but after this Sketch just broke. I can't figure out whether it's Sketch's fault or cocoascript's or maybe Mocha's...
Disappointed...
@MForever78 I suspect sendAsynchronousRequest:queue:completionHandler:
will not set the mode to "NSModalPanelRunLoopMode" which would explain the issue you're having.
You're going to have to get connection:didRecieveData:
to work.
I had a similar problem where I needed a target/action object for an NSButton (which is inside a modal window). For that I created a "COTarget" class in Objective-C which executes an inline javascript function:
https://gist.github.com/abhibeckert/dbeae1ea7716e2f49506 https://gist.github.com/abhibeckert/66f95f885f11ace75a01
You could create a similar class with delegate methods for NSURLConnectionDelegate
. Put that in a mini framework/bundle and load it up, then at least most of your code can be in CocoaScript.
Alternatively, make it a synchronous request.
@abhibeckert Thanks a lot! I will definitely give it a try.
@abhibeckert
Hello, I have tried the method COTarget
you provided but there may be some problems.
Here is my step:
COTarget
called COSTarget
(https://github.com/ccgus/CocoaScript/blob/master/src/framework/COSTarget.h), so I used the class.I build a simple framework TestFramework
and put a class MyObject
in it. Here is my class structure:
@interface MyObject : NSObject
@property (weak, nonatomic) id target;
@property SEL action;
- (void)test;
@end
@implementation MyObject
- (void)test {
[_target performSelector:_action withObject:nil];
}
@end
Here is my code in CocoaScript
framework('TestFramework');
var ob = [MyObject new];
[ob setCOSJSTargetFunction:function(res) {
log('Selector Valid');
}];
[ob test];
And in result, I didn't get the log information 'Selector Valid' in the Concole
.
Can you help to find the error of my code? Thanks.
you can do an async connection by hacking https://github.com/matt-curtis/MochaJSDelegate to implement a connection's delegates fwiw (altho currently broken in 3.4 bc it requires COScript.currentCOScript().setShouldKeepAround_(true);
Thanks @tarngerine .
Because the method I have found generally doesn't work for me, I choose to create a webview to do the async work on my project.
What I did is write a framework that create the webview and do the async work, and load the framework in the CocoaScript application. This works fine for me. Just comment in case anybody else needs the feature.
I'm closing this issue because the author doesn't seem to add the feature, and I finally find a (hard) way to achieve this.
Hi @MForever78 could you show me your approach? Is is true, that by loading the webview you can stream the value from and to the evaluated javascript (and control the execution) inside the webview from cocoascript?
@diorahman There's a better workaround now. But the idea is the same.
Check out matt-curtis/MochaJSDelegate which saves you from writing Objective-C to create a webview. And matt-curtis/MochaJSWebScriptingObject to expose function to webview. The demo in their README works fine for me.
@dongxinb you can subclass NSButton , then trigger itself。
I want to use
NSURLConnection sendAsynchronousRequest
method, which requires a block as a callback handler. Is there a way CS can do this? Or what is the recommended way to handle async request?Thanks.