ios - schermo - restrizioni localizzazione iphone




Come si attiva un blocco dopo un ritardo, come-performSelector: withObject: afterDelay:? (12)

C'è un modo per chiamare un blocco con un parametro primitivo dopo un ritardo, come usare performSelector:withObject:afterDelay: ma con un argomento come int / double / float ?


È possibile avvolgere l'argomento nella propria classe o racchiudere la chiamata del metodo in un metodo che non deve essere passato nel tipo primitivo. Quindi chiama quel metodo dopo il tuo ritardo, e all'interno di quel metodo esegui il selettore che desideri eseguire.



Credo che l'autore non stia chiedendo come aspettare un tempo (ritardo) frazionario, ma invece come passare uno scalare come argomento del selettore (withObject :) e il modo più veloce nell'obiettivo C moderno è:

[obj performSelector:...  withObject:@(0.123123123) afterDelay:10]

il tuo selettore deve cambiare i suoi parametri in NSNumber e recuperare il valore usando un selettore come floatValue o doubleValue


Ecco come attivare un blocco dopo un ritardo in Swift:

runThisAfterDelay(seconds: 2) { () -> () in
    print("Prints this 2 seconds later in main queue")
}

/// EZSwiftExtensions
func runThisAfterDelay(seconds seconds: Double, after: () -> ()) {
    let time = dispatch_time(DISPATCH_TIME_NOW, Int64(seconds * Double(NSEC_PER_SEC)))
    dispatch_after(time, dispatch_get_main_queue(), after)
}

È incluso come funzione standard nel mio repository .


Ecco il modo Swift 3 per accodare il lavoro dopo un ritardo.

DispatchQueue.main.asyncAfter(
  DispatchTime.now() + DispatchTimeInterval.seconds(2)) {
    // do work
}

Ecco un utile aiuto per evitare di ripetere la fastidiosa chiamata GCD :

public func delay(bySeconds seconds: Double, dispatchLevel: DispatchLevel = .main, closure: @escaping () -> Void) {
    let dispatchTime = DispatchTime.now() + seconds
    dispatchLevel.dispatchQueue.asyncAfter(deadline: dispatchTime, execute: closure)
}

public enum DispatchLevel {
    case main, userInteractive, userInitiated, utility, background
    var dispatchQueue: DispatchQueue {
        switch self {
        case .main:                 return DispatchQueue.main
        case .userInteractive:      return DispatchQueue.global(qos: .userInteractive)
        case .userInitiated:        return DispatchQueue.global(qos: .userInitiated)
        case .utility:              return DispatchQueue.global(qos: .utility)
        case .background:           return DispatchQueue.global(qos: .background)
        }
    }
}

Ora si ritarda semplicemente il codice sul thread principale in questo modo:

delay(bySeconds: 1.5) { 
    // delayed code
}

Se si desidera ritardare il codice su thread diversi :

delay(bySeconds: 1.5, dispatchLevel: .background) { 
    // delayed code that will run on background thread
}

Se preferisci un Framework che abbia anche alcune funzionalità a portata di mano, controlla HandySwift . Puoi aggiungerlo al tuo progetto tramite Carthage, quindi utilizzarlo esattamente come negli esempi sopra:

import HandySwift    

delay(bySeconds: 1.5) { 
    // delayed code
}

Forse più semplice che passare attraverso GCD, in una classe da qualche parte (es. "Util") o una categoria su oggetto:

+ (void)runBlock:(void (^)())block
{
    block();
}
+ (void)runAfterDelay:(CGFloat)delay block:(void (^)())block 
{
    void (^block_)() = [[block copy] autorelease];
    [self performSelector:@selector(runBlock:) withObject:block_ afterDelay:delay];
}

Quindi per usare:

[Util runAfterDelay:2 block:^{
    NSLog(@"two seconds later!");
}];

In swift 3, possiamo semplicemente usare la funzione DispatchQueue.main.asyncAfter per attivare qualsiasi funzione o azione dopo il ritardo di "n" secondi. Qui nel codice abbiamo impostato il ritardo dopo 1 secondo. Si chiama qualsiasi funzione all'interno del corpo di questa funzione che si attiverà dopo il ritardo di 1 secondo.

let when = DispatchTime.now() + 1
DispatchQueue.main.asyncAfter(deadline: when) {

    // Trigger the function/action after the delay of 1Sec

}

Penso che stiate cercando dispatch_after() . Richiede che il blocco non accetti parametri, ma puoi semplicemente lasciare che il blocco acquisisca quelle variabili dall'ambito locale.

int parameter1 = 12;
float parameter2 = 144.1;

// Delay execution of my block for 10 seconds.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
    NSLog(@"parameter1: %d parameter2: %f", parameter1, parameter2);
});

Altro: https://developer.apple.com/documentation/dispatch/1452876-dispatch_after


Per Swift ho creato una funzione globale, niente di speciale, usando il metodo dispatch_after . Mi piace più perché è leggibile e facile da usare:

func performBlock(block:() -> Void, afterDelay delay:NSTimeInterval){
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), block)
}

Che puoi usare come segue:

performBlock({ () -> Void in
    // Perform actions
}, afterDelay: 0.3)

Puoi utilizzare dispatch_after per chiamare un blocco in un secondo momento. In Xcode, inizia a digitare dispatch_after e premi Enter per completare automaticamente al seguente:

Ecco un esempio con due float come "argomenti". Non è necessario fare affidamento su alcun tipo di macro e l'intento del codice è abbastanza chiaro:

Swift 3, Swift 4

let time1 = 8.23
let time2 = 3.42

// Delay 2 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
    print("Sum of times: \(time1 + time2)")
}

Swift 2

let time1 = 8.23
let time2 = 3.42

// Delay 2 seconds
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2.0 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) { () -> Void in
        println("Sum of times: \(time1 + time2)")
}

Obiettivo C

CGFloat time1 = 3.49;
CGFloat time2 = 8.13;

// Delay 2 seconds
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    CGFloat newTime = time1 + time2;
    NSLog(@"New time: %f", newTime);
});

Swift 3 e Xcode 8.3.2

Questo codice ti aiuterà, aggiungo anche una spiegazione

// Create custom class, this will make your life easier
class CustomDelay {

    static let cd = CustomDelay()

    // This is your custom delay function
    func runAfterDelay(_ delay:Double, closure:@escaping ()->()) {
        let when = DispatchTime.now() + delay
        DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
    }
}


// here how to use it (Example 1)
class YourViewController: UIViewController {

    // example delay time 2 second
    let delayTime = 2.0

    override func viewDidLoad() {
        super.viewDidLoad()

        CustomDelay.cd.runAfterDelay(delayTime) {
            // This func will run after 2 second
            // Update your UI here, u don't need to worry to bring this to the main thread because your CustomDelay already make this to main thread automatically :)
            self.runFunc()
        }
    }

    // example function 1
    func runFunc() {
        // do your method 1 here
    }
}

// here how to use it (Example 2)
class YourSecondViewController: UIViewController {

    // let say you want to user run function shoot after 3 second they tap a button

    // Create a button (This is programatically, you can create with storyboard too)
    let shootButton: UIButton = {
        let button = UIButton(type: .system)
        button.frame = CGRect(x: 15, y: 15, width: 40, height: 40) // Customize where do you want to put your button inside your ui
        button.setTitle("Shoot", for: .normal)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        // create an action selector when user tap shoot button
        shootButton.addTarget(self, action: #selector(shoot), for: .touchUpInside)   
    }

    // example shoot function
    func shoot() {
        // example delay time 3 second then shoot
        let delayTime = 3.0

        // delay a shoot after 3 second
        CustomDelay.cd.runAfterDelay(delayTime) {
            // your shoot method here
            // Update your UI here, u don't need to worry to bring this to the main thread because your CustomDelay already make this to main thread automatically :)
        }
    }   
}




objective-c-blocks