REST API呼び出しに欠かせない部品をアップデートしました。URLキャッシュが効くようになったような気がします。
–> GET method REST API v4.4.1
–> GET method REST API v4.4
–> GET method REST API v4.3
–> GET method REST API v4.1
–> GET method REST API v4
前バージョンではmacOS 10.15上でクラッシュしないかわりにURLキャッシュが効かないという特徴がありました。ただ、edama2さんと協議した結果、macOS 10.15上でクラッシュする原因と考えられていた内容にあまり根拠がないことがわかってきました(人ごとではなく自分のことなのですが)。
可能な範囲でトライアル&エラーで調査を行なったところ、本バージョンのような処理に落ち着きました。AppleScriptからのCocoa利用については明確にドキュメントがAppleから出ているわけではないので、すでに存在するObjective-Cのプログラムの処理を参考にしつつ、Objective-CからAppleScriptへの置き換えが可能かを検討しています。
URLキャッシュについては、(当然のことながら)処理1回目には効きません。なぜか2回目も効きません。3回目とか4回目あたりから効いていることが実感できる感じです(回数ではなく、前回処理時からの経過時間を見ているのかも? GUIアプリケーションに入れて使うと2回目から効いたりします)。URLキャッシュが効いていない場合には1.5秒ぐらい、URLキャッシュが効き出すと0.02秒ぐらいで結果が返ってきています。
macOS 10.13/14/15で検証を行い、繰り返し処理を行ってもクラッシュしないことを確認しています。ただ、動作保証するというレベルではないので(本Blog掲載のScriptすべてそうですが)、問題があったら知らせてください。
ためしに、Xcode上で作成したGUIベースのAppleScriptアプリケーションに本処理を導入したところ、REST APIへの問い合わせがキャッシュされて著しい高速化を実現できました。
AppleScript名:GET method REST API v4.4.2a_wikipedia.scptd |
— Created 2019-05-02 by Takaaki Naganoya — Modified 2020-04-03 by Takaaki Naganoya — 2020 Piyomaru Software use AppleScript version "2.5" use scripting additions use framework "Foundation" use framework "AppKit" property |NSURL| : a reference to current application’s |NSURL| property NSString : a reference to current application’s NSString property NSURLCache : a reference to current application’s NSURLCache property NSURLSession : a reference to current application’s NSURLSession property NSMutableData : a reference to current application’s NSMutableData property NSURLQueryItem : a reference to current application’s NSURLQueryItem property NSOperationQueue : a reference to current application’s NSOperationQueue property NSURLComponents : a reference to current application’s NSURLComponents property NSJSONSerialization : a reference to current application’s NSJSONSerialization property NSMutableDictionary : a reference to current application’s NSMutableDictionary property NSMutableURLRequest : a reference to current application’s NSMutableURLRequest property NSUTF8StringEncoding : a reference to current application’s NSUTF8StringEncoding property NSURLSessionConfiguration : a reference to current application’s NSURLSessionConfiguration property NSURLRequestReturnCacheDataElseLoad : a reference to current application’s NSURLRequestReturnCacheDataElseLoad property retData : missing value property retCode : 0 property retHeaders : 0 property drecF : false property aSession : missing value property aCache : missing value on run set retData to missing value set drecF to false set aSession to missing value set aQueryKeyTitle to "AppleScript" set aRes to getWikiText(aQueryKeyTitle) of me return aRes end run on getWikiText(aQueryKeyTitle) set reqURLStr to "https://en.wikipedia.org/w/api.php" set aRec to {action:"parse", page:aQueryKeyTitle, |prop|:"wikitext", format:"json"} set aURL to retURLwithParams(reqURLStr, aRec) of me set aRes to callRestGETAPIAndParseResults(aURL, 5) of me if aRes = missing value then return false set bRes to (aRes’s valueForKeyPath:"parse.wikitext.*") as string return bRes end getWikiText –GET methodのREST APIを呼ぶ on callRestGETAPIAndParseResults(reqURLStr as string, timeoutSec as integer) set (my retData) to NSMutableData’s alloc()’s init() set (my retCode) to 0 set (my retHeaders) to {} set (my drecF) to false –if my aCache = missing value then set cachePath to (POSIX path of (path to library folder from user domain)) & "/Caches/AppleScriptURLCache" set my aCache to NSURLCache’s alloc()’s initWithMemoryCapacity:512000 diskCapacity:1024 * 1024 * 5 diskPath:cachePath –end if NSURLCache’s setSharedURLCache:(my aCache) set aURL to |NSURL|’s URLWithString:reqURLStr set aRequest to NSMutableURLRequest’s requestWithURL:aURL aRequest’s setHTTPMethod:"GET" aRequest’s setTimeoutInterval:timeoutSec aRequest’s setValue:"gzip" forHTTPHeaderField:"Content-Encoding" aRequest’s setValue:"AppleScript/Cocoa" forHTTPHeaderField:"User-Agent" aRequest’s setValue:"application/json; charset=UTF-8" forHTTPHeaderField:"Content-Type" set aConfig to NSURLSessionConfiguration’s defaultSessionConfiguration() aConfig’s setRequestCachePolicy:(NSURLRequestReturnCacheDataElseLoad) aConfig’s setURLCache:(my aCache) –どちらでも速度差がない set my aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(NSOperationQueue’s mainQueue()) –set my aSession to NSURLSession’s sessionWithConfiguration:aConfig delegate:(me) delegateQueue:(missing value) set aTask to aSession’s dataTaskWithRequest:aRequest aTask’s resume() –Start URL Session repeat (1000 * timeoutSec) times if (my drecF) is not equal to false then exit repeat end if delay "0.001" as real end repeat –delegateの無効化 my aSession’s finishTasksAndInvalidate() set my aSession to missing value return my parseSessionResults() end callRestGETAPIAndParseResults on URLSession:tmpSession dataTask:tmpTask didReceiveData:tmpData (my retData)’s appendData:tmpData end URLSession:dataTask:didReceiveData: on URLSession:tmpSession task:tmpTask didCompleteWithError:tmpError if tmpError = missing value then set (my drecF) to true else error "Donwload Failed" end if end URLSession:task:didCompleteWithError: on parseSessionResults() set resStr to NSString’s alloc()’s initWithData:(my retData) encoding:(NSUTF8StringEncoding) set jsonString to NSString’s stringWithString:(resStr) set jsonData to jsonString’s dataUsingEncoding:(NSUTF8StringEncoding) set aJsonDict to NSJSONSerialization’s JSONObjectWithData:jsonData options:0 |error|:(missing value) return aJsonDict end parseSessionResults on retURLwithParams(aBaseURL, aRec) set aDic to NSMutableDictionary’s dictionaryWithDictionary:aRec set aKeyList to (aDic’s allKeys()) as list set aValList to (aDic’s allValues()) as list set aLen to length of aKeyList set qList to {} repeat with i from 1 to aLen set aName to contents of item i of aKeyList set aVal to contents of item i of aValList set the end of qList to (NSURLQueryItem’s queryItemWithName:aName value:aVal) end repeat set aComp to NSURLComponents’s alloc()’s initWithString:aBaseURL aComp’s setQueryItems:qList set aURL to (aComp’s |URL|()’s absoluteString()) as text return aURL end retURLwithParams |
teratailの指定IDのユーザー情報を取得する_curl – AppleScriptの穴 says:
[…] 的なmacOSのアップデートでNSURLConnectionが使えなくなる日が来るのかもしれませんが、curlコマンドを使うように集約するべきなのか、NSURLSessionで書き換えるべきなのか悩ましいところです。 […]