Swiftから始めた我々はimportを理解していない#1


注意書き

この記事は試行実験を含んでおり、一部の説明が誤っている可能性があります。そうなんだ程度に読んでいただき、誤りがあった場合コメントをいただけると幸いです。

はじめに

夏が終わって秋がやってきたと思ったら、また夏が帰ってきて、全然久し振りじゃないです、TOSHです。

よく、iOSアプリ初学者のコードを見ていると、

import Foundation
import UIKit

といったコードを見ることがあります。その度、UIKitをimportしているならFoundationは要らないよ〜とか伝えたり、
Android開発をしていると、めちゃくちゃimport書かなくちゃいけなくてマジでめんどくさいって思ったりしています。

今まで、そこに疑問を持ってはいませんでしたが、ふと自分はimportとは何かを理解していないのでは?と思い立ってこの記事をまとめています。

自分のエンジニア背景

自分は25歳です。ちょうど新卒2年目に当たるので、まだまだJunior Engineerといったところでしょうか?大学生の時から、iOSアプリ開発を始めたので、初めて触ったのはObjective-Cではなく、Swift(バージョンは2とか)。
AndroidやUnityにちょいちょい手を出したりはしていましたが、エンジニアとしてのほとんどのキャリアをiOSに費やしています。

実際、どうでしょう。Swift。これは、Swiftの特徴と言うわけではないのですが、iOSアプリを作るときは、importをあまり深く考えることなく、
UI系のパーツを使用したいので、import UIKitを使う。音声周りの機能を使いたいので、import AVFoundation、Structを作成するだけなので、import Foundationをするといった動作をします。

importを考える

では一体なぜ、

import Foundation
import UIKit

は誤っているのでしょうか?
これについては別に誤っているわけではなく、UIKitがFoundationを含んでいるので、UIKitをImportした場合には、Foundationが不要といううわけです。
では実際に、UIKitの中身を読み解いていきましょう。

import CoreGraphics
import DataDetection
import Dispatch
import Foundation
import UIKit.DocumentManager
import UIKit.NSAttributedString
import UIKit.NSDataAsset
~省略~
import UIKit.UIWindowSceneActivationRequestOptions
import UIKit.UNNotificationResponse_UIKitAdditions
import _Concurrency

UIKitの定義を見てみるととてもたくさんimportをしており、この中でimport Foundationしているため不要になるというわけです。

では実際にこれが正しいのかを見ていきましょう。
今回試行実験として、Foundation内のクラスである、NSArrayを使用します。
まずはFoundationをimportせずにNSArrayの変数を定義してみましょう。

早速エラーが出てしまいましたね。ではここに、Foundationをimportしたモジュールである、UIKitをimportします。

すると、先程までのエラーが消えたので、仮説は正しそうです。

import UIKit.UIImage

では次の実験へと移りましょう。
先程の、UIKitの中身を覗くと、import UIKit.DocumentManagerのように、Swiftを書いているとなかなかみないimportの仕方をしていましたね。
この理論でいくと、import UIKit.UIImageをすると、UIKitの中のUIImageのみ使用できるようになるのでしょうか?
今回は変数に、

    var image: UIImage!
    var color: UIColor!

の二つを用意します。ここに、import UIKit.UIImageをしてみましょう。

あ、あれ?どうやら、エラーは出ませんね。

では一体どうやったら、エラーを出すことができるのでしょうか?

import UIKit.UIImageimport class UIKit.UIImageへと書き換えてみてください。そうするとUIColorは定義ができなくなってしまいます。

importの種類

では下の三つは一体何が違うのでしょうか?

import UIKit
import UIKit.UIImage
import class UIKit.UIImage

上記は具体的な例になっているので、これを抽象化しましょう。

import [module]
import [module].[submodule]
import [import kind] [module].[submodule]

つまり今回のケースでは、import [module].[submodule]をした際に、UIImageだけではなく、UIKit全体をimportしていたのです。そこで、import [import kind] [module].[submodule]のように種類を指定してあげると指定したものだけがimportされるというようになります。

kindの種類として使えるものは以下になります。

struct  // 構造体
class   // クラス
enum    // 列挙型
protocol // プロトコル
typealias // タイプエイリアス
func    // メソッド
let // 定数
var // 変数

まとめ

Swiftという言語はモダンで便利なように設計されており、あまりこう言った部分を意識しないでも使用することができます。自分自身あまりここら辺のことを深くは考えていませんでした。
今回はimportの一端に触れることができたので、また、深く調べてみたいですね。
第二弾に期待!