web-dev-qa-db-ja.com

swift)のforループに遅延を追加します

コーディングの「問題」があります。

2秒ごとに動的に変更したいテキストのラベルがあります。私は次のことをしました:

// WELCOME STRING ARRAY
let welcomeContainer:[String] = ["Welcome","Benvenuti","Bienvenue","Willkommen","üdvözlet","Dobrodošli","добро пожаловать","Witajcie","Bienvenido","Ласкаво просимо","Vitajte","欢迎你来"]

次に、timerwithinterval(この単純なタスクには多すぎるように見えました)を使用するのではなく、delayループ内の関数でforメソッドを試してみました。

func welcomeLabelChange() {
for i in 0..<welcomeContainer.count {
    welcomeLabel.text = welcomeContainer[i]
    delay(delay: 2.0, closure: {})
}

残念ながら、遅延は完全にスキップされています... forループは即座に実行され、配列の最後のテキストのみが表示されます。私は何が間違っているのですか?

私はこれを見つけました OBJ-C回答 、しかしそれは(古い)NSTimer実装を示唆しています。

6
Alex

この関数を使用して、何かを遅らせることもできます

//MARK: Delay func 

func delay(_ delay:Double, closure:@escaping ()->()) {
    DispatchQueue.main.asyncAfter(
        deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure)
}

使用法は:

        delay(2)  //Here you put time you want to delay
{
            //your delayed code
        }

それがあなたを助けることを願っています。

15
0ndre_

それらの変数を定義する

var i = 0
let timer : Timer?

このタイマーを、ロードされたビュー、またはラベルの変更を開始する場所に配置します

   timer =  Timer.scheduledTimer(timeInterval: 2.0, target: self, selector:#selector(YourViewController.changeText), userInfo: nil, repeats: true)

このメソッドを実装します。

func changeText(){
    if i>=welcomeContainer.count {
        i = 0
    }

    welcomeLabel.text = welcomeContainer[i]
    i += 1
}

それを停止したり、ビューコントローラを変更したいときは、呼び出すことを忘れないでください

timer.invalidate()
5
ben

スリープ機能を追加できます

for i in 0..<welcomeContainer.count {
    welcomeLabel.text = welcomeContainer[i]
    sleep(2) // or sleep(UInt32(0.5)) if you need Double
}
2
Booharin

Timerでは、invalidate内のTimerviewDidDisappearを呼び出すように注意する必要があります。そうしないと、ViewControllerを解放できません。

または、GCDディスパッチタイマーを使用することもできます。このタイマーでは、[weak self]パターンを使用して強い参照サイクルを完全に排除します。

@IBOutlet weak var welcomeLabel: UILabel!

var timer: DispatchSourceTimer!

override func viewDidLoad() {
    super.viewDidLoad()

    let welcomeStrings = ["Welcome", "Benvenuti", "Bienvenue", "Willkommen", "üdvözlet", "Dobrodošli", "добро пожаловать", "Witajcie", "Bienvenido", "Ласкаво просимо", "Vitajte", "欢迎你来"]
    var index = welcomeStrings.startIndex
    timer = DispatchSource.makeTimerSource(queue: .main)
    timer.scheduleRepeating(deadline: .now(), interval: .seconds(2))
    timer.setEventHandler { [weak self] in
        self?.welcomeLabel.text = welcomeStrings[index]
        index = index.advanced(by: 1)
        if index == welcomeStrings.endIndex {
            index = welcomeStrings.startIndex // if you really want to stop the timer and not have this repeat, call self?.timer.cancel()
        }
    }
    timer.resume()
}
1
Rob

すべてをインラインに保ちたい場合は、次のようにすることができます。

var loop: ((Int) -> Void)!
loop = { [weak self] count in
  guard count > 0 else { return }
  //Do your stuff
  DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
    loop(count - 1)
  }
}
loop(10) //However many loops you want
1
Cameron Porter

マークされた回答はループの反復を遅らせることはなく、label.textの最後の値だけを取得します。

あなたはこのようにそれを解決することができます:

func showWelcome(_ iteration: Int = 0) {
    let i = iteration>=self.welcomeContainer.count ? 0 : iteration
    let message = self.welcomeContainer[i]
    self.delay(2){
        self.welcomeLabel.text = message
        return self.showWelcome(i + 1)
    }
}

使用法:

    showWelcome()
0
Dewsman