Help us understand the problem. What is going on with this article?

CocoaTouchFramework上でImageLiteralを使用する方法

More than 1 year has passed since last update.

SwiftでCocoaTouchFrameworkを開発していて、特に不便だなと思うのは、 ImageLiteralが使用出来ないということです。

これは、ImageLiteralが、mainのBudleからリソース取得しようとするため、使用すると、mainのBundleで画像が無いとクラッシュしてしまうためです。

しかし、Xcodeの機能上、Frameworkのプロジェクト上でもImageLiteralは使えますし、コンパイルも通るので、使えないのはなんとももどかしいところです。

なので、今回は、そこをなんとかハックして、CocoaTouchFramework上でImageLiteralを使用する方法を見つけたので、紹介します。

_ExpressibleByImageLiteral

_ExpressibleByImageLiteralというProtocolを利用すれば、Framework上でImageLiteralを使用することができます。

ただし、このProtocolはXcodeの予測変換で出てこないので、実際に打ち込む必要があるので気をつけましょう。

とりあえず簡単に実装してみると以下のようになります。

// _ExpressibleByImageLiteralは予測変換で出てこないImageLiteralのProtocol
struct FrameworkImageLiteral: _ExpressibleByImageLiteral {

    let image: UIImage

    // pathにはImageLiteralで指定したImageの名前が入ってくる
    init(imageLiteralResourceName path: String) {
        // 通常のImageLiteralの動作と同じように初期化できなかったらアプリを落とすために!にする
        self.image = UIImage(named: path, in: Bundle.current, compatibleWith: nil)!
    }
}

Bundle.currentに関しては、以前に以下の記事を書いたので、それを参考にしてください。

SwiftのフレームワークでBundleを取得する方法

実際に使ってみるとこんな感じ

let image = (#imageLiteral(resourceName: "image_name") as FrameworkImageLiteral).image

これでFramework上のBundleからImageLiteralを使用して画像を取得できます。

なんかイケてなくね?

(#imageLiteral(resourceName: "image_name") as FrameworkImageLiteral) 

しかし、キャストするのが少し鬱陶しいので、もう少しいい感じにする方法を考えてみました。

いい感じにしてみた。

まずは最初の_ExpressibleByImageLiteralを実装した構造体でUIImageを生成せずに、Pathだけ保持するように変更します。

struct FrameworkImageLiteral: _ExpressibleByImageLiteral {

    let path: String

    init(imageLiteralResourceName path: String) {
        // ここでImageを生成せずにpathだけ保持しておく
        self.path = path
    }
}

次にUIImageのextensionで、Frameworkimageliteralを引数にして、先ほどFrameworkImageLiteralで行なっていたUIImageの初期化をこちらで行います。

extension UIImage {

    convenience init!(literal: FrameworkImageLiteral) {
        self.init(named: literal.path, in: Bundle.current, compatibleWith: nil)!
    }
}

それで実際に使用するとこんな感じになります。

let image = UIImage(literal: #imageLiteral(resourceName: "image_name"))

変にキャストが挟まらないので、いい感じになりました。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away