Forum Archive

App crashes on a long running button action

ZinoSama

I tried debug this code, and it worked correctly, but after I running this one, the whole app crushed.

def start(sender):
    def ani_pause():
        sender.image = ui.Image.named('iob:pause_32')

    def ani_play():
        sender.image = ui.Image.named('iob:play_32')

    global is_playing

    if is_playing is False:
        ui.animate(ani_pause)
        is_playing = True
        start_time = time.time()
        label = sender.superview['label1']
        label2 = sender.superview['label2']
        time_left = 0
        while int(label.text) != 131:
            time.sleep(0.01)
            time_now = time.time()
            duration = time_now - start_time
            time_left += 1
            label2.text = str(10 - time_left)
            if label2.text is '0':
                label.text = str(int(label.text) + 1)
                time_left = 361
        ui.animate(ani_play)
        is_playing = False
    else:
        is_playing = False
        ui.animate(ani_play)
ZinoSama

it seems like I can’t put a whole loop into button action, but I want to do a counter by time function.

cvp

@ZinoSama said

if label2.text is '0':

Please read this

Python is operator compares two variables and returns True if they reference the same object.
If the two variables reference different objects, the is operator returns False .
In other words, the is operator compares the identity of two variables and returns True if they reference the same object.

Thus, your if is always False, thus infinite loop. Use

if label2.text == '0':

But, anyway, your code is still an infinite loop. Is that normal that you test versus 131 and set 361?
Please put some prints to debug your problem and follow the values of your variables, like

  label2.text = str(10 - time_left)
  print(time_left, label2.text)
  if label2.text == '0':
ZinoSama

@cvp the 361 one is the value I forget to change for testing.
I wrote a simple while loop to test button action. The result is the label will only show 10 after 10 seconds, but not get from 1 to 10 by each second. it just didn't show 1 to 9

def start2(sender):
    label = sender.superview['label1']
    num = 0
    while num != 10:
        time.sleep(1)
        num += 1
        label.text = str(num)
JonB

Button actions stop the entire display thread until the function exits, unless you use @in_background

Solution:. Wrap your function with the in_background decorator. Note however that only one in_background gets executed at a time, in order.

ccc

+1 @JonB Ideally, actions should be super simple and run quickly. Move complexity to other parts of your code.

http://omz-software.com/pythonista/docs/ios/ui.html#about-actions-and-delegates

mikael

@ZinoSama, if you want to do a lot of little animations, you could take a look at scripter (blows dust off the link). With it, you can have several simultaneous and long-running animations without having to worry about the UI thread.

An example of a button click handler running a counter to 100:

@script
def start(sender):
    label = sender.superview["label1"]
    set_value(label, "text", range(1, 101), lambda count: f"Count: {count}")