Developer's Blog

Apple の新言語 Swift

Fenrir Advent Calendar 2014

こんにちは! iOS アプリエンジニアの八田です。Fenrir Advent Calendar 2014 の 3 日目を担当します。

私の「2014年にグッときたコレ」は Apple の新言語、Swift です。iOS アプリエンジニアの皆さん、Swift 使ってますか?

Swift について簡単に紹介しますと、iOS や Mac OS X のアプリケーションを開発するための新しいプログラミング言語で、2014年6月に開催された WWDC で発表され、9月にバージョン 1.0 が正式にリリースされました。まだ生まれたばかりの新しい言語なのでリリース後にも手が加えられていて、12月3日現在のバージョンは 1.1 となっています。

Swift は、Xcode 6 以降、iOS 7 以降、Mac OS X 10.9 以降で利用できます。

※今回の記事は、Xcode 6.1 (2014年12月3日時点での最新版) で検証した結果です。将来のバージョンアップで動作が異なる可能性がありますので、あらかじめご了承ください。

クラスの記述がスッキリ

まずは、同じクラスを Objective-C と Swift のそれぞれで記述した時の違いを見てみましょう。

// MyObjcClass.h
#import <Foundation/Foundation.h>

@interface MyObjcClass : NSObject
- (void)hello;
@end
// MyObjcClass.m
#import "MyObjcClass.h"

@implementation MyObjcClass
- (void)printHello {
    NSLog(@"Hello Objective-C!");
}
@end

同じ機能のクラスをSwiftで書くとこのようになります。

// MySwiftClass.swift
import Foundation

class MySwiftClass: NSObject {
    func printHello() {
        println("Hello Swift!")
    }
}

Swift では、定義と実装を分けなくなったので、ファイルが1つになり、記述するコード量がスッキリしています。

ライブラリは Cocoa / Cocoa Touch

言語は新しくなりましたが、iOS アプリを開発するためのライブラリは使い慣れた Cocoa Touch です。

メモリ管理方法も変わらず自動参照カウント (ARC) なので、これまで Objective-C でアプリ開発の経験があれば、Swift への敷居は非常に低いのではないでしょうか。

モダンな言語

Swift ではジェネリックス、型推論、Optional などのモダンな機能が使えるようになりました。== 演算子で文字列比較ができたり、+ 演算子で文字列連結ができるようになったのも良いところですね!

個人的にグッときたのはジェネリックスの導入です。実は、WWDC 2014 で Objective-C にジェネリックスの追加が発表されるのではないかと期待していたのですが、発表されたのはまさかの新言語。ジェネリックスは Swift で提供されることとなりました。

パフォーマンス

WWDC 2014 では Swift のパフォーマンスの良さもアピールされていました。

パフォーマンス比較を行っているブログ記事を見つけましたので紹介します。こちら (Apples to apples, Part II) の記事では、Swift と Objective-C でソートアルゴリズムを実装し、速度を比較しています。

詳細はリンク先を参照していただきたいのですが、コンパイルオプションで最適化を有効にすると Swift の方が高速に動くようです。逆に、最適化をしない場合は Objective-C の方が高速という結果も出ています。

Swift と Objective-C の相互利用

この半年間、とあるプロダクトを Objective-C から Swift へ移行していたのですが、そのときに調べたことを紹介しようと思います。

Swift と Objective-C は相互利用ができるようになっていて、これまで Objective-C で書きためた便利クラスやライブラリを Swift でも活用することができます。

Swift から Objective-C を呼び出す手順

Bridging Header を設定する

BridgingHeaderAlert

Swift プロジェクトに初めて Objective-C のコードを追加するときにこのようなダイアログが表示されるので、Yes をクリックすると Bridging Header が自動で追加されます。Bridging Header は、Objective-C から Swift への橋渡しをするためのヘッダファイルで、このファイルで Objective-C のヘッダファイルを import することで Swift から利用可能になります。デフォルトのファイル名は「<#ProjectName#>-Bridging-Header.h」です。

この設定を手動で行う場合は、プロジェクトに任意の名前のヘッダファイルを追加し、[Build Settings] -> [Swift Compiler – Code Generation] -> [Objective-C Bridging Header] にヘッダファイルのパスを記入します。

BuildSettings

Bridging Header に Objective-C のヘッダファイルを記述する

// SampleSwiftProject-Bridging-Header.h
#import "MyObjcClass.h"

SwiftのコードからObjective-Cのクラスを呼び出す

// AnyClass.swift
let objcObj = MyObjcClass()
objcObj.printHello()

Objective-C から Swift を呼び出す手順

Bridging Header を設定する

先ほどと同様に、Bridging Header を追加します。

Objective-C のコードで「<#ProjectName#>-Swift.h」を import する

Xcode 6 では、「<#ProjectName#>-Swift.h」という名前のヘッダファイルが自動で生成されるようになっています。このファイルには Swift で書かれたクラスなどが自動で定義され、Objective-C のコードで import することで Swift のクラスを利用できるようになります。

// AnyClass.m
#import "SampleObjcProject-Swift.h"

Swift のクラスを呼び出す

// AnyClass.m
MySwiftClass *swiftObj = [MySwiftClass new];
[swiftObj printHello];

試してみたところ、Bridging Header が設定されていなくても「<#ProjectName#>-Swift.h」は作られますが、Bridging Header が設定されていないと Swift のクラスが「<#ProjectName#>-Swift.h」に自動で定義されませんでした。Swift から Objective-C のクラス等を使用する予定がなくても、Bridging Header を作成し、Build Settings に設定しておく必要があるようです。

Swift で追加、拡張された機能は Objective-C では使えない

考えてみれば当然ですが、Swift にしかない機能は Objective-C へ持ち込むことはできません。Objective-C と Swift は相互に呼び出すことができますが、完全な互換ではないので相互利用するプロジェクトでは注意が必要です。

もし、混在させるのであれば、持ち込めない機能をきちんと理解しておくことをお勧めします。Swift で enum を含むライブラリを書いてしまって Objective-C で Swift の enum が使えないなど、トラブルのもととなりますので・・・。

Apple のドキュメントによると、Objective-C で利用できない Swift の機能として、以下が挙げられていました。

  • Generics
  • Tuples
  • Enumerations defined in Swift
  • Structures defined in Swift
  • Top-level functions defined in Swift
  • Global variables defined in Swift
  • Typealiases defined in Swift
  • Swift-style variadics
  • Nested types
  • Curried functions

例えば、以下のようなコードを Objective-C で使うときに、Swift で定義した列挙型 (enum) は Objective-C で使用できませんし、enum を引数にとるメソッドも使用できません。

// MySwiftClass.swift
import Foundation

class MySwiftClass: NSObject {
    func printRedString() {
        println("color code is \(MyColor.Red.toRGBString())")
    }
    func printColor(color: MyColor) {
        println("color code is \(color.toRGBString())")
    }
}

enum MyColor: Int {
    case Red
    case Green
    case Blue

    func toRGBString() -> String {
        switch self {
        case .Red:
            return "#FF0000"
        case .Green:
            return "#00FF00"
        case .Blue:
            return "#0000FF"
        }
    }
}

MethodCall
Objective-C 側では、Swift の enum を引数にとるメソッドは表示されません。

相互利用は、あくまでも既存の資産を活用する用途に止めておいたほうが無難な印象でした。

いかがでしたでしょうか。このほかにも、Swift について学ぶには Apple の公式ドキュメントが役に立ちます。これから Swift を始める方、まだ読んだことのない方はぜひ一読しておくことをオススメします!便利な機能があるのに知らないままでいるのは勿体無いですしね ;)

フェンリルのオフィシャル Twitter アカウントでは、フェンリルプロダクトの最新情報などをつぶやいています。よろしければフォローしてください!

 

Copyright © 2019 Fenrir Inc. All rights reserved.