Cocoa デザインパターンの採用


うまく設計された、弾力性のあるアプリを書くことへの一つの援助は、Cocoa の確立されたデザインパターンを使用することです。これらのパターンの多くは、Objective-C で定義されたクラスに依存しています。Objective-C との Swift の相互運用性のため、Swift のコードでこれらの一般的なパターンを利用することができます。多くの場合、Swift 言語の機能を既存の Cocoa パターンを拡張、簡素化し、それらをより強力で使いやすくします。


デリゲート化


Swift と Objective-C のいずれにおいても、デリゲート化は多くの場合、相互作用と適合するデリゲート・プロパティを定義するプロトコルで表されます。ただ Objective-C のように、デリゲートが応答しないメッセージを送信する前に、それがセレクタに応答するかどうかをデリゲートに聞いてください。Swift では、optional の連鎖を使用して、おそらく nil オブジェクトに対して optional のプロトコルメソッドを呼び出して if-let 構文を使うと、結果を開封する可能性があります。以下に示すコードリストは、それ以降のプロセスを示しています。


  1. myDelegatenil でないことをチェックして下さい。
  2. myDelegate が、window:willUseFullScreenContentSize: メソッドを実装していることをチェックして下さい。
  3. 1と2が当てはまる場合、このメソッドを呼び出し、fullScreenSize という名前の値にメソッドの結果を代入します。
  4. メソッドの戻り値を印刷します。

    << SWIFT >>

  1. class MyDelegate: NSObject, NSWindowDelegate {
  2.        func window(_ NSWindow, willUseFullScreenContentSize proposedSize:
    NSSize) -> NSSize {
  3.                return proposedSize
  4.        }
  5. }
  6. myWindow.delegate = MyDelegate()
  7. if let fullScreenSize = myWindow.delegate?.window(myWindow,
    willUseFullScreenContentSize: mySize) {
  8.        print(NSStringFromSize(fullScreenSize))
  9. }


遅延した初期化


遅延したプロパティ は、プロパティが最初にアクセスされたときにのみ基礎値が初期化されるプロパティです。遅延したプロパティは、プロパティの初期値が複雑な、または計算コストの高い設定を必要とする場合や、インスタンスの初期化が完了するまで決定できない場合に便利です。


Objective-C では、その値が nil の場合、基礎となるインスタンス変数が条件付きで初期化されるように、プロパティはその合成された getter メソッドをオーバーライドできます。


    <<OBJECTIVE-C>>

  1. @property NSXMLDocument *XML;
  2. - (NSXMLDocument *)XML {
  3.         if (_XML == nil) {
  4.                 _XML = [[NSXMLDocument alloc] initWithContentsOfURL:[[Bundle mainBundle] URLForResource:@"/path/to/resource" withExtension:@"xml"] options:0 error:nil];
  5.         }
  6.         return _XML;
  7. }


Swift では、lazy 修飾子を使用して、初期値を持つ格納されたプロパティを宣言し、プロパティが初めてアクセスされたときにのみ評価される初期値を計算する式を持つことができます。


    << SWIFT >>

    lazy var XML: XMLDocument = try! XMLDocument(contentsOf:
    Bundle.main.url(forResource: "document", withExtension: "xml")!)



遅延したプロパティは、完全に初期化されたインスタンスにアクセスする時にのみ計算されるため、そのデフォルトの値の初期化式で定数または変数プロパティにアクセスします。


    << SWIFT >>

  1. var pattern: String
  2. lazy var regex: NSRegularExpression = try! NSRegularExpression(pattern:
    self.pattern, options: [])


初期化以上の追加設定が必要な値の場合、プロパティのデフォルト値を、完全に初期化された値を返す、self を評価するクロージャに割り当てることができます。


    << SWIFT >>

  1. lazy var currencyFormatter: NumberFormatter = {
  2.         let formatter = NumberFormatter()
  3.         formatter.numberStyle = .currency
  4.         formatter.currencySymbol = "¤"
  5.         return formatter
  6. }()


注意: 遅延したプロパティがまだ初期化されておらず、同時に複数のスレッドによってアクセスされている場合、プロパティが一度だけ初期化されるという保証はありません。


詳細については、Swift プログラミング言語(Swift 4.0.3)遅延した格納されたプロパティ を参照してください。


エラー処理


Cocoa では、エラーを生成するメソッドは最後のパラメータとして NSError ポインタパラメータをとり、このパラメータは、エラーが発生した場合にその引数に NSError オブジェクトを設定します。Swift は、エラーを生成する Objective-C メソッドを、Swift 独自のエラー処理機能に基づいてエラーを throw するメソッドに自動的に変換します。


注意: デリゲートメソッドや NSError オブジェクト引数を使用して補完ハンドラを使用するメソッドのように、エラーを 消費する メソッドは、Swift によって import されたときに、throw するメソッドにはなりません。


たとえば、NSFileManager の、以下の Objective-C メソッドを考えてみましょう。


    <<OBJECTIVE-C>>

  1. - (BOOL)removeItemAtURL:(NSURL *)URL
  2.                 error:(NSError **)error;


Swift では、これは以下のように import されます。


    << SWIFT >>

    func removeItem(at: URL) throws



removeItem(at:) メソッドは Swift によって Void の戻り値型で、error パラメータのない、throws 宣言とともに import されていることに注意してください。


Objective-C メソッドの最後の非ブロックパラメータが NSError ** 型の場合、Swift はそれを throws キーワードで置き換えて、メソッドがエラーを throw できることを示します。Objective-C のメソッドの error パラメータも最初のパラメータである場合、"WithError" または "AndReturnError" という接尾辞があれば、セレクタの最初の部分からそれを削除して Swift はメソッド名をさらに簡素化しようとします。他のメソッドが結果のセレクタで宣言されている場合、メソッド名は変更されません。


Objective-C メソッドがエラーを発生し、メソッド呼び出しの成功または失敗を示す BOOL 値を返した場合、Swift は関数の戻り値の型を Void に変更します。同様に、Objective-C メソッドがエラーを生成する際、メソッド呼び出しの失敗を示すために nil 値を返す場合、Swift は関数の戻り値の型を optional でない型に変更します。


それ以外で、約束が推測できない場合、メソッドはそのまま残されます。


注意: NSError を生成する Objective-C メソッド宣言で NS_SWIFT_NOTHROW マクロを使用して、throw するメソッドとして Swift によって import されないようにして下さい。


エラーの catch と処理


Objective-C では、エラー処理はオプトイン (opt-in) で、つまり、エラーポインタが提供されていない限り、メソッドの呼び出しによって生成されたエラーは無視されます。Swift では、throw するメソッドを呼び出すには、明示的なエラー処理が必要です。


Objective-C でメソッドを呼び出すときにエラーを処理する方法の例を以下に示します。


    <<OBJECTIVE-C>>

  1. NSFileManager *fileManager = [NSFileManager defaultManager];
  2. NSURL *fromURL = [NSURL fileURLWithPath:@"/path/to/old"];
  3. NSURL *toURL = [NSURL fileURLWithPath:@"/path/to/new"];
  4. NSError *error = nil;
  5. BOOL success = [fileManager moveItemAtURL:fromURL toURL:toURL error:&error];
  6. if (!success) {
  7.         NSLog(@"Error: %@", error.domain);
  8. }


Swift では、これと同等のコードは以下のとおりです:


    << SWIFT >>

  1. let fileManager = FileManager.default
  2. let fromURL = URL(fileURLWithPath: "/path/to/old")
  3. let toURL = URL(fileURLWithPath: "/path/to/new")
  4. do {
  5.         try fileManager.moveItem(at: fromURL, to: toURL)
  6. } catch let error as NSError {
  7.         print("Error: \(error.domain)")
  8. }


さらに、特定のエラーコードと一致する catch 句を使用すると、起こりうるエラーの状態を区別するのに便利です。


    << SWIFT >>

  1. do {
  2.         try fileManager.moveItem(at: fromURL, to: toURL)
  3. } catch CocoaError.fileNoSuchFile {
  4.         print("Error: no such file exists")
  5. } catch CocoaError.fileReadUnsupportedScheme {
  6.         print("Error: unsupported scheme (should be 'file://')")
  7. }


エラーを Optional の値に変換する


Objective-C では、特定のエラーが発生したのではなく、エラーがあったかどうかだけを気にするときに、error パラメータに NULL を渡します。Swift では、try? と書いて、throw する式を optional の値を返す式に変更し、その値が nil かどうかをチェックします。


たとえば、NSFileManager インスタンスメソッドの URL(for:in:appropriateForURL:create:) は、指定された検索パスとドメインに URL を返し、適切なURLが存在せず、作成できない場合はエラーを生成します。Objective-C では、メソッドの成功または失敗は、NSURL オブジェクトが返されるかどうかによって決まります。


    <<OBJECTIVE-C>>

  1. NSFileManager *fileManager = [NSFileManager defaultManager];
  2. NSURL *tmpURL = [fileManager URLForDirectory:NSCachesDirectory
  3.                         inDomain:NSUserDomainMask
  4.                 appropriateForURL:nil
  5.                         create:YES
  6.                         error:nil];
  7. if (tmpURL != nil) {
  8.         // ...
  9. }


Swift では同じ事を以下のようにできます:


    << SWIFT >>

  1. let fileManager = FileManager.default
  2. if let tmpURL = try? fileManager.url(for: .cachesDirectory, in: .userDomainMask,
    appropriateFor: nil, create: true) {
  3.         // ...
  4. }


エラーを throw する


Objective-C メソッドでエラーが発生した場合は、そのエラーを使用してそのメソッドのエラーポインタ引数を設定します。


    <<OBJECTIVE-C>>

  1. // an error occurred
  2. if (errorPtr) {
  3.         *errorPtr = [NSError errorWithDomain:NSURLErrorDomain
  4.                         code:NSURLErrorCannotOpenFile
  5.                 userInfo:nil];
  6. }


Swift メソッドでエラーが発生すると、エラーが throw され、自動的に呼び出し元に伝播されます。


    << SWIFT >>

  1. // an error occurred
  2. throw NSError(domain: NSURLErrorDomain, code: NSURLErrorCannotOpenFile, userInfo:
    nil)


Objective-C コードがエラーを throw する Swift メソッドを呼び出すと、エラーはブリッジされた Objective-C メソッドのエラーポインタ引数に自動的に伝播されます。


たとえば、NSDocumentread(from:ofType:) メソッドを考えてみましょう。Objective-C では、このメソッドの最後のパラメータは NSError ** 型です。NSDocument の Swift のサブクラスでこのメソッドをオーバーライドすると、このメソッドはそのエラーパラメータを置き換えて代わりに throw します。


    << SWIFT >>

  1. class SerializedDocument: NSDocument {
  2.         static let ErrorDomain = "com.example.error.serialized-document"
  3.         var representedObject: [String: Any] = [:]
  4.         override func read(from fileWrapper: FileWrapper, ofType typeName: String)
    throws {
  5.                 guard let data = fileWrapper.regularFileContents else {
  6.                         throw NSError(domain: NSURLErrorDomain, code: NSURLErrorCannotOpenFile,
    userInfo: nil)
  7.                 }
  8.                 if case let JSON as [String: Any] = try JSONSerialization.jsonObject(with:
    data) {
  9.                         self.representedObject = JSON
  10.                 } else {
  11.                         throw NSError(domain: SerializedDocument.ErrorDomain, code: -1,
    userInfo: nil)
  12.                 }
  13.         }
  14. }


メソッドがドキュメントの通常のファイル内容を持つオブジェクトを作成できない場合は、NSError オブジェクトを throw します。メソッドが Swift コードから呼び出された場合、そのエラーはその呼び出し元の範囲に伝播されます。メソッドが Objective-C コードから呼び出された場合、エラーは代わりにエラーポインター引数を設定します。


Objective-C では、エラー処理は選択制 (opt-in) であり、つまり、エラーポインタを提供しない限り、メソッドを呼び出すことによって生成されるエラーは無視されます。Swift では、throw するメソッドを呼び出すには、明示的なエラー処理が必要です。


注意: Swift のエラー処理は Objective-C の例外処理に似ていますが、完全に別の機能です。Objective-C メソッドが実行時に例外を throw した場合、Swift は実行時エラーを引き起こします。Swift では Objective-C の例外から直接回復する方法はありません。例外処理の全ての動作は、Swift が使用する Objective-C コードで実装しなければなりません。


カスタムエラーの Catch と処理


Objective-C フレームワークは、カスタムエラードメインと列挙型を使用して、関連カテゴリのエラーをグループ化できます。


以下の例は、Objective-C の NS_ERROR_ENUM マクロを使用して定義されたカスタマイズされたエラー型を示しています。


    <<OBJECTIVE-C>>

  1. static NSString *const MyErrorDomain = @"com.example.MyErrorDomain";
  2. typedef NS_ERROR_ENUM(MyErrorDomain, MyError) {
  3.         specificError1 = 0,
  4.         specificError2 = 1
  5. };


以下の例では、Swift でカスタムエラー型を使用してエラーを生成する方法を示します。


    << SWIFT >>

  1. func customThrow() throws {
  2.         throw NSError(
  3.                 domain: MyErrorDomain,
  4.                 code: MyError.specificError2.rawValue,
  5.                 userInfo: [
  6.                 NSLocalizedDescriptionKey: "A customized error from MyErrorDomain."
  7.                 ]
  8.         )
  9. }
  10. do {
  11.         try customThrow()
  12. } catch MyError.specificError1 {
  13.         print("Caught specific error #1")
  14. } catch let error as MyError where error.code == .specificError2 {
  15.         print("Caught specific error #2, ", error.localizedDescription)
  16.         // Prints "Caught specific error #2. A customized error from MyErrorDomain."
  17. } let error {
  18.         fatalError("Some other error: \(error)")
  19. }


キー値の監視


キー値監視は、オブジェクトが他のオブジェクトの指定したプロパティへの変更を通知されるようにするメカニズムです。クラスが NSObject クラスから継承するかぎり、Swift クラスでキー値監視を使用することができます。Swift にキー値監視を実装するためには、以下の2つの手順を踏んで下さい。


  1. 監視したいプロパティにどれでも、dynamic の修飾子と objc 属性を追加します。dynamic の詳細については、動的な送出を要求 を参照してください。

    1. << SWIFT >>

    2. class MyObjectToObserve: NSObject {
    3.        dynamic var myDate = NSDate()
    4.        func updateDate() {
    5.                myDate = NSDate()
    6.        }
    7. }


  2. キーパスに監視者を作成し、observe(_:options:changeHandler) メソッドを呼び出します。キーパスの詳細については、キーとキーパス を参照してください。

    1. << SWIFT >>

    2. class MyObserver: NSObject {
    3.         @objc var objectToObserve: MyObjectToObserve
    4.         var observation: NSKeyValueObservation?
    5.         init(object: MyObjectToObserve) {
    6.                objectToObserve = object
    7.                 super.init()
    8.         observation = observe(\.objectToObserve.myDate) { object, change in
    9.                         print("Observed a change to \(object.objectToObserve).myDate,
      updated to: \(object.objectToObserve.myDate)")
    10.                 }
    11.         }
    12. }
    13. let observed = MyObjectToObserve()
    14. let observer = MyObserver(object: observed)
    15. observed.updateDate()



ターゲット・アクション


ターゲット・アクションは、特定のイベントが発生したときに、あるオブジェクトが別のオブジェクトにメッセージを送信する一般的な Cocoa のデザインパターンです。ターゲット・アクション・モデルは Swift と Objective-C で基本的に似ています。Swift では、Selector 型を使用して Objective-C セレクタを参照します。Swift コードでターゲット・アクションを使用する例については、セレクタ を参照してください。


シングルトン


シングルトンは、オブジェクトのグローバルにアクセス可能な共有インスタンスを提供します。サウンドエフェクトを再生するオーディオチャンネルや HTTP リクエストを作成するネットワークマネージャなど、アプリ全体で共有されるリソースまたはサービスに統一されたアクセスポイントを提供する方法として、独自のシングルトンを作成できます。


Objective-C では、dispatch_once 関数の呼び出しで初期化を包み込むことによって、シングルトン・オブジェクトのインスタンスを1つだけ作成されると確信でき、アプリの寿命中にブロックを1回だけ実行します。


    <<OBJECTIVE-C>>

  1. + (instancetype)sharedInstance {
  2.         static id _sharedInstance = nil;
  3.         static dispatch_once_t onceToken;
  4.         dispatch_once(&onceToken, ^{
  5.                 _sharedInstance = [[self alloc] init];
  6.         });
  7.         return _sharedInstance;
  8. }


Swift では、静的型プロパティを使用でき、それは、複数のスレッドで同時にアクセスされた場合でも、一度だけ遅延して初期化されることが保証されています。


    << SWIFT >>

  1. class Singleton {
  2.         static let sharedInstance = Singleton()
  3. }


初期化以上の追加の設定を行う必要がある場合は、クロージャの呼び出しの結果をグローバル定数に代入することができます。


    << SWIFT >>

  1. class Singleton {
  2.         static let sharedInstance: Singleton = {
  3.                 let instance = Singleton()
  4.                 // setup code
  5.                 return instance
  6.         }()
  7. }


詳細については、Swift プログラミング言語(Swift 4.0.3)型プロパティ を参照してください。


Introspection(内省)


Objective-C では、オブジェクトが特定のクラス型であるかどうかを確認するには、isKindOfClass: メソッドを使い、オブジェクトが指定されたプロトコルに準拠しているかどうかを確認するために conformsToProtocol: メソッドを使って下さい。Swift では、型を確認するために is 演算子を使ってこのタスクを達成するか、または、as? 演算子を使用してその型にダウンキャストします。


is 演算子を使用して、インスタンスが特定のサブクラス型であるかどうかを確認できます。インスタンスがそのサブクラス型であれば is 演算子は true を返し、そうでない場合、false を返します。


    << SWIFT >>

  1. if object is UIButton {
  2.        // object is of type UIButton
  3. } else {
  4.        // object is not of type UIButton
  5. }


また、as? 演算子を使用して、サブクラス型にダウンキャストしようと try することができます。as? 演算子は、if-let 文を使用して、定数に結合できる optional の値を返します。


    << SWIFT >>

  1. if let button = object as? UIButton {
  2.        // object is successfully cast to type UIButton and bound to button
  3. } else {
  4.        // object could not be cast to type UIButton
  5. }


詳細については、Swift プログラミング言語 (Swift 4.0.3)型キャスト を参照してください。


プロトコルを確認し、それにキャストするには、クラスへの確認とキャストとまったく同じ構文に従います。以下に as? 演算子を使用し、プロトコルに準拠しているかを確認する例を挙げます。


    << SWIFT >>

  1. if let dataSource = object as? UITableViewDataSource {
  2.        // object conforms to UITableViewDataSource and is bound to dataSource
  3. } else {
  4.        // object not conform to UITableViewDataSource
  5. }


このキャストをした後、dataSource 定数は UITableViewDataSource 型であり、UITableViewDataSource プロトコルで定義されたメソッドを呼び出し、プロパティにアクセスすることのみができます。他の操作を実行するために、別の型に戻ってそれをキャストしなければなりません。


詳細については、Swift プログラミング言語(Swift 4.0.3)プロトコル を参照してください。


連載


連載 (Serialization) を使用すると、アプリ内のオブジェクトを JSON やプロパティリストのようなアーキテクチャに依存しない表現にコード化および復号化できます。これらの表現は、その後ファイルに書き込まれるか、ローカルまたはネットワークを介して別のプロセスに送信されます。


Objective-C では、Foundation フレームワーククラスの NSJSONSerialiation および NSPropertyListSerialization を使用して、復号された JSON またはプロパティリストの連載値 (通常は NSDictionary<NSString *,id> 型のオブジェクト) からオブジェクトを初期化できます。


Swift では、標準ライブラリはデータのコード化と複合化に関する標準化されたアプローチを定義しています。このアプローチは、型を Encodable または Decodable プロトコルに適合させることによって、または両方のプロトコルに準拠させるための近道として Codable に準拠させることによって採用されます。Foundation フレームワーククラス JSONncoderPropertyListEncoder を使用して、インスタンスを JSON またはプロパティリストデータに変換することができます。同様に、JSONDecoder クラスと PropertyListDecoder クラスを使用して、JSON またはプロパティリストデータからインスタンスを復号して初期化することができます。


たとえば、Web サーバーと通信するアプリは、以下のように食料品の JSON 表現を受け取るでしょう。


  1. {
  2.         "name": "Banana",
  3.         "points": 200,
  4.         "description": "A banana grown in Ecuador.",
  5.         "varieties": [
  6.                 "yellow",
  7.                 "green",
  8.                 "brown"
  9.         ]
  10. }


食料品を表す Swift の型を記述する方法は、エンコーダ (encoder、暗号機) とデコーダ (decoder、復号器) を提供する連載フォーマットで使用できます。


    << SWIFT >>

  1. struct GroceryProduct: Codable {
  2.         let name: String
  3.         let points: Int
  4.         let description: String
  5.         let varieties: [String]
  6. }


JSON 表現から GroceryProduct を作成するには、JSONDecoder インスタンスを作成し、GroceryProduct.self 型と共に JSON データを渡します。


    << SWIFT >>

  1. let json = """
  2.         {
  3.                 "name": "Banana",
  4.                 "points": 200,
  5.                 "description": "A banana grown in Ecuador.",
  6.                 "varieties": [
  7.                         "yellow",
  8.                         "green",
  9.                         "brown"
  10.                 ]
  11.         }
  12. """.data(using: .utf8)!
  13. let decoder = JSONDecoder()
  14. let banana = try decoder.decode(GroceryProduct.self, from: json)
  15. print("\(banana.name) (\(banana.points) points): \(banana.description)")
  16. // Prints "Banana (200 points): A banana grown in Ecuador."


より複雑なカスタム型のコード化と復号の詳細については、カスタム型のエンコードとデコード を参照してください。JSON のコード化と復号化の詳細については、カスタム型での JSON の使用 を参照してください。


ローカライズ


Objective-C では、文字列をローカライズするため、通常はマクロの NSLocalizedString ファミリを使用します。これらは NSLocalizedString、NSLocalizedStringFromTable、NSLocalizedStringFromTableInBundle、および NSLocalizedStringWithDefaultValue を含みます。Swift では、これらのマクロの機能は、単一の関数 NSLocalizedString(_:tableName:bundle:value:comment:) を介して利用できます。


各 Objective-C マクロに対応する別々の関数を定義するよりむしろ、Swift の NSLocalizedString(_:tableName:bundle:value:) 関数は、必要に応じてオーバーライドできるように tableName、bundle、 および value 引数のデフォルト値を指定します。


たとえば、アプリ内のローカライズされた文字列の最も一般的な形式は、ローカライズ化キーとコメントだけが必要です。


    << SWIFT >>

  1. let format = NSLocalizedString("Hello, %@!", comment: "Hello, {given name}!")
  2. let name = "Mei"
  3. let greeting = String(format: format, arguments: [name as CVarArg])
  4. print(greeting)
  5. // Prints "Hello, Mei!"


または、別のバンドルからローカライズ化リソースを使用するために、アプリのもっと複雑な使用が必要になることがあります。


    << SWIFT >>

  1. if let path = Bundle.main.path(forResource: "Localization", ofType: "strings",
    inDirectory: nil, forLocalization: "ja"),
  2.         let bundle = Bundle(path: path) {
  3.         let translation = NSLocalizedString("Hello", bundle: bundle, comment: "")
  4.         print(translation)
  5. }
  6. // Prints "こんにちは"


詳細については、国際化およびローカライズ化ガイド を参照してください。



自動解放プール


自動解放プールブロックを使用すると、オブジェクトをすぐに割り当て解除せずに所有権を放棄できます。通常は、独自の自動解放プールブロックを作成する必要はありませんが、セカンダリスレッドが生じる場合や、そうした方がいい場合、多くの一時的なオブジェクトを作成するループを書く場合など、必要な場合があります。


Objective-C では、自動解放プールブロックは @autoreleasepool を使ってマークされます。Swift では、autoreleasepool(_:) 関数を使用して自動解放プールブロック内でクロージャを実行できます。


    << SWIFT >>

  1. import Foundation
  2. autoreleasepool {
  3.         // code that creates autoreleased objects.
  4. }


詳細については、高度なメモリ管理プログラミングガイド を参照してください。



API の利用


一部のクラスとメソッドは、アプリがターゲットとするすべてのプラットフォームのすべてのバージョンで使用できるわけではありません。アプリが機能の違いに対応できるようにするには、それらの API が利用できるか確認します。


Objective-C では、respondsToSelector: および instancesRespondToSelector: メソッドを使用して、クラスまたはインスタンスメソッドが利用できるか確認します。確認を行わないと、メソッドの呼び出しは NSInvalidArgumentException "インスタンスに送信されたセレクタが認識できません" 例外を throw します。たとえば、requestWhenInUseAuthorization メソッドは、iOS 8.0 および macOS 10.10 以降の CLLocationManager のインスタンスでのみ使用できます。


    <<OBJECTIVE-C>>

  1. if ([CLLocationManager
    instancesRespondToSelector:@selector(requestWhenInUseAuthorization)]) {
  2.     // Method is available for use.
  3. } else {
  4.     // Method is not available.
  5. }


Swift では、ターゲットのプラットフォーム上のバージョンでサポートされているわけでないメソッドを呼び出そうとすると、コンパイル時エラーが発生します。


前の例は Swift ではこうなります:


    << SWIFT >>

  1. let locationManager = CLLocationManager()
  2. locationManager.requestWhenInUseAuthorization()
  3. // error: only available on iOS 8.0 or newer


アプリが iOS 8.0 より前のバージョンまたは macOS 10.10 より前のバージョンをターゲットにしている場合、 requestWhenInUseAuthorization() は使用できないため、コンパイラはエラーを報告します。


Swift コードは、実行時 の条件として API の利用可能性を使用できます。利用の確認は、if、guard、 または while 文のような制御フロー文の条件の代わりに使用できます。


前の例では、実行時にメソッドが使用可能な場合のみ、if 文で利用可能性をチェックして requestWhenInUseAuthorization() を呼び出すことができます。


    << SWIFT >>

  1. let locationManager = CLLocationManager()
  2. if #available(iOS 8.0, macOS 10.10, *) {
  3.         locationManager.requestWhenInUseAuthorization()
  4. }


あるいは、現在のターゲットが指定された要件を満たさない限り、範囲外に出てくる guard 文で利用可能性を確認することもできます。このアプローチは、異なるプラットフォーム機能を扱うロジックを簡素化します。


    << SWIFT >>

  1. let locationManager = CLLocationManager()
  2. guard #available(iOS 8.0, macOS 10.10, *) else { return }
  3. locationManager.requestWhenInUseAuthorization()


それぞれのプラットフォーム引数は、以下にリストされているプラットフォーム名の1つからなり、対応するバージョン番号が続きます。最後の引数はアスタリスク(*) で、将来ありうるプラットフォームを処理するために使用されます。


プラットフォーム名


すべての Cocoa API は利用情報を提供するので、あなたが書いたコードは、アプリがターゲットとしているどのプラットフォーム上でも期待どおりに動作することを確信できます。


宣言に @available 属性で注釈することで、独自の API の利用可能性を表すことができます。@available 属性は、#available の実行時確認と同じ構文を使用し、プラットフォームのバージョン要件はコンマで区切られた引数として提供されます。


例えば:


    << SWIFT >>

  1. @available(iOS 8.0, macOS 10.10, *)
  2. func useShinyNewFeature() {
  3.         // ...
  4. }


注意: @available 属性で注釈されたメソッドは、明示的な利用確認を使用せずに、指定されたプラットフォーム要件で使用可能な API を安全に使用できます。


コマンドライン引数の処理


macOS では、通常 Dock または Launchpad のアイコンをクリックするか、Finder からそのアイコンをダブルクリックしてアプリを開きます。ただし、プログラムでアプリを開き、ターミナルからコマンドライン引数を渡すこともできます。


起動時に指定されたコマンドライン引数のリストを取得するには、CommandLine.arguments の型プロパティにアクセスします。


$ /path/to/app --argumentName value


    << SWIFT >>

  1. for argument in CommandLine.arguments {
  2.         print(argument)
  3. }
  4. // prints "/path/to/app"
  5. // prints "--argumentName"
  6. // prints "value"


CommandLine.arguments の最初の要素は、実行可能ファイルへのパスです。起動時に指定されたコマンドライン引数は、CommandLine.arguments[1] で始まります。


注意: CommandLine.arguments を使用して引数にアクセスすることは、ProcessInfo.processInfoarguments プロパティにアクセスすることと同じです。




前:Cocoa フレームワークでの作業 次:C の API との相互作用
目次
Xcode 9 の新機能

Swift:はじめに
Swift Programming Language
Swift Blog より

  • はじめに(Part I)
  • 基本設定
  • Swift 環境の設定
    Swift のインポートプロセスの理解
  • 相互運用性(Part II)
  • Objective-C API との相互作用
  • 初期化
  • クラスファクトリメソッドとコンビニエンスイニシャライザ
    失敗可能な初期化
    プロパティへのアクセス
    メソッドでの作業
  • id の互換性
  • Any のダウンキャスト
    動的なメソッドの参照
    認識されないセレクタと optional の連鎖
  • ヌル可能性 (Nullabity) と optionals
  • ヌル可能性のない (nonnullable) オブジェクトに Optional をブリッジする
    プロトコルで修飾されたクラス
    軽量級の汎用
    拡張機能
  • クロージャ
  • self をキャプチャする時の強い循環参照を回避する
  • オブジェクトの比較
  • Hash する
  • Swift の型の互換性
  • Objective-C で Swift インターフェースの構成
    動的な送出を要求
  • セレクタ
  • Objective-C メソッドの安全でない呼び出し
    キーとキーパス
  • Swift のクラスとプロトコルの書き方及び Objective-C の動作
  • Objective-C のクラスからの継承
  • NSCoding
    プロトコルの採用
    イニシャライザとデイニシャライザを書く
    Objective-C API で Swift クラス名を使用する
  • Interface Builder との統合
  • アウトレットとアクションを使った作業
    ライブレンダリング
  • プロパティ属性の指定
  • Strong と Weak
    読み/書き可能と読み取り専用
    コピーの意味
    コアデータ管理オブジェクトサブクラスの実装
    プロトコルの宣言
  • Cocoa フレームワークでの作業
  • Foundation
  • ブリッジ型
  • 名前の変更された型
  • 文字列

    配列
    セット
    Dictionary
  • Core Foundation
  • 再マッピングされた型
    メモリ管理オブジェクト
    管理されないオブジェクト
    統合ログオン
    Cocoa 構造体
  • Cocoa デザインパターンの採用
  • デリゲート化
    遅延した初期化
  • エラー処理
  • エラーの catch と処理
    エラーを Optional の値に変換する
    エラーを throw する
    カスタムエラーの Catch と処理
    キー値の監視
    ターゲット・アクション
    シングルトン
    Introspection(内省)
  • 連載
  • ローカライズ
    自動解放プール
    API の利用
    コマンドライン引数の処理
  • C の API との相互作用
  • 原始的な型
  • グローバル定数
  • import された定数の列挙体と構造体
  • 関数
  • 可変個引数の関数
  • 構造体
  • 型メンバとして関数を import
    列挙型
    Option のセット
    ユニオン
    ビットフィールド
    名前のない構造体と union のフィールド
  • ポインタ
  • 定数ポインタ
    可変ポインタ
    自動解放ポインタ
    関数ポインタ
    バッファポインタ
    ヌルポインタ
    ポインタの計算
    データ型サイズの計算
    1回限りの初期化
  • プリプロセッサの指令
  • 簡単なマクロ
    複雑なマクロ
    条件付きコンパイルブロック
  • うまく組み合わせる(part III)
  • 同じプロジェクトでの Swift と Objective-C
  • 「うまく組み合わせる」概観
  • 同じアプリターゲット内からコードを import
  • Objective-C から Swift への import
    Swift から Objective-C への import
  • 同じフレームワークターゲット内からコードを import
  • Objective-C から Swift への import
    Swift から Objective-C への import
    外部フレームワークの import
  • Objective-C からの Swift の使い方
  • Objective-C ヘッダでの Swift クラスまたはプロトコルの参照
    Objective-C クラスで採用可能な Swift プロトコルを宣言
    Objective-C の実装での Swift プロトコルの採用
    Objective-C から使用できる Swift のエラー型の宣言
  • Objective-C インターフェイス用に Swift 名をオーバーライド
  • クラスファクトリメソッド
    列挙型
    Objective-C 宣言を洗練する
    Swift で Objective-C インターフェイスを使用できないようにする
    Objective-C API へ利用可能性情報の追加
    プロダクトモジュールの命名
    トラブルシューティングのヒントと注意
  • 移行(Part IV)
  • Objective-C から Swift への移行
  • 移行のための Objective-C コードの準備
  • 移行プロセス
  • はじめる前に
    作業中に
    見終わったら
    トラブルシューティングのヒントと注意
  • 更新履歴
  • マニュアルの更新履歴












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)












    トップへ(Swift を Cocoa と Objective-C と使う)