NSTimer with anonymous function / block?

前端 未结 9 2298
囚心锁ツ
囚心锁ツ 2020-12-25 10:17

I want to be able to schedule three small events in the future without having to write a function for each. How can I do this using NSTimer? I understand block

相关标签:
9条回答
  • 2020-12-25 10:48

    I've made a Macro that will do this and auto handle dealloc, arc, retain cycles etc. No need to worry about using weak references. It will also always be on main thread

    #define inlineTimer(__interval, __block) {\
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((0.0) * NSEC_PER_SEC)), dispatch_get_main_queue(), (__block));\
    [NSTimer scheduledTimerWithTimeInterval:__interval repeats:YES block:^(NSTimer *__timer) {\
    if (self.window != nil) {\
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((0.0) * NSEC_PER_SEC)), dispatch_get_main_queue(), (__block));\
    } else {\
    [__timer invalidate];\
    }\
    }];\
    }
    

    Example usage:

    __block ticks = 0;
    
    inlineTimer(0.5, ^{
        ticks++;
        self.label.text = [NSString stringWithFormat:@"Ticks: %i", ticks];//strong reference to self and self.label won't cause retain cycle! Wahoo
    });
    

    Note that self.label is not a weak reference, yet this will all be automatically released due to how the macro is structured.

    Naturally this only works w/ UI classes, given that it's checking .window for when it should dealloc.

    0 讨论(0)
  • 2020-12-25 10:52

    Objective-C version of @Peter Peng's answer:

    _actionDelayTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:[NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"Well this is useless.");
    }] selector:@selector(main) userInfo:nil repeats:YES];
    
    0 讨论(0)
  • 2020-12-25 10:55

    A block based timer API exists in Cocoa (as of iOS 10+ / macOS 10.12+) – here's how you can use it from Swift 3 onwards:

    Timer(timeInterval: gameInterval, repeats: false) { _ in
        print("herp derp")
    }
    

    … or in Objective-C:

    [NSTimer scheduledTimerWithTimeInterval:gameInterval repeats:NO block:^(NSTimer *timer) {
        NSLog(@"herp derp");
    }];
    

    As noted in a comment, be careful not to use strong self references inside the block to avoid retain cycles (for more info).

    If you need to target OS versions older than iOS10, macOS 12, tvOS 10, watchOS 3, you should use one of the other solutions.

    0 讨论(0)
  • 2020-12-25 10:56

    As of late 2018, you do it precisely like this:

    Timer.scheduledTimer(withTimeInterval: 0.25, repeats: true) { timer in
      print("no, seriously, this works on iPhone")
    } 
    

    This thanks to @JohnnyC !

    Truly strange!

    0 讨论(0)
  • 2020-12-25 10:57

    You can make use of dispatch_after if you want to achieve something similar to NSTimer and block execution.

    Here is the sample code for the same:

        int64_t delayInSeconds = gameInterval; // Your Game Interval as mentioned above by you
    
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    
            // Update your label here. 
    
        });
    

    Hope this helps.

    0 讨论(0)
  • 2020-12-25 10:58

    I love this hack @Peter-Pang!! BlockOperation is created on the fly, own by the Timer which itself is own by the running queue, and call the main selector on the block to run it.... nice!!!

    Updated for Swift 3

    Timer.scheduledTimer(timeInterval: 1, target: BlockOperation { // ... }, selector: #selector(Operation.main), userInfo: nil, repeats: false)

    0 讨论(0)
提交回复
热议问题