はじめに
こんにちは。iOSエンジニアの@satoshi-babaです。 いま巷で賑わっているXCodeGenを検証する過程で、UIKit系のクラスの参照が解決できない事象に出くわしました...。 その事象を解決するまでの道のりを共有したいと思います。
事の始まり
現在、私はXCodeGenの検証を実施しています。
ある日私はほとんどの設定を書き終え「いや〜これは完璧だわ!ビルドして動作確認するぞ!」と息巻いていたところ、 およそ1000を超えるSwift Compiler Errorに遭遇してしまいました。
表示されていたエラーは大きく分けて以下の3つでした。
Use of Undeclared Identifier CGFloat
Use of Undeclared Identifier UIFont
Use of Undeclared Identifier UIImage
該当の処理を確認すると、確かにCGFloatやUIFontは使用されています。 しかしimportされているのはFoundationのみで、UIKitに属するCGFloatやUIFontは解決できなそうです。
import Foundation extension String { func labelHeight(width: CGFloat, font: UIFont, maxLine: Int = 0) -> CGFloat { let label = UILabel() label.font = font label.lineBreakMode = .byTruncatingTail label.numberOfLines = maxLine label.text = self let rect: CGSize = label.sizeThatFits(CGSize(width: width-label.layoutMargins.left-label.layoutMargins.right, height: CGFloat.greatestFiniteMagnitude)) return rect.height } }
とりあえず全てのクラスにUIKitのimportすれば動きそうです。 しかし、なぜこのような状態で今までコンパイルできたのか、XCogeGenで生成したプロジェクトで解決できなくなったのか気になります。 もしかしたら重要な見落としがあるかと思い、調査することにしました。
原因はBridging Header忘れ!!
XCogeGenで生成したプロジェクトの時に発生する問題です。絶対に設定し忘れている項目があるはずです! Build Settingsを上から順番チェックしてみることにしました。
すると見事にBridging Headerの追加を忘れていました!
設定を追加したら無事にビルドができるようになりました。 これで安心!...では終われません!
Bridging Headerの動きをさらに追ってみることにしました。
Bridging Headerは全てのSwiftファイルにimportされる
まずはBridging Headerの動作について、下記の公式ページで確認してみました。 Importing Objective-C into Swift
どうやらBridging Headerは全てのSwiftファイルにimportされるみたいです。 Bridging Headerまたはその先でUIKitをimportしていればいい感じに解決されちゃいそうですね...!
実際に読み込んでいる先でimportされていました!
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @interface HogeLogic : NSObject (省略)
感想
Bridging Headerをはずすだけでこんな影響が出るなんて思いもしませんでした。 昔のC言語でのCommonヘッダーみたいな役割が簡単にできちゃいますね!(意図してませんでしたが) もしかしたらコードレビューの観点に盛り込むべきかもしれませんね。