しるてく

技術的な話をします

UICollectionViewでSDWebImage使うと同じ画像が表示されてしまうことがある

CollectionViewで図鑑(所持していると画像が見えて、所持していないと?画像が表示される)みたいなのを作るとして、

class HogeCollectionViewCell: UICollectionViewCell {
    @IBOutlet weak var hogeImageView: UIImageView!

    func setImage(url: String?) {
        if url != nil {
            self.hogeImageView.sd_setImageWithURL(NSURL(string: url))
        } else {
            self.hogeImageView.image = UIImage(named: "empty_hoge")
        }
    }
}

こんな感じのカスタムセルを作って、 cell.setImage(url) みたいな感じで画像をセットすると、未所持セルで何故か他の所持セルと同じ画像が表示されてしまう。

どうやら動きをみると、画面外にスクロールすると、どんどん未所持セルが所持セルに置き換わっているようなので、cellのreuseでsdWebImageが悪さしているらしいことが分かる。

なので、以下のように、 prepareForReusesd_cancelCurrentImageLoad を呼んであげればよさそうだ。

class HogeCollectionViewCell: UICollectionViewCell {
    @IBOutlet weak var hogeImageView: UIImageView!

    override func prepareForReuse() {
        super.prepareForReuse()
        self.hogeImageView.sd_cancelCurrentImageLoad()
    }

    func setImage(url: String?) {
        if url != nil {
            self.hogeImageView.sd_setImageWithURL(NSURL(string: url))
        } else {
            self.hogeImageView.image = UIImage(named: "empty_hoge")
        }
    }
}

なおった。

MapBox iOS SDK 2.0.0 試した

MapBoxっていうOpenStreetMapのデザインをカスタムできるみたいなサービスがあるのでiOS SDKを触ってみた。 触ってて、なんか転がっている情報となんか違うなと思っていたら、ちょうど6日程前に2.0.0がリリースされたっぽい。

www.mapbox.com

使い方

  1. MapBoxに登録する
  2. なんかデザインいじいじする
  3. pod 'Mapbox-iOS-SDK' して importしてあげてあとはよしなに

ドキュメントそこそこまとまっているのでちゃんと読めば、サンプル作る程度なら迷わなそう。

感想

  • Web上でデザインの設定ができるんだけどすごい簡単だし、いろいろな表示が出来て良い
    • ただ、アプリ側でどうやって表示するのかようわからんかった
    • JSON書いてね!みたいな記述もあれば(しかも書き方/何を変更すればいいのか分からん)
    • styleURLにMap ID(mapbox://<user.style>)指定してねみたいな記述もある

こういう感じ

        mapView.styleURL         = NSURL(string: "asset://styles/light-v7.json") // これはOK
        mapView.styleURL         = NSURL(string: "mapbox://silvers.xxxxxx") // 真っ黒の地図になった
  • 地図の移動を検知するほうほうがなさそう?

google mapでいうところのこれ

    func mapView(mapView: GMSMapView, didChangeCameraPosition position:GMSCameraPosition) {
        println("didChangeCameraPosition(): latitude:\(position.target.latitude), longitude:\(position.target.longitude)")
    }

    func mapView(mapView: GMSMapView, idleAtCameraPosition position:GMSCameraPosition) {
        println("idleAtCameraPosition(): latitude:\(position.target.latitude), longitude:\(position.target.longitude)")
    }

まとめ

簡単にカスタマイズされたデザインの地図表示するなら楽そうだなって感じだった。

一方で、地図上で複雑な処理させるならGoogleMapのほうがやりやすい。

Mapbox.js使えばWebでも使えるのでこっちは今すぐ使っても良いなあ!と思った(イベント会場の位置とか、お店の位置とかそういうの示すのに)。

Assets.carを展開してpngをゲットしたい

assets catalogにpdf突っ込むとビルド時に@1x, @2x, @3xのpng画像に変換してくれる。 Android用にpng書き出すのが面倒だったので、png取得できないかなーと思ったらAssets.carってやつにまとめられているらしい。

展開するには以下のツールをビルドして ./cartool [展開したいcar] [展開先のdir] ってやるといい。

github.com

swiftでArrayの範囲外をよんだときにエラーにならずnilを返すextension

swiftのArrayでインデックスの範囲外を指定すると実行時にエラーになってしまう。

    let data = [ 1, 2, 3, 4 ]
    return index < data.count ? data[index] : nil

毎度毎度こんな感じで書くのだるいので、

    let data = [ 1, 2, 3, 4 ]
    return data[safe: index]

でアクセスできるようにする

gist.github.com

githubではdiffを見たくないけど手元では見たい

pull-reqとか見てるとstoryboardがすごい行数のdiff出してきて他のファイルのdiffが見づらい。

そんなときは .gitattributes*.storyboard -diff って追加してあげるとdiffがでなくてステキだ。

しかし、自分が作業しているときはうっかり変な変更入れていないかとか確認したいこともある。

そんなときは .git/info/attributes*.storyboard diff=word って追加してあげると自分の環境だけdiffがみれてステキだ。

UICollectionViewでCellを長押ししたい

UILongPressGestureRecognizer を都度生成するの効率悪いのでViewDidLoadで一度だけ生成して、タップ後にどのCellを押したか判定する感じにする

     override func viewDidLoad() {
        super.viewDidLoad()

        let longPressRecognizer = UILongPressGestureRecognizer(target: self, action: "onLongPressAction:")
        longPressRecognizer.allowableMovement = 10
        longPressRecognizer.minimumPressDuration = 0.5
        self.collectionView.addGestureRecognizer(longPressRecognizer)
    }
    func onLongPressAction(sender: UILongPressGestureRecognizer) {
        let point: CGPoint = sender.locationInView(self.collectionView)
        let indexPath = self.collectionView.indexPathForItemAtPoint(point)

        if let indexPath = indexPath {
            switch sender.state {
            case .Began:
                // 例えばTimerをstartさせる
            case .Ended:
                // 例えばTimerをstopさせる
            default:
                break
        }
    }