ios - schermo - restrizioni localizzazione iphone




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

È 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.

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 ?



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