High Sierra NSDictionary woes

Hi All,

This line worked before:

set nsDict to current application's NSDictionary's dictionaryWithObjectsAndKeys_("value1", "key1", theValue, "key2", "value3", "key3", missing value)

But not in High Sierra so tried:

set nsDict to   current application's class "NSDictionary"'s dictionaryWithObjectsAndKeys:{"value1", "key1", theValue, "key2", "value3", "key3", missing value}

both throw error:

+[NSDictionary dictionaryWithObjectsAndKeys:]: second object of each pair must be non-nil. Or, did you forget to nil-terminate your parameter list? (error -10000)

I had to rewire all my NSArrays to use the new parameter method

set argArray to   current application's class "NSArray"'s arrayWithArray:{helperPath, "5F67Hj", encstr,  missing value}

which works but not sure how to redo NSDictionary here. It goes to notification center below.

on sendNotification_dat_tx_nt_d_dct_(aTitle, aSubtitle, aMessage, aActionButtonTitle, aOtherButtonTitle, aDict)
	my logInfo_var_lvl_("Begin Notification send","",1)
	set myNotification to current application's NSUserNotification's alloc()'s init()
	set myNotification's title to aTitle
	set myNotification's subtitle to aSubtitle
	set myNotification's informativeText to (aMessage) as text
	set myNotification's actionButtonTitle to aActionButtonTitle
	set myNotification's otherButtonTitle to aOtherButtonTitle
	set myNotification's soundName to "Boing"
	set myNotification's userInfo to aDict

	current application's NSUserNotificationCenter's defaultUserNotificationCenter's scheduleNotification_(myNotification)
end sendNotification_

Thx, Rob

What you’re looking for is this:

set nsDict to current application's NSDictionary's dictionaryWithObjects:{"value1", theValue, "value3"} forKeys:{"key1", "key2", "key3"}

I’m not sure why you’d use the trailing-nil versions from ASObjC.

But then I’m even more bamboozled as to why you’re not using interleaved syntax :frowning: It’s been around since 10.9…

Thanks Shane,

Of course! Though dictionaryWithObjectsAndKeys is certainly valid in ObjC and did work before. With interleaving you don’t need the nil terminator? I am always a few years behind…

I just never got around to rewriting (interleaving…) some of my old apps, which have worked fine till now. And now that I am using an external editor the interleaving gets translated though not in all cases as with the above line.

Cheers, Rob

Yes, and you should definitely log a bug on the issue, not least because these things often crop up elsewhere too.

I guess my surprise is because it’s something you rarely see in Objective-C code any more – it’s a relic of a time when where there was no alternative.

You still need it. It’s an standard va_list and only a few functions will be handled special by the compiler (stringWithFormat, NSLog, Printf for example).

The difference with High Sierra is your syntax. While with the old syntax you send an va_list with the new syntax you send an array (note the curly braces). I’m not even sure if you can use an va_list with the new ASObjC syntax at all so you should stick with the old syntax.

You’re correct, but it in this case I think the syntax is a red herring (I was referring more to the syntax used in the longer snippet of script Rob posted).

My guess is that the scripting bridge relies on the relevant framework .bridgesupport file to be able to handle any methods using a va_list.

If you look at Foundation.bridgesupport in 10.12, you see this:

In the equivalent in 10.13, the entry has disappeared. My guess is that the scripting bridge relies on those variadic and sentinel attributes.

There are other issues in the new .bridgesupport files, too. AppleScriptObjC doesn’t cope with the new entry for NSRect, and the value for the NSNotFound enum is incorrect.

If anyone finds any others, please log bugs ASAP.

So man BridgeSupport says:

A quick look through Foundation.bridgesupport in 10.13 shows all methods that previously required the sentinel attribute have been removed. Perhaps it was deliberate after all.

Interesting…

Yes my notification handler (with the old syntax ) was from an old utilities script that I hadn’t edited externally like the others. Sorry to bamboozle you Shane!

I also see that AppleScript |size| is still not understood in the Hi Sierra. Of course I didn’t report it either.

Cheers, Rob

I presume you mean when used with NSRects, because they’re being returned as a list ({x, y}, {w, h}}) instead of a record.

You’re correct. Every ObjC method is actually an C-function (C symbols). These symbols are stored in an hash table and when you call an method the symbol is looked up and the right function is called. If the function doesn’t exists you get a nice “Unrecognized selector send to instance” error instead of an BAD_EXEC crash like in C or C++. This is what the ObjC runtime does for you with the cost of a little performance. But I think I don’t tell you anything new here.

When it comes to va_list it’s a different story. va_list is an C macro, that is a set of predefined pre-processor code that will be replaced (similar too the old NSReleasePool) by real code before the code is compiled. Because variable arguments does’t really exists the va_list macro is replaced with an struct that can hold the variable arguments. Therefore methods with variadic arguments are defined in the bridge like C functions so the bridge can handle it.

The sentinel is to indicate which argument is the va_list struct argument starting from back. 0 value is the default meaning the last argument. So when the last argument is an va_list struct then sentinel attribute doesn’t have to be defined.

I think it more an error than deliberate. Maybe there is an bug in the tool that creates the bridge support files because it is so consistent. It doesn’t only affect AppleScriptObjC but also PyObjC and the latter supports variadic arguments.

Could be – however the variadic methods that don’t require a trailing nil are still there.

Ah yes. I saw your post on Hi Sierra bugs yesterday and looked again at console:

{{177.0, 463.0}, {583.0, 382.0}} doesn’t understand the “size” message.

Didn’t connect at first that it wasn’t showing the expected record. Duh.

On another note I am seeing many console messages:

AppleEvents: received mach msg which wasn’t complex type as expected in getMemoryReference.

and it seems to not like “tell application Finder”.

Log "pre finder tell"
        tell application "Finder"
        set diskName to name of startup disk & " (Boot Volume)" as string
Log "post finder tell"

2017-09-30 08:23:37.272120-0400 backupList+[2664:143798] pre finder tell
2017-09-30 08:23:37.294663-0400 backupList+[2664:143798] AppleEvents: received mach msg which wasn’t complex type as expected in getMemoryReference.
2017-09-30 08:23:37.297013-0400 backupList+[2664:143798] post finder tell

Please make up a simple project that produces it, and log a bug with Apple ASAP.

I hit the same bug, sent it off to apple with a sample. Is there a cocoa framework that lets you get information about a volume, i.e. format, volume name?

You can use NSURL:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

set theFolder to POSIX path of (path to desktop)

set theURL to current application's |NSURL|'s fileURLWithPath:theFolder
set {theResult, theValue, theError} to theURL's getResourceValue:(reference) forKey:(current application's NSURLVolumeNameKey) |error|:(reference)

set {theResult, theValue, theError} to theURL's getResourceValue:(reference) forKey:(current application's NSURLVolumeLocalizedFormatDescriptionKey) |error|:(reference)

NSWorkspace also has -getFileSystemInfoForPath:isRemovable:isWritable:isUnmountable:description:type:.