Cocoa フレームワークでの作業
Objective-C との相互運用性の一環として、Swift は Cocoa フレームワークを扱う便利で効率的な方法を提供します。
Swift は、自動的にいくつかの Objective-C の型を Swift の型に変換し、いくつかの Swift の型を Objective-C の型にに変換します。Objective-C と Swift の間で変換できる型は、ブリッジ 型と呼ばれます。たとえば、Swift コードでは、NSString パラメータをとるように宣言された Objective-C メソッドに String 値を渡すことができます。さらに、Foundation、AppKit、UIKit などの Cocoa フレームワークの多くは、Swift で、より自然な API に改良しています。たとえば、NSCoder の decodeObjectOfClass(_:forKey :) メソッドは Swift の汎用を使用してより強力な型シグニチャを提供します。
Foundation
Foundation フレームワークは、データ保管、テキスト処理、日付と時刻、並べ替えとフィルタリング、永続性、及びネットワークを含む、アプリやフレームワークの基本機能を提供します。
ブリッジ型
Swift の Foundation オーバーレイは、以下のObjective-C 参照型に対して、以下のブリッジ値の型を提供します。
Objective-C 参照型 | Swift 値型 |
---|---|
NSAffineTransform | AffineTransform |
NSArray | Array |
NSCalendar | Calendar |
NSCharacterSet | CharacterSet |
NSData | Data |
NSDateComponents | DateComponents |
NSDateInterval | DateInterval |
NSDate | Date |
NSDecimalNumber | Decimal |
NSDictionary | Dictionary |
NSIndexPath | IndexPath |
NSIndexSet | IndexSet |
NSLocale | Locale |
NSMeasurement | Measurement |
NSNotification | Notification |
NSNumber | Swift numeric types (Int, Float, など) |
NSPersonNameComponents | PersonNameComponents |
NSSet | Set |
NSString | String |
NSTimeZone | TimeZone |
NSURLComponents | URLComponents |
NSURLQueryItem | URLQueryItem |
NSURL | URL |
NSURLComponents | URLComponents |
NSURLQueryItem | URLQueryItem |
NSURLRequest | URLRequest |
NSUUID | UUID |
これらの値型は、対応する参照型と同じ機能を持ちます。不変および可変サブクラスを含むクラスクラスタは、単一の値型にブリッジされます。Swift コードは var と let を使用して可変性を制御するので、両方のクラスは必要ありません。対応する参照型は、元ののクラス名に NS 接頭辞をしてアクセスできます。
ブリッジされた Objective-C 参照型を使用できる場所であればどこでも、代わりに Swift の値型を使用できます。これにより、参照型の実装で利用可能な機能を Swift コードに自然な形で利用できるようになります。このため、自分のコードで直接ブリッジされた参照型を使用する必要はほとんどありません。実際、Swift コードが Objective-C API を import するとき、importer は Objective-C の参照型を、対応する値型に置き換えます。同様に、Objective-C コードが Swift API を import する場合、importer はまた Swift 値型を、対応する Objective-C の参照型に置き換えます。
参照型よりも値型が上回る主な利点の1つは、コードを推論しやすくなることです。値型の詳細については、Swift プログラミング言語(Swift 4.0.3) の クラスと構造体、および WWDC 2015 セッション 414 Swift での値型によるより優れたアプリのビルド を参照してください。
ブリッジされた Foundation オブジェクトを使用する必要がある場合は、as 型キャスト演算子を使用してブリッジされた型間でキャストできます。
名前の変更された型
Swift Foundation のオーバーレイは、クラスとプロトコル、および関連する列挙型と定数の名前を変更します。
import された Foundation クラスおよびプロトコルは、以下の例外を除いて NS 接頭辞を削除します。
- Objective-C に固有のクラス、または NSObject、NSAutoreleasePool、NSException、 および NSProxy などの Objective-C 実行環境に本質的に関連するクラス
- NSBackgroundActivity、NSUserNotification、 および NSXPCConnection などのプラットフォーム固有のクラス
- NSString、NSDictionary、 および NSURL などの ブリッジ型 で説明した、値型と同等のものを持つクラス
- NSAttributedString、NSRegularExpression、 および NSPredicate などの、同等の値型を持たないが、近い将来それを持つように計画されているクラス
Foundation クラスは、しばしば列挙型または定数型を宣言します。これらの型を import する場合、Swift はそれらを関連型の入れ子にされた型に移動します。たとえば、NSJSONReadingOptions のオプションセットは JSONSerialization.ReadingOptions として import されます。
文字列
Swift は、String 型と NSString クラスの間をブリッジします。NSString オブジェクトを作成するには、as 演算子を使用して String 値をキャストします。また、型注釈を明示的に提供して、文字列リテラルを使用する事により NSString オブジェクトを作成することもできます。
- import Foundation
- let string: String = "abc"
- let bridgedString: NSString = string as NSString
- let stringLiteral: NSString = "123"
- if let integerValue = Int(stringLiteral as String) {
-         print("\(stringLiteral) is the integer \(integerValue)")
- }
- // Prints "123 is the integer 123"
<< SWIFT >>
数
Swift は、NSNumber クラスと Int、Double、 および Bool などの Swift の数値型の間のブリッジを行います。
NSNumber オブジェクトを作成するには、as 演算子を使用して Swift の数値をキャストします。NSNumber はさまざまな種類の型を含んでいるので、Swift の数値型にキャストするときには as? 演算子を使用しなければなりません。例えば、数値の 500 を表す NSNumber 値を Swift の Int8 型にキャストするのは失敗し、nil が返ります。と言うのも、Int8 値の最大値は 127 を表すからです。
また、型注釈を明示的に提供し、浮動小数点、整数、またはブール値リテラルを使用して NSNumber オブジェクトを作成することもできます。
- import Foundation
- let number = 42
- let bridgedNumber: NSNumber = number as NSNumber
- let integerLiteral: NSNumber = 5
- let floatLiteral: NSNumber = 3.14159
- let booleanLiteral: NSNumber = true
<< SWIFT >>
配列
Swift は、Array 型と NSArray クラスとの間をブリッジします。パラメータ化された型を持つ NSArray オブジェクトから Swift 配列にブリッジすると、結果の配列の要素型もブリッジされます。NSArray オブジェクトがパラメータ化された型を指定しない場合、型 [Any] の Swift 配列にブリッジされます。
たとえば、以下の Objective-C 宣言を考えてみましょう。
- @property NSArray *objects;
- @property NSArray<NSDate *> *dates;
- - (NSArray<NSDate *> *)datesBeforeDate:(NSDate *)date;
- - (void)addDatesParsedFromTimestamps:(NSArray<NSString *> *)timestamps;
<<OBJECTIVE-C>>
Swift はこれを以下のように import します:
- var objects: [Any]
- var dates: [Date]
- func datesBeforeDate(date: Date) -> [Date]
- func addDatesParsedFromTimestamps(timestamps: [String])
<< SWIFT >>
上で概説した同じブリッジの規則に従って、Swift の配列リテラルから直接 NSArray オブジェクトを作成することもできます。NSArray オブジェクトとして明示的に定数または変数型を入力し、それを配列リテラルに割り当てると、Swift は Swift の配列の代わりに NSArray オブジェクトを作成します。
- let schoolSupplies: NSArray = ["Pencil", "Eraser", "Notebook"]
- // schoolSupplies is an NSArray object containing three values
<< SWIFT >>
セット
配列に加えて、Swift は Set 型と NSSet クラスの間をブリッジします。パラメータ化された型を持つ NSSet オブジェクトから Swift のセットにブリッジすると、結果のセットは Set<ObjectType> 型になります。NSSet オブジェクトがパラメータ化された型を指定していない場合、Set<AnyHashable> 型の Swift のセットにブリッジされます。
たとえば、以下の Objective-C 宣言を考えてみましょう。
- @property NSSet *objects;
- @property NSSet<NSString *> *words;
- - (NSSet<NSString *> *)wordsMatchingPredicate:(NSPredicate *)predicate;
- - (void)removeWords:(NSSet<NSString *> *)words;
<<OBJECTIVE-C>>
Swift は、以下のようにこれを import します:
- var objects: Set<AnyHashable>
- var words: Set<String>
- func wordsMatchingPredicate(predicate: NSPredicate) -> Set<String>
- func removeWords(words: Set<String>)
<< SWIFT >>
上で概説したのと同じブリッジの規則に従って、Swift の配列リテラルから直接 NSSet オブジェクトを作成することもできます。NSSet オブジェクトとして明示的に定数または変数型を入力し、それに配列リテラルを割り当てると、Swift は Swift のセットの代わりに NSSet オブジェクトを作成します。
- let amenities: NSSet = ["Sauna", "Steam Room", "Jacuzzi"]
- // amenities is an NSSet object containing three values
<< SWIFT >>
Dictionary
Swift はまた Dictionary 型と NSDictionary クラスとの間でもブリッジします。パラメーター化された型を持つ NSDictionary オブジェクトから Swift の dictionary にブリッジすると、結果の dictionary は [Key:Value] 型になります。NSDictionary オブジェクトがパラメータ化された型を指定していない場合、[AnyHashable:Any] 型の Swift dictionary にブリッジされます。
たとえば、以下の Objective-C の宣言を考えてみましょう:
- @property NSDictionary *keyedObjects;
- @property NSDictionary<NSURL *, NSData *> *cachedData;
- - (NSDictionary<NSURL *, NSNumber *> *)fileSizesForURLsWithSuffix:(NSString
*)suffix; - - (void)setCacheExpirations:(NSDictionary<NSURL *, NSDate *> *)expirations;
<<OBJECTIVE-C>>
Swift は、以下のようにこれを import します:
- var keyedObjects: [AnyHashable: Any]
- var cachedData: [URL: Data]
- func fileSizesForURLsWithSuffix(suffix: String) -> [URL: NSNumber]
- func setCacheExpirations(expirations: [URL: NSDate])
<< SWIFT >>
上で概説したのと同じブリッジの規則に従って、Swift dictionary リテラルから直接 NSDictionary オブジェクトを作成することもできます。NSDictionary オブジェクトとして明示的に定数または変数型を入力し、それに dictionary リテラルを割り当てると、Swift は Swift dictionary の代わりに NSDictionary オブジェクトを作成します。
- let medalRankings: NSDictionary = ["Gold": "1st Place", "Silver": "2nd Place",
"Bronze": "3rd Place"] - // medalRankings is an NSDictionary object containing three key-value pairs
<< SWIFT >>
Core Foundation
Core Foundation 型は Swift クラスとして import されます。メモリ管理の注釈が提供されている限り、Swift は、あなた自身をインスタンス化する、Core Foundation オブジェクトを含む Core Foundation オブジェクトのメモリを自動的に管理します。Swift では、自由通話でブリッジされた Foundation と Core Foundation 型の各ペアを互換性を持って使用できます。また、最初にブリッジする Foundation 型にキャストする場合、Swift 標準ライブラリに、いくつかの自由通話でブリッジされた Core Foundation 型もブリッジすることができます。
再マッピングされた型
Swift が、Core Foundation 型を import すると、コンパイラはこれらの型の名前を再マッピングします。Swift クラスは全て参照型で接尾語が冗長であるため、コンパイラは各型の名の末尾から Ref を削除します。
Core Foundation の CFTypeRef 型は完全に AnyObject 型に再マッピングします。CFTypeRef を使用するどこででも、今や、コード内では AnyObject を使用する必要があります。
メモリ管理オブジェクト
注釈付きの API から返された Core Foundation オブジェクトは、Swift で自動的にメモリ管理されており、CFRetain、CFRelease または CFAutorelease 関数をあなた自身で起動する必要はありません。
あなた独自の C 関数と Objective-C のメソッドから Core Foundation のオブジェクトを返すと、自動的にメモリ管理の呼び出しを挿入するため、CF_RETURNS_RETAINED または CF_RETURNS_NOT_RETAINED マクロのどちらかで注釈を付けられます。また、CF_IMPLICIT_BRIDGING_ENABLED マクロと CF_IMPLICIT_BRIDGING_DISABLED マクロを使用して、Core Foundation の所有権ポリシーの命名規則に従う C 関数宣言を囲んで、命名からメモリ管理を推測することもできます。
Core Foundation オブジェクトを間接的に返さない注釈付きの API のみを使用する場合は、この節の残りの部分をスキップできます。それ以外の場合は、管理されない Core Foundation オブジェクトでの操作を読み続けてください。
管理されないオブジェクト
Swift が、注釈されていない API を import する時は、コンパイラは返された Core Foundation オブジェクトのメモリを自動的に管理することはできません。Swift は、Unmanaged<Instance> 構造体にこれらの、返された Core Foundation のオブジェクトを包み込みます。すべての間接的に返された Core Foundation のオブジェクトも同様に管理されていません。例えば、ここで注釈なしの C 関数を取り上げましょう:
<<OBJECTIVE-C>>
CFStringRef StringByAddingTwoStrings(CFStringRef s1, CFStringRef s2)
そして、Swift は以下のようにこれを import します:
- func StringByAddingTwoStrings(_: CFString!, _: CFString!) -> Unmanaged<CFString>! {
-         // ...
- }
<< SWIFT >>
注釈なしの API から管理されないオブジェクトを受信した場合、それを使用して作業する前に、メモリ管理オブジェクトにすぐに変換する必要があります。そうすれば、Swift は、メモリ管理を出来るようになります。 Unmanaged<Instance> 構造体は、管理されていないオブジェクトを、takeUnretainedValue() と takeRetainedValue() のメモリ管理オブジェクトに変換するために2つのメソッドを提供します。これらのメソッドはどちらも、オリジナルで、オブジェクトの開封された型を返します。呼びだそうとする API が、オブジェクトを保持するのか保持しないのかに基づいて、どちらのメソッドを使用するかを選択して下さい。
例えば、上記に挙げた C の関数は、返す前に CFString オブジェクトを保持していないと仮定します。オブジェクトの使用を開始するには、takeUnretainedValue() 関数を使用して下さい。
- let memoryManagedResult = StringByAddingTwoStrings(str1, str2).takeUnretainedValue()
- // memoryManagedResult is a memory managed CFString
<< SWIFT >>
また、管理されないオブジェクトに対して retain()、release()、 および autorelease() メソッドを呼び出すこともできますが、この方法はお勧めしません。
詳細については、Core Foundation のためのメモリ管理プログラミングガイド の 所有権ポリシー を参照してください。
統合ログオン
統合されたログオンシステムは、システムのすべてのレベルを通じてメッセージするのをキャプチャするための API を提供し、Foundation フレームワークの NSLog 関数を置き換えるものです。統合ログオンは、iOS 10.0 以降、macOS 10.12 以降、tvOS 10.0 以降、および watchOS 3.0 以降で利用できます。
Swift では、os モジュールのサブモジュール log にある最上位レベルの os_log(_:dso:log:type:_:) 関数を使用して、統合ログオンシステムと対話できます。
- import os.log
- os_log("This is a log message.")
<< SWIFT >>
NSString または printf 形式の文字列と1つ以上の後続の引数を使用して、ログメッセージをフォーマットできます。
- let fileSize = 1234567890
- os_log("Finished downloading file. Size: %{iec-bytes}d", fileSize)
<< SWIFT >>
また、ログオン・イベントの重要度に応じてログ・メッセージを処理する方法を制御するために、Info、Debug、または Error のようなログオン・システムによって定義されたログ・レベルを指定することもできます。たとえば、役に立つかもしれないが、トラブルシューティングのエラーには不可欠ではない情報は、情報レベルに記録されます。
<< SWIFT >>
os_log("This is additional info that may be helpful for troubleshooting.", type:
.info)
特定のサブシステムにメッセージをログとして記録するには、サブシステムとカテゴリを指定して、新しい OSLog オブジェクトを作成し、それをパラメータとして os_log 関数に渡すことができます。
- let customLog = OSLog("com.your_company.your_subsystem_name.plist",
"your_category_name") - os_log("This is info that may be helpful during development or debugging.", log:
customLog, type: .debug)
<< SWIFT >>
統合ログオンシステムの詳細については、ログオン を参照してください。
Cocoa 構造体
Swift のコードから Objective-C のコードにブリッジするとき、Cocoa と Foundation からの組み込み構造体は NSValue インスタンスとしてブリッジされます。その結果、参照型のインスタンスのみを受け付ける Cocoa API 内の Swift から Objective-C 構造体を使用できます。これは、インスタンスの定義型が構造体型として Swift にブリッジされていても当てはまります。
以下の構造体は NSValue にブリッジされます:
- CATransform3D
- CLLocationCoordinate2D
- CGAffineTransform
- CGPoint
- CGRect
- CGSize
- CGVector
- CMTimeMapping
- CMTimeRange
- CMTime
- MKCoordinateSpan
- NSRange
- SCNMatrix4
- SCNVector3
- SCNVector4
- UIEdgeInsets
- UIOffset
前:Swift のクラスとプロトコルの書き方及び Objective-C の動作 次:Cocoa デザインパターンの採用