URL Request using StringWithContentsOfURL:encoding:error:

It took me awhile to figure out how to rewrite one of my dusty old call methods to AppleScriptObjC. The parameters and string coercion is a little pickier in AppleScriptObjC than my old call method.

For comparison here is my old Call Method in AppleScript Studio:

        set Download_URL to "http://macosxautomation.com"
	set SaveFilePath to "/downloadtest.html"
	set writetofile to false

		set load_URL to call method "URLWithString:" of class "NSURL" with parameter Download_URL
		-- send URL
			set Download_URL_data to call method "stringWithContentsOfURL:encoding:error:" of class "NSString" with parameters {load_URL, 4, 1}
			get Download_URL_data
		on error EM
			set Download_URL_data to EM
		end try
		if writetofile is true then
			--write to file
			call method "writeToFile:atomically:" of object Download_URL_data with parameters {SaveFilePath, true}
		end if
	end try

		display dialog Download_URL_data
	on error EM
		display dialog EM
	end try

Here is the same operation (without error checking) in AppleScript ObjC:

script DownloadURLExampleAppDelegate
	property parent : class "NSObject"
	property MyEncoding : 4 --code for UTF8
	property MyError : missing value -- had to set this error parameter to 'missing value'. Only way I could get it not to complain in the console
	property MyDownloadURL : "http://www.macosxautomation.com" as string -- just an example URL for testing
	property MyWritetofile : true -- set to true if you wish to download the data
	property MyWritetoFilePath : POSIX path of (path to home folder) & "/MyDownload.html" -- if you MyWritetofile is true, then Save MyDownload to the home folder
	on dURL(MyDownloadURL, MyWritetofile)
		-- convert the DownloadURL to a NSURL string
		tell class "NSURL" of current application
			set myURL to URLWithString_(MyDownloadURL)
		end tell
		-- Download the data (the download will be a data object and will be coersed to an AppleScript String later)
		tell class "NSString" of current application
			set DownloadData to stringWithContentsOfURL_encoding_error_(myURL, MyEncoding, MyError)
		end tell
		if MyWritetofile then -- if write to file is true
			tell DownloadData -- tell the object of DownloadData to save it to a file
				writeToFile_atomically_(MyWritetoFilePath, true)
			end tell
		end if
		set StringData to DownloadData as string -- set the data to an AppleScript String (required if the download data is text)
		display dialog (StringData) -- for testing show what's been downloaded
	end dURL
	on applicationWillFinishLaunching_(aNotification)
		dURL(MyDownloadURL, MyWritetofile) -- you can run this elsewhere, It's easier for me to test nonUI code here
	end applicationWillFinishLaunching_
	on applicationShouldTerminate_(sender)
		-- Insert code here to do any housekeeping before your application quits 
		return current application's NSTerminateNow
	end applicationShouldTerminate_
end script

I’ve included how to write the data to a file as an option in both AppleScript Studio and AppleScriptObjC examples using Objective-C.

In my new applications, I’ve been trying to avoid using do shell script such as this one:

set MyDownloadData to do shell script "curl -m 8 'http://macosxautomation.com'"

cURL and the do shell script is easier. But each time it launches, there is some latency and another process has to be launched each time the do shell script is run. For repetitive task, it’s probably better to use ObjC methods. Side note: If someone has a way to access libcurl using ASOC, I’d like to see your example! cURL/libcurl has many options; I just don’t know how to use libcurl without using the command line.

Hope this helps anyone either converting the old call methods to AppleScriptObjC, or doing a URL Request in the new environment.

Have a look at using curl via an NSTask.

That came to mind after I posted this. Just started working with NSTask now for an embedded media player. Might give it a shot with curl soon.

The only problem with the NSTask, is it still launches another task (curl), would like to talk to libcurl directly.

For large downloads to run in the background, using curl and NSTask is probably the way to go.