How to stop handler from button

I’m new to xcode and asobj… how can I pause or stop a looping handler from one button that is called from another button? The looping handler freezes the gui so that a stop button cannot be pushed. And if that isn’t enough to ask, how would a stop button go about pausing or stopping a looping handler? Thank you very much for any direction (I’ve scoured the web and tried everything).

ASObjC projects in Xcode are no different than any other language Xcode projects, in that in order to carry out intensive operations while keeping the UI responsive, you have to run the intensive operations in the background, while keeping the main thread and run loop for the UI responses.

From memory I don’t believe you can use the “NSThread” class from AppleScript or ASObjC, but I could be mistaken on that as it’s been a while since I used background tasks with AppleScript.
But the last time I did background tasks in an ASObjC project, I used the “NSObject” class’s performSelectorInBackground:withObject: function.

So you could do something like this.


property repeatStopped : false

on applicationDidFinishLaunching:notification
	my performSelectorInBackground:("repeatFunction") withObject:(missing value)
end applicationDidFinishLaunching:

on repeatFunction()
	repeat until my repeatStopped
		log "repeating"
	end repeat
end repeatFunction

And you would stop the repeat loop within the “repeatFunction” method by setting the “repeatStopped” property too true.

Something like this.


-- link this stopRepeat function to an NSButton's action method in Interface Builder.

on stopRepeat:sender
	set my repeatStopped to true
end stopRepeat:

I believe the “NSObject” class performSelectorInBackground:withObject: function, calls the “NSThread” class detachNewThreadSelector:toTarget:withObject: function.
But I don’t think you can call “NSThread” class functions directly, but I could be mistaken on that, as it’s been a while for me with these methods.

Also please be aware, that without knowing what version of MacOS you’re running, some of these old “NSObject” class functions may not work at all on the newer MacOS’s.

I only tested this on “Mojave”, but on newer MacOS’s these techniques may not work.
I made a very simple basic ASObjC project in Xcode with a start and stop button, and a spinning progress wheel to indicate if the repeat loop is running or stopped.
I can post the code if you’re interested.

Hope you find this helpful.

Regards Mark

Woo hoo! Thank you Mark FX. I can’t tell you how beautiful this solution is to me :). Worked like a charm. Can’t thank you enough. Have a great day!

I strongly recommend not putting ASObjC code on background threads like that.

The problem is that there’s only one instance of AppleScript to run code, and it runs it on a last-in, first-served basis. That means if you have code that is running on one thread and you call code on another, the first code is effectively paused until the latter is done (or some other code is called). The result is that you lose control of the order in which code is executed.

You may not see it in simple projects, and it may only be intermittent because of timing issues, but it’s a ticking time bomb.

The better solution is this:

https://macscripter.net/viewtopic.php?id=47084

Thank you Shane. I appreciate it.

My posting should have come with a word of warning.

AppleScript is NOT a multithreading programming language, it’s a single threaded scripting language. And as Shane has posted out, AppleScript can only have a single instance, meaning different sets of AppleScript code can NOT run simultaneously, AppleScript can only run one line of code at a time.
Unlike proper multithreading programming languages like ObjectiveC or Swift.

My posting was a bit of a cheat to allow your UI to remain responsive while running code in the background, and does not represent a true code multithreading solution for AppleScript, because AppleScript cannot ever be multithreading.

it’s important to make sure you stop the background code from running, before you try to run another bunch of code, as the background code will block any other code from running, or the other code will block the background code from running.
So if you’re using my above posted code, always check if the background code is still running, before trying to launch other code, maybe by checking the “repeatStopped” property value is true.

Shane’s linked solution also does not represent true multithreading, but does give you more control over which code has priority in running, so gives you more control over which code runs and in which order.
only use my solution if you’re using it ONLY to allow a responsive UI, and making sure you stop the background code before proceeding with other code execution, maybe launched from the user clicking a UI element.

Hope that makes things more clear.

Regards Mark

Thanks Mark and Shane. Seeing the two approaches gives me a better idea of what I’m dealing with.

Thanks for taking the time to help me.