Strange AppleScript declare error

  1. 2 months ago

    Thomas E

    Jul 5 Pre-Release Testers

    Currently I review some older projects to get them running on 64-bit.
    Now I have a strange error and no idea what's wrong.

    I call AppleScript (Xojo 2019r1.1 on macOS 10.14.15) via declares (as shown in Proper way to execute an AppleScript? .
    It worked fine in past but now I get a strange error.
    Simplified example:
    In a push button's action event paste following code

    Soft Declare Function NSClassFromString Lib "Cocoa" (classname As CFStringRef) As ptr
    Soft Declare Function initWithSource Lib "Cocoa" selector "initWithSource:" (obj As ptr,source As CFStringRef) As ptr
    Soft Declare Function executeAndReturnError Lib "Cocoa" selector "executeAndReturnError:" (obj As ptr,ByRef error As ptr) As ptr
    
    Dim theScript As String =  "tell application ""Finder"" to close window ""test"""
    Dim ASClass  As Ptr = NSClassFromString("NSAppleScript")
    Dim scr As ptr
    Try
      scr = initWithSource(ASClass,theScript)
    Catch e As RuntimeException
      System.Log System.LogLevelError, "Got an Exception " + Str(e.ErrorNumber)
      System.Log System.LogLevelError, e.Message
      Return
    End
    
    Dim err As ptr
    Dim descriptor As ptr = executeAndReturnError(scr, err)
    If descriptor = Nil Then
      Dim e As RuntimeException
      e.Message = "Can't execute AppleScript!"
    End If  

    Now open a Window "test" in Finder and run the application. The window should be closed.

    I get an exception

    +[NSAppleScript initWithSource:]: unrecognized selector sent to class 0xa8539240

    I have no idea what's wrong here because it worked well in past.
    Any clues?

    initWithSource: is an instance constructor: You cannot call it on the class but on an allocated instance of it.
    Your code is missing the alloc(Classptr) method that was included in the original you linked.

  2. Ulrich B

    Jul 5 Pre-Release Testers, Xojo Pro Answer Europe (Germany, Berlin) · xo...

    initWithSource: is an instance constructor: You cannot call it on the class but on an allocated instance of it.
    Your code is missing the alloc(Classptr) method that was included in the original you linked.

  3. Thomas E

    Jul 5 Pre-Release Testers

    Thanks. You're right.
    I did not look and thought that an init… must be a class method.
    A typical "This can't be wrong" error ;-)

  4. Ulrich B

    Jul 5 Pre-Release Testers, Xojo Pro Europe (Germany, Berlin) · xo...
    Edited 2 months ago

    :D
    You’re welcome.

    It is exactly the other way:
    If you encounter any ObjectiveC constructor that has the class it is name – in this case, if it would exist, it were appleScriptWithSource: –, then you could be quite sure to have a class constructor.
    Another indicator would be the (+) sign in Apple’s ObjC documentation.

  5. Sam R

    Jul 5 Pre-Release Testers, Xojo Pro, Third Party Store Hengchun, Pingtung, Taiwan

    If I may just expand on this to emphasize something. Whenever you copy and paste Objective-C declares you should follow this rule.

    If the code includes a "init" & "alloc" pair, you are responsible for releasing this object when you're done with it. Failure do so will result in memory leaks. So check and make sure that there is a "release" at or near the end.

    On the other hand; if the code uses a class constructor as illustrated by @Ulrich B, you should call "retain" on the object notifying the system that it should keep this object in scope, then followed by "release" when you're done. Failure to "retain" an object means the OS will release it at the end of the current cycle, failure to release it will lead to a memory leak.

    Don't call "retain" on an object that's created via "init" & "alloc", otherwise you'll need to call release at least twice. Once an object has been released, trying to access it will lead to a crash.

  6. jim m

    Jul 5 Pre-Release Testers, Xojo Pro piDog.com

    @Sam R Whenever you copy and paste Objective-C declares you should follow this rule.

    Also be sure to read the whole conversation, as issues like these tend to get worked out into a more fully fledged example.
    See Joe Ranieri's version of the code. It handles autorelease and errors properly.

or Sign Up to reply!