カテゴリー別アーカイブ: Swift

[Swift]NSNotificationCenterを使ってヘッドフォン抜き差し時のトリガーができたのにbuttonのtitleとかlabelのtextが変わらない時

[Swift]ヘッドフォンを抜き差しするとAVAudioEngineがクラッシュするときの対処方の続き。

「NSNotificationCenterを使ってヘッドフォン抜き差し時のトリガーができたぜ、やったぜ」と思ってたのに、ボタンのタイトルとかラベルのテキストがうまく変わらないじゃないか!

いろいろ調べた結果、dispatch_async(dispatch_get_main_queue())を使ったらなんとかなった。

ダメだったコード


func configChange(notification:NSNotification) {
self.button.setTitle("PLAY", forState: .Normal)
self.labelRate.text = "100%"
}

これだと、ヘッドフォンを抜き差しして10秒くらい待ったら、ボタンタイトル・ラベルテキストが変わるときもある、変わらない時もある。なぜだ!

解決策


func configChange(notification:NSNotification) {
dispatch_async(dispatch_get_main_queue(), {
self.button.setTitle("PLAY", forState: .Normal)
self.label.text = "100%"
})
}

こうしたらできた。

原因

StackOverflowでSwift alternative to performSelectorOnMainThreadとかProblems with NSNotificationCenter and UIPickerViewとか参考にしたところ、

Notificationが送られるThreadが違う

ということらしい。

The issue is likely that the notification is sent (and therefore received) on a different thread than the main thread. Only on the main thread will you be able to update UI elements (like a label).

なるほど、ラベルとかのUI elementの情報をupdateするにはmain thread上でなければならないが、notificationが(私の場合はfunc configChange)、main threadではなく、他のthreadに送られているのだ、ということらしい。

だいたい今のいままで、threadとかいうのが複数あるのも知らんかった。。。

threadの確認

じゃあ、ヘッドフォン抜き差しするときのfunc congigChangeは、どのthreadで行なわれているのよ?と確認してみる。

func configChange(notification:NSNotification) {
println("config change %@", NSThread.currentThread())
}

上記コード書いて、Xcodeに実機繋げてヘッドフォン抜き差ししてみると、thread3とかthread4とかthread5とか、いろんなthreadで動作しているのがわかる。やっぱこれが原因なのね。

main threadで動かすには

dispatch_async(dispatch_get_main_queue(), {})というのを使えばいいらしい。

func configChange(notification:NSNotification) {
dispatch_async(dispatch_get_main_queue(), {
println("config change %@", NSThread.currentThread())
})
}

これで確認してみると、たしかに、ヘッドフォン抜き差しのたびにmain threadで動いていることがわかる。なるほどねー。

なお、かつてはperformSelectorOnMainThreadなるものがあったそうだが、古いから使っちゃダメよとのこと。

ちょっと賢くなった気がする。
以上!

[Swift]ヘッドフォンを抜き差しするとAVAudioEngineがクラッシュするときの対処方

AVAudioEngineを使ってオーディオ再生プレイヤーを作っていたところ、ヘッドフォンやイヤフォンを抜き差しするとアプリがフリーズし、しばらくしたらクラッシュするという現象が発生しました。

こまったときはStackOverflowだということで質問したところ、
AVAudioEngineConfigurationChangeNotificationを使うんだよ、と教えられました。

そういうのってデバイス側でなんか勝手にやってくれると思ってたら、挙動をプログラミングしないといけないのね。。。

初心者の私は、それだけ言われてもよくわかんねーよと思いつつ、せっかくもらったヒントでググりまくりStackOverflowやGithubなどを見まくった結果、以下のとおり解決しました。

・ViewDidLoadの中に以下を書く

NSNotificationCenter.defaultCenter().addObserver(self,
selector:"configChange:", // 動作させたいfunction名
name:AVAudioEngineConfigurationChangeNotification,
object:audioEngin // AVAudioEngineを代入した変数名)


・ViewDidLoadm外に適当に以下を書く

func configChange(notification:NSNotification) {
// ヘッドフォンを抜くor差した時にしたいこと書く
}


なんか正しいのかわかんないながらも、無事フリーズとクラッシュはしなくなりました。
以上。

※万事解決かと思ったら、まだ問題が。。。。
(続き:[Swift]NSNotificationCenterを使ってヘッドフォン抜き差し時のトリガーができたのにbuttonのtitleとかlabelのtextが変わらない時

[Swift]AVAudioEngineを使ってDelayをかける

[Swift]AVAudioEngineを使ってReverbをかける」の続きです。今回は、AVAudioEngineを使って曲にディレイをかけます。主な流れはリバーブのときと同じで、ディレイのNodeを作って、それをAudioEngineへ追加して、Node同士を接続して、という感じです。

なおディレイでは以下4つのプロパティを設定できます。
DelayTime
Feedback
LowPassCutOff
WetDryMix

[Swift]AVAudioEngineを使って曲の再生をする」で作ったものに追記をして進めていますので、ご注意ください。

できるもの

AVAudioEngineを使って曲にディレイをかける。
スクリーンショット 2014-11-19 16.20.43

ソフトのバージョン

OS: OSX Yosemite 10.10.1
Xcode: 6.1

つくりかた

動画でご確認ください。

コード


import UIKit
import AVFoundation

class ViewController: UIViewController {

@IBOutlet weak var buttonPlay: UIButton!
@IBOutlet weak var sliderReverb: UISlider!

@IBOutlet weak var sliderDelayTime: UISlider!
@IBOutlet weak var sliderFeedback: UISlider!
@IBOutlet weak var sliderLowPassCutOff: UISlider!
@IBOutlet weak var sliderWetDryMix: UISlider!

var audioEngine: AVAudioEngine!
var audioFilePlayer: AVAudioPlayerNode!
var audioReverb: AVAudioUnitReverb!
var audioDelay: AVAudioUnitDelay!
var audioFile: AVAudioFile!

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

// AudioEngineの生成
audioEngine = AVAudioEngine()

// AVPlayerNodeの生成
audioFilePlayer = AVAudioPlayerNode()

// AVAudioFileの生成
audioFile = AVAudioFile(forReading: NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("test", ofType: "mp3")!), error: nil)

// ReverbNodeの生成
audioReverb = AVAudioUnitReverb()
audioReverb.loadFactoryPreset(.LargeHall2)
audioReverb.wetDryMix = 0

// DelayNodeの生成
audioDelay = AVAudioUnitDelay()
audioDelay.delayTime = 0
audioDelay.feedback = 50
audioDelay.lowPassCutoff = 15000
audioDelay.wetDryMix = 100

// AVPlayerNodeとReverbNodeとDelayNodeをAVAudioEngineへ追加
audioEngine.attachNode(audioFilePlayer)
audioEngine.attachNode(audioReverb)
audioEngine.attachNode(audioDelay)

// AVPlayerNodeとReverbNodeとDelayNodeをAVAudioEngineへ接続
audioEngine.connect(audioFilePlayer, to: audioReverb, format: audioFile.processingFormat)
audioEngine.connect(audioReverb, to: audioDelay, format: audioFile.processingFormat)
audioEngine.connect(audioDelay, to: audioEngine.mainMixerNode, format: audioFile.processingFormat)

// AVAudioEngineの開始
audioEngine.startAndReturnError(nil)

}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

@IBAction func buttonPlayPressed(sender: UIButton) {
if (audioFilePlayer.playing) {
audioFilePlayer.pause()
buttonPlay.setTitle("PLAY", forState: .Normal)
} else {
audioFilePlayer.scheduleFile(audioFile, atTime: nil, completionHandler: nil)
audioFilePlayer.play()
buttonPlay.setTitle("PAUSE", forState: .Normal)
}
}

@IBAction func sliderReverbChanged(sender: UISlider) {
audioReverb.wetDryMix = sliderReverb.value
}

@IBAction func sliderDelayTimeChanged(sender: UISlider) {
audioDelay.delayTime = NSTimeInterval(sliderDelayTime.value)
}

@IBAction func sliderFeedbackChanged(sender: UISlider) {
audioDelay.feedback = sliderFeedback.value
}

@IBAction func sliderLowPassCutOff(sender: UISlider) {
audioDelay.lowPassCutoff = sliderLowPassCutOff.value
}

@IBAction func sliderWetDryMix(sender: UISlider) {
audioDelay.wetDryMix = sliderWetDryMix.value
}
}


[Swift]AVAudioEngineを使ってReverbをかける

[Swift]AVAudioEngineを使って曲の再生をする」の続きです。今回は、AVAudioEngineを使って曲にリバーブをかけます。主な流れは、リバーブのNodeを作って、それをAudioEngineへ追加して、Node同士を接続して、という感じです。

かけるリバーブは、loadFactoryPresetで、プリセットの中から選ぶことができます。
また、リバーブの強さ?深さ?は、wetDryMixで、0から100の間で設定できます。

[Swift]AVAudioEngineを使って曲の再生をする」で作ったものに追記をして進めていますので、ご注意ください。

(続き:[Swift]AVAudioEngineを使ってDelayをかける

できること

AVAudioEngineを使って曲にリバーブをかけます。
スクリーンショット 2014-11-19 14.15.14

ソフトのバージョン

OS: OSX Yosemite 10.10.1
Xcode: 6.1

つくりかた

動画でご確認ください。

コード


import UIKit
import AVFoundation

class ViewController: UIViewController {

@IBOutlet weak var buttonPlay: UIButton!
@IBOutlet weak var sliderReverb: UISlider!

var audioEngine: AVAudioEngine!
var audioFilePlayer: AVAudioPlayerNode!
var audioReverb: AVAudioUnitReverb!
var audioFile: AVAudioFile!

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

// AudioEngineの生成
audioEngine = AVAudioEngine()

// AVPlayerNodeの生成
audioFilePlayer = AVAudioPlayerNode()

// AVAudioFileの生成
audioFile = AVAudioFile(forReading: NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("test", ofType: "mp3")!), error: nil)

// ReverbNodeの生成
audioReverb = AVAudioUnitReverb()
audioReverb.loadFactoryPreset(.LargeHall2)
audioReverb.wetDryMix = 0

// AVPlayerNodeとReverbNodeをAVAudioEngineへ追加
audioEngine.attachNode(audioFilePlayer)
audioEngine.attachNode(audioReverb)

// AVPlayerNodeとReverbNodeをAVAudioEngineへ接続
audioEngine.connect(audioFilePlayer, to: audioReverb, format: audioFile.processingFormat)
audioEngine.connect(audioReverb, to: audioEngine.mainMixerNode, format: audioFile.processingFormat)

// AVAudioEngineの開始
audioEngine.startAndReturnError(nil)

}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

@IBAction func buttonPlayPressed(sender: UIButton) {
if (audioFilePlayer.playing) {
audioFilePlayer.pause()
buttonPlay.setTitle("PLAY", forState: .Normal)
} else {
audioFilePlayer.scheduleFile(audioFile, atTime: nil, completionHandler: nil)
audioFilePlayer.play()
buttonPlay.setTitle("PAUSE", forState: .Normal)
}
}

@IBAction func sliderReverbChanged(sender: UISlider) {
audioReverb.wetDryMix = sliderReverb.value
}

}

[Swift]AVAudioEngineを使って曲の再生をする

Swiftで、AVAudioEngineを使って曲の再生をしてみましょう。

AVAudioEngineはiOS8で新しく追加された機能だそうで、オーディオ信号を加工(リバーブかけたりピッチや速度変えたり)できます。以前のものよりも比較的簡単にできるのがメリットみたいですよ。

今回は、とりあえず曲を再生するだけ。エフェクトかけたりなどは、以後おいおいやっていければと思います。

なお、AVAudioEngineについて詳しく知りたい方は、ググるといっぱい出てきますので、そちらで。

(続き:[Swift]AVAudioEngineを使ってReverbをかける

できること

AVAudioEngineを使って曲を再生します。

ソフトのバージョン

OS: OSX Yosemite 10.10.1
Xcode: 6.1

つくりかた

動画でご確認ください。

コード


import UIKit
import AVFoundation

class ViewController: UIViewController {

@IBOutlet weak var buttonPlay: UIButton!

var audioEngine: AVAudioEngine!
var audioFilePlayer: AVAudioPlayerNode!
var audioFile: AVAudioFile!

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

// AVAudioEngineの生成
audioEngine = AVAudioEngine()

// AVPlayerNodeの生成
audioFilePlayer = AVAudioPlayerNode()

// AVAudioFileの生成
audioFile = AVAudioFile(forReading: NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("test", ofType: "mp3")!), error: nil)

// AVPlayerNodeをAVAudioEngineへ追加
audioEngine.attachNode(audioFilePlayer)

// AVPlayerNodeをAVAudioEngineへ
audioEngine.connect(audioFilePlayer, to: audioEngine.mainMixerNode, format: audioFile.processingFormat)

// AVAudioEngineの開始
audioEngine.startAndReturnError(nil)
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

@IBAction func buttonPlayPressed(sender: UIButton) {
if (audioFilePlayer.playing) {
audioFilePlayer.pause()
buttonPlay.setTitle("PLAY", forState: .Normal)
} else {
audioFilePlayer.scheduleFile(audioFile, atTime: nil, completionHandler: nil)
audioFilePlayer.play()
buttonPlay.setTitle("PAUSE", forState: .Normal)
}
}
}

(続き:[Swift]AVAudioEngineを使ってReverbをかける

[Swift]AVAudioEngine, AVAudioPlayerNode, AVAudioPCMBufferを使った音源の再生

ハマりにハマって更新が滞っています。

耳コピアプリを作りたくて、音源の再生、再生位置の変更、ピッチの変更、再生速度の変更などを実装したいのですが、いろいろと困難にぶちあたり進みません。。。。

とりあえず、AVAudioEngine, AVAudioPlayerNode, AVAudioPCMBufferを使った音源の再生のメモです。これで、Bufferとして?、音源が再生できます。

曲の総時間(秒)は、総フレーム数(.length)を、サンプルレート(44100)で割って出しています。
labelTotalTime.text = String(audioFile.length/44100)のところです。

AVAudioFileを使って、曲のピッチ変更、再生速度の変更にも成功していますので、後日公開します。

いずれにしても、AVAudioEngineを使って、曲の現在再生時間の表示や取得ができず、困っています。
UISlider動かすと曲の再生箇所が変わる、みたいなこともできません。

だれか助けて!


//
// ViewController.swift
//

import UIKit
import AVFoundation

class ViewController: UIViewController {

var audioEngine: AVAudioEngine!
var audioBufferPlayer: AVAudioPlayerNode!
var audioFile: AVAudioFile!
var audioBuffer: AVAudioPCMBuffer!

@IBOutlet weak var labelTotalTime: UILabel!

@IBAction func playWithAVAudioPCMBufferPressed(sender: AnyObject) {
if !audioEngine.running {
audioEngine.startAndReturnError(nil)
}

if audioBufferPlayer.playing {
audioBufferPlayer.pause()
} else {
audioBufferPlayer.play()
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("update"), userInfo: nil, repeats: true)
}

}

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.

audioEngine = AVAudioEngine()
audioBufferPlayer = AVAudioPlayerNode()
audioEngine.attachNode(audioBufferPlayer)

audioFile = AVAudioFile(forReading: NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("test", ofType: "mp3")!), error: nil)
audioBuffer = AVAudioPCMBuffer(PCMFormat: audioFile.processingFormat, frameCapacity: UInt32(audioFile.length))
audioFile.readIntoBuffer(audioBuffer, error: nil)

audioEngine.connect(audioBufferPlayer, to: audioEngine.mainMixerNode, format: audioBuffer.format)
audioBufferPlayer.scheduleBuffer(audioBuffer, completionHandler: nil)

labelTotalTime.text = String(audioFile.length/44100)

}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

}

Swiftでオーディオプレイヤー:再生速度(rate)の変更

Swiftでオーディオプレイヤー:UISliderの設置と、曲の再生時間や再生箇所との同期」の続きです。UISliderを設置し、Sliderの動きと、再生速度(レート)を同期させます。AVAudioPlayerの.enableRateや.rateなどが勉強できると思います。

前回までのデータに数行コードを追記しますので、前回の投稿も参考ください。

できること

スクリーンショット 2014-10-22 18.24.57

ソフトのバージョン

OS: OSX Yosemite 10.10
Xcode: 6.1

つくりかた

動画でご確認ください。

課題

再生速度を変えると、音質が、、、、、。
解決策をご存知のかた、ぜひアドバイスくださいませ!

コード

太字部分が今回追記したコードです。
RateChange

import UIKit
import AVFoundation

class ViewController: UIViewController {

var audioPath = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(“test”, ofType: “mp3”)!)
var player = AVAudioPlayer()
var timer = NSTimer()

@IBOutlet weak var labelCurrentTime: UILabel!
@IBOutlet weak var labelTotalTime: UILabel!
@IBOutlet weak var labelRate: UILabel!

@IBOutlet weak var btnPlayTitle: UIButton!

@IBOutlet weak var sliderCurrentTime: UISlider!
@IBOutlet weak var sliderRate: UISlider!

@IBAction func btnPlay(sender: UIButton) {
if !player.playing {
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector(“updatePlayingTime”), userInfo: nil, repeats: true)
player.play()
btnPlayTitle.setTitle(“Pause”, forState: UIControlState.Normal)
} else {
player.pause()
btnPlayTitle.setTitle(“Play”, forState: UIControlState.Normal)
}
}

@IBAction func sliderMove(sender: UISlider) {
player.currentTime = Double(sliderCurrentTime.value)
self.updatePlayingTime()
}

@IBAction func sliderRateMove(sender: UISlider) {
player.rate = sliderRate.value
labelRate.text = String(format: “%.1f倍速”, sliderRate.value)
}

func updatePlayingTime() {
sliderCurrentTime.value = Float(player.currentTime)
labelCurrentTime.text = formatTimeString(player.currentTime)
}

func formatTimeString(d: Double) -> String {
let s: Int = Int(d % 60)
let m: Int = Int((d – Double(s)) / 60 % 60)
let h: Int = Int((d – Double(m) – Double(s)) / 3600 % 3600)
let str = String(format: “%02d:%02d:%02d”, h, m, s)
return str
}

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
player = AVAudioPlayer(contentsOfURL: audioPath, error: nil)
player.enableRate = true
player.prepareToPlay()
labelTotalTime.text = formatTimeString(player.duration)
sliderCurrentTime.maximumValue = Float(player.duration)
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

}

Swiftでオーディオプレイヤー:UISliderの設置と、曲の再生時間や再生箇所との同期

【Swift】曲の再生時間と総時間をhh:mm:ssの表記でラベルに表示する方法」の続きです。UISliderを設置し、曲の再生時間や再生箇所とSliderを同期させます。UISliderの.valueや、.maximumValueなどが勉強できると思います。前回までのデータをもとに、数行コードを追記しただけです。

できるもの

スクリーンショット 2014-10-22 12.18.15

ソフトのバージョン

OS: OSX Yosemite 10.10
Xcode: 6.1

つくりかた

動画でご確認ください。

コード

太字部分を追記してます。

import UIKit
import AVFoundation

class ViewController: UIViewController {

var audioPath = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(“test”, ofType: “mp3”)!)
var player = AVAudioPlayer()

var timer = NSTimer()

@IBOutlet weak var labelCurrentTime: UILabel!
@IBOutlet weak var labelTotalTime: UILabel!
@IBOutlet weak var btnPlayTitle: UIButton!
@IBOutlet weak var sliderCurrentTime: UISlider!

@IBAction func btnPlay(sender: UIButton) {
if !player.playing {
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector(“updatePlayingTime”), userInfo: nil, repeats: true)
player.play()
btnPlayTitle.setTitle(“Pause”, forState: UIControlState.Normal)
} else {
player.pause()
btnPlayTitle.setTitle(“Play”, forState: UIControlState.Normal)
}
}

@IBAction func sliderMove(sender: UISlider) {
player.currentTime = Double(sliderCurrentTime.value)
self.updatePlayingTime()
}

func updatePlayingTime() {
sliderCurrentTime.value = Float(player.currentTime)
labelCurrentTime.text = formatTimeString(player.currentTime)
}

func formatTimeString(d: Double) -> String {
let s: Int = Int(d % 60)
let m: Int = Int((d – Double(s)) / 60 % 60)
let h: Int = Int((d – Double(m) – Double(s)) / 3600 % 3600)
let str = String(format: “%02d:%02d:%02d”, h, m, s)
return str
}

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
player = AVAudioPlayer(contentsOfURL: audioPath, error: nil)
player.prepareToPlay()
labelTotalTime.text = formatTimeString(player.duration)
sliderCurrentTime.maximumValue = Float(player.duration)
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

【Swift】曲の再生時間と総時間をhh:mm:ssの表記でラベルに表示する方法

【Swift】ボタンをタップすると曲が再生され、且つ、ボタンタイトルが変わる方法」の続きです。NSTimerを使って、曲の再生時間と総時間をhh:mm:ssの表記でラベルに表示します。AVAudioPlayerの.currentTimeや.durationを使っています。

次回は、スライドバーを使って、再生箇所を自由に変更できるようにする予定です!

できるもの

スクリーンショット 2014-10-21 19.32.42
左側のラベルに曲の再生時間を、右側のラベルに曲の総時間を表示します。

ソフトのバージョン

OS: OSX Yosemite 10.10
Xcode: 6.1

つくりかた

動画でご確認ください。

コード


import UIKit
import AVFoundation

class ViewController: UIViewController {

var audioPath = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("test", ofType: "mp3")!)

var player = AVAudioPlayer()
var timer = NSTimer()

@IBOutlet weak var labelCurrentTime: UILabel!
@IBOutlet weak var labelTotalTime: UILabel!
@IBOutlet weak var btnPlayTitle: UIButton!

@IBAction func btnPlay(sender: UIButton) {
if !player.playing {
timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("updatePlayingTime"), userInfo: nil, repeats: true)
player.play()
btnPlayTitle.setTitle("Pause", forState: UIControlState.Normal)
} else {
player.pause()
btnPlayTitle.setTitle("Play", forState: UIControlState.Normal)
}
}

func updatePlayingTime() {
labelCurrentTime.text = formatTimeString(player.currentTime)
}

func formatTimeString(d: Double) -> String {
let s: Int = Int(d % 60)
let m: Int = Int((d - Double(s)) / 60 % 60)
let h: Int = Int((d - Double(m) - Double(s)) / 3600 % 3600)
let str = String(format: "%02d:%02d:%02d", h, m, s)
return str
}

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
player = AVAudioPlayer(contentsOfURL: audioPath, error: nil)
player.prepareToPlay()
labelTotalTime.text = formatTimeString(player.duration)
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

SwiftでなんちゃってStopWatchを作ってみた(その2):ミリ秒を表示しよう

「SwiftでなんちゃってStopWatchを作ってみた(その1)」の続きです。前回のものをベースに、コードをちょっと書き換えまして、ミリ秒を表示できるようにしました。具体的には、NSTimerの処理時間の変更と、ラベルテキストの表示(String(format:))に手を加えています。

できるもの

スクリーンショット 2014-10-21 13.16.02

ソフトのバージョン

OS: OSX Yosemite 10.10
Xcode: 6.1
※前回まで6.1beta使ってましたが、今回から6.1になりました。

つくりかた

動画でご確認ください。

コード


import UIKit

class ViewController: UIViewController {

var countNum = 0
var timerRunning = false
var timer = NSTimer()

func update() {
countNum++
timeFormat(countNum)
}

func timeFormat(countNum:Int) {
let ms = countNum % 100
let s = (countNum - ms) / 100 % 60
let m = (countNum - s - ms) / 6000 % 3600
label.text = String(format: "%02d:%02d.%02d", m, s, ms)
}

@IBOutlet weak var label: UILabel!

@IBAction func start(sender: UIButton) {
if timerRunning == false {
timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: Selector("update"), userInfo: nil, repeats: true)
timerRunning = true
}
}

@IBAction func stop(sender: UIButton) {
if timerRunning == true {
timer.invalidate()
timerRunning = false
}
}

@IBAction func reset(sender: UIButton) {
countNum = 0
label.text = "00:00.00"
}

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

}