Swiftプログラマなら、import Foundation
と記述する機会は多いと思います。でもちょっと待った。よく理解しないまま思考停止でこの記述を繰り返したりしていませんか?
ケンヂまるも最近まで思考停止していましたが、それではいかんとFoundation
フレームワークが何者なのか調べてみました。
Swift
フレームワークにあるString
クラスとFoundation
フレームワークにあるString
クラスの違いは?String
クラスのFoundation
フレームワークインポート前と後の挙動の違いは?Swift
フレームワークとFoundation
フレームワークが別で定義されているのはなぜ?Foundation
フレームワークにあるNSString
など"NS"が頭につくクラスは何者?Foundation
フレームワークはそもそも何を目的にしたフレームワーク?
といった部分についてまとめておきます。
調査では断片的な情報しか得られなかったので、それらを理解しやすいよう体系的にまとめたので、推測も含まれています。誤りがあればご指摘頂けるとありがたいです。
FoundationフレームワークはObjective-CライブラリをSwiftから使えるようにしたもの
Swiftは比較的歴史の浅いプログラミング言語です。2014年にリリースされたわけですが、それ以前のアプリ開発ではObjective-Cが主に使われていました。
Swift言語の基本的な機能はSwift
フレームワークに実装されましたが、Objective-Cで活用されていたクラス群はFoundation
フレームワークをインポートすることでアクセスできるよう設計されました。
つまりFoundation
フレームワークはSwiftプログラミング言語からObjective-Cのクラス群にアクセスするための橋渡しをします。
例えば、Swift
フレームワークには日付や時刻に関するクラス群は用意されていません。そういった機能はObjective-Cの時代に既に実装されていたので、そちらを活用します。Foundation
フレームワークをインポートすると、Foundation
フレームワークで定義されているDate
クラスを活用できます。
let now = Date()
now.formatted() // 結果:2024/05/16, 8:16
他にも、Swift
フレームワークで既に定義されているクラスの機能も、Foundation
フレームワークをインポートすることで補完されたりします。
Swift
フレームワークのString
クラスのドキュメントでは、String(format:_:)
コンストラクタの存在を確認することができます。Swift
フレームワークで定義されているように見えるので、そのまま使えるかと勘違いしてしまいそうですが、実際にはFoundation
フレームワークをインポートしないと使うことができません。
String(format: "%02d時%02d分", 8, 15) // ビルドエラーにならない
// 結果:"08時15分"
Foundationフレームワークをインポートすると挙動が変化するクラスもある
Foundation
フレームワークをインポートすると、Foundation
フレームワークで定義されているクラスが使えるようになったり、Swift
フレームワークで既に定義されているクラスに対して機能が補完されたりするということを説明しました。
これはありがたいことですが、実はFoundation
フレームワークをインポートする前と後で、String
クラスの一部のメソッドの挙動が変化してしまうという、ちょっと危険な仕様も存在します。
"a".contains("") // true
"a".contains("a") // true
"" == "" // true
"".contains("") // false
"a".contains("") // false
"a".contains("a") // true
"" == "" // true
この危険な仕様、StackoverflowのWhy does String.contains behave differently when I import Foundation?を見つけて初めて知りました。
Swiftはクラスや構造体などをextend
できるので、オブジェクトの挙動が後から書き換えられる可能性があるプログラム言語なので、ある程度の挙動変化の想定は必要です。とはいえ、こんな基礎的な部分の挙動がこっそり変化する実装はやめてほしいものですよね…。開発するときはテストをしっかり作成しよう。そうしよう。
StringクラスとNSStringクラスの関係
Foundation
フレームワークにはString
クラスがありますが、それとは別にNSString
クラスも存在します。
Foundation
フレームワークはSwiftプログラミング言語からObjective-Cのクラス群にアクセスするための橋渡しをする、ということは先述しました。
そしてNSString
クラスは、Objective-Cで定義されていた文字列を表現するクラス名です。Foundation
フレームワークでは、NSString
クラスとString
クラスは同じものとして扱われます。
print("" is String) // 結果:true
print("" is NSString) // 結果:true
print(String("") is NSString) // 結果:true
print(NSString("") is String) // 結果:true
ほかにも、NSDate
クラスはDate
クラスとしてアクセスできますし、NSArray
クラスはArray
クラスとしてアクセスできます。
クラスの対応表はPrefer Swift Value Types to Bridged Objective-C Reference Typesに記載があります。
あとがき
Swiftは比較的新しいプログラミング言語なので比較的洗練されているものの、中途半端な形でObjective-Cから機能を取り入れたためにFoundation
フレームワーク周りを中心としてクールじゃない仕様になってしまっていて残念です。
ただ、Apple製品向けのアプリ開発言語としては主流だと思うので、今後も使い続けていくことになると思います。こういったクールじゃない部分についてもちゃんと理解しているかどうかが、Swiftプログラマの質の違いに現れるんじゃないかってことで、今後も積極的に気になった部分は深掘りしていこうと思います。