2018/01/19 更新

この記事で紹介しているNuke+WebPをdeprecateして、plugin形式にした Nuke-WebP-Pluginを作成しました。

詳しくはこちらをご覧ください。

はじめに

iOSエンジニアの小菅です。

今回の記事は、去年末くらいから名前を聞くようになったNukeをForkして、WebPのデコード処理を組み込んだモノを開発して公開したので、それの紹介と作業手順などを書いていきます。

余談ですが、Nuke[ニューク]の意味を調べたら核兵器って意味らしいです。

Nukeと作ったものの紹介

先にNukeの紹介と作ったもののインストール方法を紹介します。

本家のNukeのレポジトリ

今回、本家がWebP対応をする予定がないとのことだったので、ForkしてそのままWebP対応した版をCocoaPodsに登録しました。

Forkして作成したレポジトリ

CococaPodsCarthageに対応させたので以下のようにインストールできます。

# Podfile

pod 'Nuke+WebP', '~> 6.0'
# Cartfile

github 'ryokosuge/Nuke-WebP'

NukeのExampleにWebP表示の物を追加したやつもあげてあるので、是非試してみてください!

> bundle exec pod try Nuke+WebP
Updating spec repositories

Trying Nuke+WebP
Performing CocoaPods Installation
Fetching podspec for `Nuke+WebP` from `../`
Installing DFCache (4.0.2)
Installing Nuke+WebP (6.0)
Installing Preheat (3.0)
Installing libwebp (0.6.0)
Sending stats
Pod installation complete! There are 3 dependencies from the Podfile and 4 total pods installed.
Opening '/private/var/folders/yl/6188sfqd28l1klc_nxby14d40000gn/T/CocoaPods/Try/Nuke+WebP/Example/Nuke+WebP_Demo.xcworkspace'

ここから先はNuke+WebPを作った理由や、手順周りを書いていきます。

Nukeを選んだきっかけ

マンガZEROのiOSではSDWebImageを使って画像表示を行なっていました。

SDWebImageの採用理由としては以下の2点があります。

  1. 使い慣れている
  2. WebPに対応している

弊社マンガ事業部のアプリでは作品のバナー画像などの大きい画像のほとんどをWebP形式に変換して表示しています。

WebPの凄さについては以下の記事を参考にしてください。

何も苦しむことなくSDWebImageWebPの画像を表示していましたが、UIが変わり画像をたくさん表示するようになってから表示速度が遅くなってきました。(自分の組み方があまりよろしくないというのが1番の要因なのはわかっています…)

そのことをマンガZEROのチームメンバーにも指摘され、サーバーエンジニアに画像のリサイズなどを行ってもらう傍ら、アプリ側もどうにか出来ないかなと考えていました。

そんな中、年末に以下の記事を読みました。

マンガZEROもまさに記事と同じくExtensionは使わず、画像のダウンロードと表示処理しかしていませんでした。

この記事でNukeの存在を初めて知って衝撃だったのが以下の画像です。


Alexander Grebenyuk | Programming in Swift, Objective-C.より引用

色々調べていくうちにSDWebImageから乗り換えることを考えるようになりましたが、NukeがWebP対応していなかったのでどうしても乗り換えられませんでした。

NukeはWebP対応していないかった

最近作られている画像ローダー周りのライブラリはWebP対応されていないのが多いです。

理由はAppleがWebPに対応していないからです。

NukeのレポジトリのissueでもWebPサポートをお願いするissueがありましたが以下の理由で別ライブラリ採用を見送りました。

  • mattt/WebPImageSerializationが全くメンテナンスされていない
    • 4年前のcommitが最後
  • Method Swizzlingを使用している
    • UIImageのinitializerをSwizzlingしていたのですが、他のエンジニアがマンガZEROのメンテナンスをする際の負担になるかと思った

ただどうしてもNukeを導入したい熱が治らず、rs/SDWebImagepinterest/PINRemoteImageWebPのデコード処理を読んでいたら自分で書いて、なおかつNukeにも簡単に導入できると判断したので、自分で作成することにしました。

最初はそのままアプリに導入

最初はマンガZEROのiOSにそのままNukeを導入して、追加でWebPのデコード処理を書いて無事表示させることが出来ました。

一旦はそのままで大丈夫かと思っていましたが、他のアプリにも簡単に導入出来る様に本家をForkしてライブラリ化することを決めました。

弊社iOSチームはGithubのPrivateのSpecレポジトリを作っていて共有できるライブラリをそこにあげて他の人に使ってもらえるようにする文化があるので、最初はそこにあげようかと思いましたが、思い切ってpublicにあげてCocoaPodsに公開することにしました。

Forkしてからの簡単な手順

できる限り本家のソースコードを汚したくない(アップデートの追従が難しくなる)ので、自分で書くコードは別ディレクトリに書くようにしました。

  1. 本家repositoryからforkする
  2. レポジトリ名を変更する
    • 今回の場合だとryokosuge/Nukeからryokosuge/Nuke-WebPに変更
  3. もくもくとWebPのデコード処理を書いていく
    • 本家が対応しているものはできる限り対応していく
    • libwebpWatchOSでビルド出来なかったので諦める
  4. 無事実装終わったらリリース処理
  5. アカウント登録していない場合はbundle exec pod trunk register [e-mail] '[your name]'で登録処理
    • 自分の場合はbundle exec pod trunk register ryo.kosuge@gmail.com 'Ryo Kosuge'
    • 登録処理が完了するとbundle exec pod trunk meで確認できる
  6. bundle exec pod spec lint [ライブラリ名].podspecでlintかける
  7. bundle exec pod trunk push [ライブラリ名].podspecCocoaPodsに登録する
  8. carthage build --no-skip-currentでbuildする
  9. carthage archiveでフレームワークのzipを作成
  10. GitHubのreleaseページに貼り付ける

上記の作業でほぼ公開作業が完了しました。

本家レポジトリはSwift Packge Managerにも対応していましたが、現状自分自身が使っていないものに無理して対応するのもおかしいかと思い今回はやめました。

必要になった際に対応しようかと思いますが、すぐに対応して欲しい場合はPull Requestを投げつけてもらえればと思います。

ライブラリのソースコードを読んで学んだこと

今回は以下のレポジトリに大変お世話になりました。

お世話&参考にさせていただいた部分を紹介します。

SDWebImage && PINRemoteImage

  • .podspecの書き方が勉強になった
  • iOSとmacOSでの対応方法
    • UIImageNSImageの対応方法…
  • WebPのデコード処理
    • PINRemoteImageSDWebImageを見比べながら少しずつ意味調べて書いていきました
  • libwebpとの依存関係の解消方法
    • Cocoapodsにはlibwebpあるので多少は問題ありませんでしたが、Carthageの対応方法はPINRemoteImageを参考にやりました

Nuke

  • Swiftのソースコード全般
    • 依存関係の解消だったり、拡張のしやすさやテストコードなどとても勉強になりました

特にNukeのソースコードは何度も読み返しました。

ここまで簡潔に拡張可能なソースコードって書けるんだなって感動しました…。

Swiftでアプリもある程度余裕持って作れるようになって、アプリの設計に不満を感じ始めたらぜひNukeのソースコードを読んでみてください。

素晴らしい設計でした。

終わりに

ざっと作成したライブラリの紹介と手順と感想とを書かせて頂きました。

初めてのCocoaPodsへのライブラリ登録だったのでテンション上がった状態でブログ書きました。

Forkして書くことで本家のソースコード読みながら実装することが出来て楽しかったです。

今回は本家がWebPに対応する予定がないとのことだったのでForkしてそのまま登録までさせていただきましたが、また違うライブラリでForkする機会があったら今度はそのままPull Requestを出してみようかと思います。

Pull Requestお待ちしております!