How to use NSAutoreleasePool in AppleScriptObjC - macos

I am wondering how to stop another function from a background function.
In addition, I have to drain NSAutoreleasePool, but I don't know how to do it.
I think this app sometimes freeze if I don't release pool.
property i : 0
property myLabel : missing value
on myStartButtonHandler_(sender)
my performSelectorInBackground_withObject_("start", missing value) -- This code prevents "Stop" Button from freezing.
end myStartButtonHandler_
on myStopButtonHandler_(sender)
-- I want to stop start() function and drain AutoreleasePool!
-- I don't want to use "quit me" because I want to stop only start() function.
end myStopButtonHandler_
on start()
repeat
set i to i + 1
myLabel's setIntegerValue_(i)
delay 1
end repeat
end start
You can download source code from here --> https://dl.dropboxusercontent.com/u/97497395/test2.zip
For your information, I am using Xcode 4.6.3.
EDIT
My script has delay 300 command, so I can't stop the function with checking the value of the variable. Sorry.
EDIT
I conceived of an idea to stop the function while delay commands.
on start()
repeat 5 times
if i = 1 then
error -128
else
delay 60
end repeat
end start
on myStopButtonHandler_(sender)
set i to 1
end myStopButtonHandler_
I can stop the function in 60 seconds, but I can't stop it as soon as I push the stop button. So, I am still waiting for your answer.

An easy way to stop the function is to have a variable. Check the value of the variable. If the variable is true for example then you can exit your repeat loop and drain the autorelease pool. I'm running to work now so no time to write code. Good luck.
EDIT: If you use an NSTimer to fire your handler, as opposed to a repeat loop, then you can invalidate the timer to stop it from running the handler. I use this to invalidate a timer because you should always check that the timer is valid before invalidating it... it will crash if you invalidate a non-valid timer.
-(void)deleteMyTimer {
if ([myTimer isValid]) {
[myTimer invalidate]
myTimer = nil;
}
}

Related

Exit infinite loop by quitting application

I have an AppleScript application in which I have a background task running in an infinite loop.
repeat while true
-- do some tasks
delay 0.5
end repeat
When I export and run the application, I am not able to quit it normally, instead I have to use the force quit. How am I able to fix this?
Instead of the infinite loop implement the on idle handler. It allows to consider the quit command.
on idle
-- do some tasks
return 1
end idle
However there is a restriction. The minimum interval is one second.

Can't quit from AppleScript application

I have an endless loop AppleScript application started at login. But there is a problem: I can not quit it unless im using SIGKILL. Is there any way to add some quit handler to it? Or there is better approach to make background process in AppleScript then "repeat - delay - end repeat"?
It doesn't sound like you're using an on idle handler, that's what you want to do.
on run
-- prep code goes here
end run
on idle
-- your code here
display dialog "TEST" giving up after 4
return 10
end idle
The above code will repeat itself every 10 seconds (based on the return value of 10, change as needed). The only other thing to keep in mind is this script needs to be saved as "Stay Open".
Hope this helps

How to delete the dispatched block using GCD

I have this code:
_myQueue = dispatch_queue_create("com.myapp", DISPATCH_QUEUE_SERIAL);
_mainQueue = dispatch_get_main_queue();
and lot of this block that require some seconds (or minutes)
dispatch_async(_myQueue,
^{
if(canRun){
dispatch_async(_mainQueue,^{/* updating interface here */});
// code here
}
});
My app have a "Stop" button to try stopping all job, and the BOOL "canRun" help me to execute all blocks w/o do nothing.....but always I have to wait the completition of each block until the queue come 0.
Is there any way to instantly "clean" the queue istead doing that?
The aim is to stop processes and to start over without closing and reopening the application.
This project works under ARC.
You can cancel them if you take a few extra steps to creat a dispatch_source object and keep a reference to it.
Review this for starters
https://developer.apple.com/library/mac/documentation/Performance/Reference/GCD_libdispatch_Ref/index.html
There are functions to pause, resume and cancel.

MATLAB: flushing event queue with drawnow

The function drawnow
causes figure windows and their children to update, and flushes the system event queue. Any callbacks generated by incoming events (e.g., mouse or key events) are dispatched before drawnow returns.
I have the following script:
clear all;
clc;
t = timer;
set(t, 'Period', 1);
set(t, 'ExecutionMode', 'fixedSpacing');
set(t, 'TimerFcn', #(event, data) disp('Timer rollover!'));
start(t);
while(1)
%# do something interesting
drawnow;
end
With the drawnow in place, the timer event will occur every second. Without it, no callback function occurs because the while loop is "blocking".
My questions:
1) Is there a way to flush the queue without updating figure windows?
2) When we say "flush the event queue", do we mean "execute everything in the event queue", "execute what's next in the queue and drop everything else out of the queue", or something else entirely?
I have multiple callback functions from multiple separate timers happening in the background of my program. Not having one of these callbacks executing is not an option for me. I just wanted to clarify and make sure I'm doing the right thing.
1) Not to my knowledge - at least, I believe the only way to flush the queue is to call drawnow. Depending on what you mean by 'update figure windows', you may be able to prevent drawnow from having an undesirable effect (e.g. by removing data sources before calling drawnow).
2) I can't test this right now, but based on how I've used it before, and the description you gave above, I'm pretty sure it's "execute everything in the queue".
Another thing I'm not sure about is whether you need while 1; drawnow - don't events work as you would expect if you just end the script after start(t)? I thought drawnow was only necessary if you are doing some other stuff e.g. inside the while loop.
If you also place a small pause in the loop, that also frees up some time for the timer. For example pause(0.001). Some examples:
start(t); while(1); end; %No timer events occur
start(t); while(1); pause(0.001); end %Timer events occur
start(t); while(1); drawnow; end %Timer events occur (your original example)
start(t); while(1); pause(0); end %No timer events (just thought I'd check)

What does "DoEvents" do in vb6?

What does "DoEvents" do in vb6 ?
Why do I get the error message "Out of stack space" ? What does it mean ?
DoEvents() allows other Windows messages to be processed.
The reason you get an out of stack space error is probably because DoEvents() is allowing events to occur that call your code again, which again calls DoEvents(), and so on until the stack space, which tracks the return addresses for all these calls, has run out.
In general, I do not recommend using DoEvents() due to problems like these and the fact that it violates the overall event-driven design of Windows.
A slightly different way of looking at DoEvents is that it flushes the events in the event queue. If your sub or function triggers an event, that event handler becomes a sub that is in line to run as soon as your sub/function is finished. DoEvents says to run that event handler sub now, instead of waiting till the end of your sub.
While I agree in spirit with Jonathon about not using DoEvents, I would temper his statement by saying I only recommend using it if you know exactly why, and know all of the repercussions of changing the order of the event queue this way. Most often, DoEvents is indicated when you want to update your screen in some way from within the context of a subroutine, before the subroutine is finished executing.
An example of this is when you are using the ProgressBar control. Suppose you are iterating through several thousand records, and want to provide feedback to the user as to how far along you are by updating a progress bar. You might interrupt your loop every hundred records and change the value on the progressbar control. However (unless you do something about it) you won't see the change on the screen until after the progressbar's change event handler runs, and that handler won't run until your sub is done executing. It will just get put in the event queue. The way to force the change event to run immediately, suspending your sub, is to call DoEvents. This will flush all existing events from the queue--in this case your progressbar's change event--and will update the progressbar control on the screen.
Now, "out of stack space" basically means that you've been caught in an endless loop of function calls. The most basic way to cause that is this:
Public sub MySub()
MySub
End Sub
And then call MySub from somewhere. You'll get an out of stack space error. If you look at the Call Stack, you'll see a very long line of calls to MySub.
A well-known real-world example of this would happen in older versions of VB:
Public Sub TextBoxArray_LostFocus(index as Integer)
If TextBoxArray(index) = "" Then
TextBoxArray(index).SetFocus
MsgBox "Please enter a value"
End If
End Sub
This situation assumes two members of a TextBox control array called TextBoxArray. Now, if the user starts with the first one (index 0) and moves to the second one (index 1) then index 0's LostFocus event will fire. However, VB would also internally set the focus to the index 1 box. Then the code would set the focus back to index 0, firing index 1's LostFocus event! You're caught in a loop. They fixed that in VB5 or 6 by waiting to set the focus until the LostFocus event was done executing.
I would clarify Johnathon's answer in that it pumps that VB message loop and allows the VB Runtime to process windows messages, which is the opposite of Sleep which allows for Windows to process its events (not necessary in the world of Multicore CPUs and true multitasking OS's but when VB6 was written Windows 9x was the dominant OS and a hard loop that only had DoEvents in it would spike the CPU usage to 100%). So seeing things like
While fDoneFile = False
DoEvents
Sleep 55
Wend
was a common pattern throughout the VB6 world.
As stated else where, DoEvents allows other events in your application to fire. Here's an example of how you can use DoEvents without the "Out of stack space" issue. This makes sure you don't run through the code multiple times by using a Boolean to indicate the code is running.
Sub Example()
'Create static variable to indicate the sub is running.
Static isRunning As Boolean
'Exit the sub if isRunning
If isRunning Then Exit Sub
'Indicate sub is running
isRunning = True
'Sub does stuff
DoEvents
'Ends up calling sub again
Example 'Added just to prove via testing.
'Indicate sub is no longer runningrunning
isRunning = False
End Sub

Resources