このブログはアフィリエイト広告を利用しています

Swift

Swiftプログラミングのimport Foundationについて理解する

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クラスを活用できます。

import Foundation

let now = Date()
now.formatted() // 結果:2024/05/16, 8:16

他にも、Swiftフレームワークで既に定義されているクラスの機能も、Foundationフレームワークをインポートすることで補完されたりします。

SwiftフレームワークのStringクラスのドキュメントでは、String(format:_:)コンストラクタの存在を確認することができます。Swiftフレームワークで定義されているように見えるので、そのまま使えるかと勘違いしてしまいそうですが、実際にはFoundationフレームワークをインポートしないと使うことができません。

String(format: "%02d時%02d分", 8, 15) // ビルドエラー(そんなコンストラクタは定義されていないと怒られる)
import Foundation
String(format: "%02d時%02d分", 8, 15) // ビルドエラーにならない
// 結果:"08時15分"

Foundationフレームワークをインポートすると挙動が変化するクラスもある

Foundationフレームワークをインポートすると、Foundationフレームワークで定義されているクラスが使えるようになったり、Swiftフレームワークで既に定義されているクラスに対して機能が補完されたりするということを説明しました。

これはありがたいことですが、実はFoundationフレームワークをインポートする前と後で、Stringクラスの一部のメソッドの挙動が変化してしまうという、ちょっと危険な仕様も存在します。

"".contains("") // true
"a".contains("") // true
"a".contains("a") // true
"" == "" // true
import Foundation

"".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クラスは同じものとして扱われます。

import Foundation

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プログラマの質の違いに現れるんじゃないかってことで、今後も積極的に気になった部分は深掘りしていこうと思います。

-Swift

© 2024 ヂまるBlog