SwiftとObjective-Cのコードを1つのプロジェクトでつかう

こんにちは。モバイルファースト室の中村(@_nkmrh)です。

仕事でSwiftを使うことはまだないのでSwiftについて色々気になっている今日この頃です。

今回はSwiftObjective-C(以下、Obj-C)を1つのプロジェクト内でつかう方法と、両者の相違点について気になった点を紹介したいと思います。

Swift -> Obj-C

まず、SwiftからObj-Cを使う方法です。

SwiftからObj-Cを使うには、[product module name]-Bridging-Header.hを作成します。

※ [ProductModuleName]は通常ProductNameと同じです。ProductNameにアルファベット以外の文字を使っている場合、その文字は( _ )(アンダースコア)に置換されます。

Xcodeのメニュー"File > New > File > (iOS or OS X) > Source > Header File."からファイル名を[product module name]-Bridging-Header.hと指定しプロジェクトに追加します。

このBridging Header Fileに、SwiftからインポートしたいObj-Cヘッダーファイルを書きます。

// SwiftAndObj_C-Bridging-Header.h

#import "XYZCustomViewController.h"

f:id:nkmrh:20141202093827p:plain

Build Settings > Objective-C Bridging Headerに作成したファイルのパスを指定します。

f:id:nkmrh:20141202093936p:plain

これでBridging header fileに書かれたObj-Cヘッダーファイルが、全てのSwiftファイルから見えるようになりました。

次のようにSwiftからXYZCustomViewControllerのインスタンスが作成できます。

Swift

var controller = XYZCustomViewController()
self.view.addSubview(controller.view)

Obj-C -> Swift

今度は逆に、Obj-CからSwiftを使う方法です。

Obj-CからSwiftをつかうには、次のインポート文を書きます。

Obj-C

#import [ProductModuleName]-Swift.h

[ProductModuleName]-Swift.hファイルはXcodeから自動生成されるもので、開発者が用意する必要はありません。

これでObj-CからSwiftを使うことができます。

Obj-C

#import "SwiftAndObj_C-Swift.h"

// ViewControllerクラスがSwiftで書かれている場合

ViewController* controller = [ViewController new];
controller.view = [self configureView:controller.view];

型の違い

Obj-Cの変数をSwiftで使う場合、両者の型が違うのでコンバージョンやダウンキャストをします。

// CGFloatをFloat型に代入するには、コンバージョンしたい変数を括弧で囲みコンバージョンします。
myFloat = Float(controller.cgfloat)
// NSDictionaryをDictionaryに、NSArrayをArrayに代入するにはas演算子でダウンキャストします。
myDictionary = controller.nsdictionary as Dictionary<String , AnyObject>
myArray = controller.nsarray as Array<AnyObject>

デリゲートパターン

Obj-Cではデリゲートオブジェクトに対してメッセージ送信可能かrespondsToSelector:メソッドで確認後メッセージ送信していました。 Swiftではif-letシンタックスで次のようにスッキリと書けます。

Obj-C

if ([self.delegate respondsToSelector:@selector(delegateMethod:)]) {
  [self.delegate delegateMethod:arg];
}
Swift

if let value = delegate?.delegateMethod?(arg) {
  println(value)
}

?演算子でデリゲートがnilかどうか、メソッドが定義されているかどうかチェックしています。

キー値監視

NSObjectを継承して作成したSwiftクラスは、キー値監視が使えます。監視したいプロパティにdynamic修飾子を追記します。

Swift

class MyObjectToObserve: NSObject {
  // dynamic修飾子を追記します
  dynamic var myDate = NSDate()
  func updateDate() {
    myDate = NSDate()
  }
}

class MyObserver: NSObject {
  private var myContext = 0
  var objectToObserve = MyObjectToObserve()
  override init() {
    super.init()
    objectToObserve.addObserver(self, forKeyPath:"myDate", options: .New, context: &myContext)
  }

  override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject: AnyObject], context: UnsafeMutablePointer<Void>) {
    if context == &myContext {
      println("Date changed")
    }
    else {
      super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
    }
  }

  deinit {
    objectToObserve.removeObserver(self, forKeyPath: "myDate", context: &myContext)
  }
}

まとめ

Obj-CとSwiftを同時に使う方法と、両者の相違点について書きました。この記事は、Using Swift with Cocoa and Objective-Cから気になった箇所を紹介させていただきました。 iBooks Storeで無料でダウンロードできるので、もしまだという方は1度目を通してみると良いかと思います。