0.追記
@susieyy さんのご指摘により解決致しました。
Beta7にアップデートしてから、以下のコマンドは実施されましかたか?
Beta7以前の中間コンパイルがあるとうまく動作しないですrm -rf ~/Library/Developer/Xcode/DerivedData
こちらを実行後、@objcを取り除いても、正常に動作しました。
1.はまったこと
beta7に変更してから、これまでのDelegateだとうまく通らならかったのでメモ。
ハマったプロジェクトは、この前投稿したこちらの記事(SwiftでTinderUIを実装してみた)です。
2.beta7に対応する前のコード
「SwiftでTinderUIを実装してみた」にソースはほとんどおいているので(もしくはGithub)、下記コードは必要な部分のみを抜粋しています。
今回関連するファイルは2つで、DraggableView.swiftとDraggableViewBackground.swiftです。
それぞれのファイルのサマリーを先に書いておくと、
-
DraggableView.swiftでは、
-
左右にスワイプされたときに起こるカードのアクションを定義している
-
DraggableViewBackgroun.swiftで使うためのDelegateを用意している
-
DraggableViewBackground.swiftでは、
-
背景やボタン、TinderUIのカードなどを描画する
-
カードに表示するテキストの生成、読み込みなどを行う
-
左右にスワイプされたときに、表示するテキストを変える
-
DraggableView.swiftで用意されたprotocolを継承している
という感じです。
それで、下記コードがbeta7に対応する前のコードです。
// このファイルでは、TinderUIで言うところのカードのViewを生成し、ドラッグされた時の挙動を定義しています。
// Delegate先で使う予定のfunctionをprotocolで宣言しておきます。
protocol DraggableViewDelegate {
func cardSwipedLeft(card: UIView)
func cardSwipedRight(card: UIView)
}
class DraggableView: UIView {
var delegate: DraggableViewDelegate?
.
.
.
func rightAction() { // カードが右にドラッグされたときの処理
var finishPoint: CGPoint = CGPointMake(500, 2*yFromCenter + self.originalPoint.y) // ドラッグされて、手が話された場所を変数に入れておく
// カードが画面から消えるようにする
UIView.animateWithDuration(0.3, animations: {
self.center = finishPoint
}, completion: { (value: Bool) in
self.removeFromSuperview()
})
delegate?.cardSwipedRight(self) // ここで、delegate先のDraggableViewBackground.swiftに書かれている関数を呼び出す
NSLog("YES")
}
func leftAction() { // カードが左にドラッグされたときの処理
var finishPoint: CGPoint = CGPointMake(-500, 2*yFromCenter + self.originalPoint.y) // ドラッグされて、手が話された場所を変数に入れておく
// カードが画面から消えるようにする
UIView.animateWithDuration(0.3, animations: {
self.center = finishPoint
}, completion: { (value: Bool) in
self.removeFromSuperview()
})
delegate?.cardSwipedLeft(self) // ここで、delegate先のDraggableViewBackground.swiftに書かれている関数を呼び出す
NSLog("NO")
}
.
.
.
}
// このファイルでは、背景やその他のボタンを描画したり、カードの読み込みなどを行っています。
class DraggableViewBackground: UIView, DraggableViewDelegate{ // 先ほど用意したDelegateのためのprotocolを継承
.
.
.
// カードのViewを描画
func createDraggableViewWithDataAtIndex(index: Int) -> DraggableView {
var draggableView: DraggableView = DraggableView(frame:CGRectMake(30, 100, CARD_WIDTH, CARD_HEIGHT))
draggableView.information.text = "\(exampleCardLabels[index])"
draggableView.backgroundColor = UIColor.whiteColor()
draggableView.delegate = self
println("delegate = \(draggableView.delegate?)")
return draggableView
}
// 宣言していたProtocolにあるfunctionの中身を書いていきます。
func cardSwipedLeft(card: UIView) {
loadedCards.removeObjectAtIndex(0)
if ( cardsLoadedIndex < allCards.count ) {
loadedCards.addObject(allCards.objectAtIndex(cardsLoadedIndex))
cardsLoadedIndex++
self.insertSubview(loadedCards.objectAtIndex(MAX_BUFFER_SIZE-1) as UIView, belowSubview: loadedCards.objectAtIndex(MAX_BUFFER_SIZE-2) as UIView)
}
if (cardsLoadedIndex == 5) {
self.result.text = "hoge"
}
}
func cardSwipedRight(card: UIView) {
loadedCards.removeObjectAtIndex(0)
println("allCards = \(allCards.count)")
println("cardsLoadedIndex is /(cardsLoadedIndex)")
println(loadedCards.count)
if ( cardsLoadedIndex < allCards.count ) {
loadedCards.addObject(allCards.objectAtIndex(cardsLoadedIndex))
cardsLoadedIndex++
self.insertSubview(loadedCards.objectAtIndex(MAX_BUFFER_SIZE-1) as UIView, belowSubview: loadedCards.objectAtIndex(MAX_BUFFER_SIZE-2) as UIView)
}
if (cardsLoadedIndex == 5) {
self.result.text = "huga"
}
}
.
.
.
}
beta7以前は、これで動いていたのですが、beta7にしたら、
draggableView.dalegate? = self
がnilになり、
delegate?.cardSwipedLeft(self)
もそのままnilなので、
func cardSwipedLeft
が呼び出されなくなってしまいました。
3.対策
色々と調べてたのですが、対策は、
@objc protocol DraggableViewDelegate {
func cardSwipedLeft(card: UIView)
func cardSwipedRight(card: UIView)
}
というように@objc
をprotocolの前につければさきほどのnilの部分に全てきちんとしたOptional型での値が入りました。
4.よくわからないこと
- @objcをつけることによってナゼ解消されるのか?
- そもそも設計上、このDelegateがベストプラクティスなのか?
ご存知の方、是非教えて下さいm(_ _)m