first of all, using Cocoa Grand Central Dispatch (GCD) is the better choice to perform asynchronous tasks.
The block ^{} is executed asynchronously, you can store the result into a property or instance variable
or call a handler / method as a callback. The handler can also be implemented by using ASOC code on the AppleScript side
Ironically, the cocoa stuff is the stuff I actually had working!
I’m looking at chapter “From Shell Script to Task” of the book, as it appears to be the most relevant. The issue I’m having is that I can’t seem to start to understand how I would mould that around the
set myThread to NSThread's detachNewThreadSelector_toTarget_withObject_("isInternetAvail:", current application's networkTest, missing value)
The nature of asynchronous tasks is to do several things (apparently) at the same time.
Therefore the detachNewThreadSelector method cannot return anything directly because the main “timeline” moves on instantly.
Asynchronous tasks usually return their result in a callback or delegate method
- (void)didCheckInternetConnection:(BOOL)isUP
{
id ASOCClass = NSClassFromString(@"nameOfASOCClass"); // change nameOfASOCClass to the appropriate name
[ASOCClass didCheckInternetConnection:@(isUP)];
}
the name of the Cocoa method and the delegate method can be different
in the ASOC class implement
property myAppleScriptProperty : false
on didCheckInternetConnection_(isUP)
set my myAppleScriptProperty to isUP as boolean
end didCheckInternetConnection_
Righty, I’ve resolved some of the issues but it’s still erring…
-- AppDelegate.applescript
property NSThread : class "NSThread"
property ConnectivityMethods : class "ConnectivityMethods"
property myAppleScriptProperty : false
script AppDelegate
property parent : class "NSObject"
property myAppleScriptProperty : false
on dintConn_(isUP)
set my myAppleScriptProperty to isUP as boolean
log "Yo!" & my myAppleScriptProperty
end dintConn_
on applicationWillFinishLaunching_(aNotification)
end applicationWillFinishLaunching_
on testConn_(sender)
log "Here"
set myString to current application's NSString's stringWithString_("www.google.com")
set myThread to NSThread's detachNewThreadSelector_toTarget_withObject_("hostIsReachable:", current application's ConnectivityMethods, myString)
log "returned"
end testConn_
on applicationShouldTerminate_(sender)
return current application's NSTerminateNow
end applicationShouldTerminate_
end script
I created a simple test project.
Indeed the compiler complains if the method name is used twice.
The reason is the NSObject category which is needed as an interface declaration of the delegate method
Thanks StefanK for this simple project, very useful
I have been playing with this and noticed two puzzling things, probably touching the limits of ASOC :
Your code sets the myAppleScriptProperty boolean value as confirmed by the log following immediately but somehow it seems to only change it on an instance of the script and does not modify the AppDelegate property. If you add a simple button in the interface and link it to a handler to simply log the value of that property it is still unchanged (It will report myAppleScriptProperty as false even tho you are connected and your callback to applescript just logged a true…)
When inside the called back applescript handler (didCheckInternetConnection_) it seems we have a limited scope as we can do certain things, like set variables or call more handlers but a simple cocoa method like NSTextfield setStringValue_ will report as error -10000, unrecognized function.
I am looking at this sample project also. StefanK might have something else in mind for his demo than what you wanted.
I see the same thing @mikaelectron mentions- the Cocoa class does a call back on the ASOC class not instance, effectively not really returning the value. Though that construct is nice, I don’t see it’s usefulness with respect to this project. If one were to make a project where the ASOC object only handled secondary functions, that might be pertinent. But since the ASOC object is the app delegate, you’d probably want that value returned.
Secondly, wrapping the main body of hostIsReachable in an async call is usually good form, it does actually preclude proper return value from being returned (when I was working with the code). In most cases, I would want to check for network reachability before presenting some other alert to the user, or proceeding with the function.
Here’s some changes I made (I added a button also):
script AppDelegate
property parent : class "NSObject"
property ConnectivityMethods : class "ConnectivityMethods"
property myAppleScriptProperty : false
property myButton : missing value
on applicationWillFinishLaunching_(aNotification)
set my myAppleScriptProperty to (ConnectivityMethods's hostIsReachable_("www.google.com") as boolean)
end applicationWillFinishLaunching_
on applicationShouldTerminate_(sender)
-- Insert code here to do any housekeeping before your application quits
return current application's NSTerminateNow
end applicationShouldTerminate_
on pushButton_(sender)
tell me to log "current value= " & my myAppleScriptProperty
end
end script
yes, your code will work and set the property fine.
I was interested in this “call back from cocoa” to AS delegate for another purpose (using GCDAsyncSocket) and since it uses another method that will return the result and not the one originally called by the AS I cannot use return to directly get the output.
I found another way around for the moment using UserDefaults but was wondering about this class / instance issue and if there was any possible fix or solution.