134
118

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Objective-C → Swift コンバータ3種を比較(Swiftify, iSwift, objc2swift)

Last updated at Posted at 2016-03-25

Swiftが発表されて以来早2年、なんだかんだと言い訳しつつその後も大量のObjective-Cコードを生産し続けてまいりました。そんなカルマを精算すべく、よく使いまわしているコードはSwift化 しておこう、と思うのですが、どうしても「既に動いているコードを書き直す」というのは、他の緊急性の高いタスクに割りこまれてしまいがち。。

そんなわけで、ObjC → Swiftに 自動変換 してくれるコンバートツールを試してみようと思い立った次第です。

##コンバータを探してみる

「確かヤフーさんが昨年コンバータをオープンソースで出してたなー」とググってみると、けっこう他にもいろいろとコンバータや変換方法が見つかりました。

###Swiftify

オンラインで、コードブロック/ファイル/プロジェクトの単位で変換 できます。

Pricing というタブがあるので見てみたところ、無料でできるのは、

  • コードブロック単位での変換
  • 1回のコードサイズが10kBまで

のようです。

swiftify_pricing.jpg

###iSwift

オンライン版、ダウンロード版(Macアプリ)の2種類があるようです。オンライン版は、コードブロック単位での変換のみ。

iswift_online.jpg

ダウンロード版は試用期間1日で、その後は有料($14.99)となるようです。

###objc2swift

昨年12月にヤフーさんが オープンソースで公開 したコンバータ。

手軽に試せるオンライン版もあります。

objc2swift.jpg

ソースコードを clone してきて gradle でビルドすれば、

$ git clone https://github.com/yahoojapan/objc2swift.git
$ cd objc2swift
$ gradle jar

こんな感じでコマンドラインからも変換できるようです。

$ objc2swift src/test/resources/sample.*

###Objective-C to Swift Converter

こちらも国産、デジタルサーカス @tomzoh さんによる変換ツール。

メソッドコール単位での変換に対応しているようです。

objc2swift.meのバックエンドは文字列処理ベースの地味~で泥臭いプログラムだし、前述のとおりメソッドコールにしか対応していないので、いつか上記プロジェクトをバックエンドにしたみたいです。

(上記記述を踏まえ、今回は試しませんでした)

###その他、コード変換に関する参考記事

##コンバートしてみる

今回Swiftへの自動変換対象として用いたコードは、以下のリポジトリにある TTMCaptureManager というクラス。

AVFoundation の動画の録画処理をラップしたクラスで、

self.captureManager = [[TTMCaptureManager alloc] initWithPreviewView:self.view];
[self.captureManager startRecording];

これだけで録画処理が書けて、フレームレートも簡単に変えられるようにしてあるので、たまーに引っ張り出してきて使ってます。

・・・が、2013年にプライベートでざっと書いたもので、なにぶん汚い。1ファイルで600行もある。リファクタリングしたいけど、どうせならSwiftで書きなおしてからSwiftyにリファクタリングしたい

そんなわけでこのクラスを各コンバータにかけてみました。

###Swiftify

使ってみて気付きましたが、サインアップ(無料)しないと1kBまでしかコンバート結果を表示してくれないようです。

で、サインアップして、変換してみた結果がこちら。

swiftify_result.jpg

一番上にこう書かれています。

swift
// The output below is limited by 10 KB.
// Upgrade your plan to remove this limitation.

変換結果の良し悪し以前に、無料プランでの上限10kBに引っかかってしまったのでした。長いコードこそ変換したいのに。。

変換の手間を考えると月15ドルは決して高いものではありませんが、無料で使える他のコンバータとの比較になるので、ここを実力とします。(正直なところ、変換されたコードを見ても、インデントが崩れてたりして、ちょっと不穏な感じが否めませんでした。。)

###iSwift

TTMCaptureManager.m を貼ると・・・エラー。

swift
/*
Unexpected :  <

Expected   :
'NULLABLE', 'NONNULL', const, volatile, 'NONNULL_', 'NULLABLE_', '+', '-', typedef, extern, static, auto, register, 'BLOCK___', 'WEAK___', void, char, short, int, long, float, double, Class, id, SEL, BOOL, signed, unsigned, #type, 'USER_TYPE_NAME', struct, union, '{', enum, 'NS_ENUM', 'NS_OPTIONS', @end, @property, 'COMMENT_MULTI', 'COMMENT_SINGLE'
*/

こういう無名カテゴリでのプロトコルへの適合がiSwift的にはダメみたいです。

TTMCaptureManager.m
@interface TTMCaptureManager () <AVCaptureFileOutputRecordingDelegate, AVCaptureAudioDataOutputSampleBufferDelegate, AVCaptureVideoDataOutputSampleBufferDelegate>

ではヘッダはどうだろう、と TTMCaptureManager.h を貼ってみると・・・エラー

swift
/*
Unexpected :  @

Expected   :
'NULLABLE', 'NONNULL', const, volatile, 'NONNULL_', 'NULLABLE_', '*', typedef, extern, static, auto, register, 'BLOCK___', 'WEAK___', void, char, short, int, long, float, double, Class, id, SEL, BOOL, signed, unsigned, #type, 'USER_TYPE_NAME', struct, union, #identifier, enum, 'NS_ENUM', '(', 'NS_OPTIONS', @implementation, @interface, @class, #ifdef, #ifndef, #ident, #include, #undef, #import, #define, #pragma, #if, 'ELIF__', #else, #endif, 'COMMENT_MULTI', 'COMMENT_SINGLE'
*/

@import がダメみたいです。

TTMCaptureManager.h
@import CoreMedia;

これならどうだ、とヘッダの @interface 部分だけ貼ってみたところ、

TTMCaptureManager.h
@interface TTMCaptureManager : NSObject

@property (nonatomic, assign) id<TTMCaptureManagerDelegate> delegate;
@property (nonatomic, readonly) BOOL isRecording;
@property (nonatomic, copy) void (^onBuffer)(CMSampleBufferRef sampleBuffer);

- (instancetype)initWithPreviewView:(UIView *)previewView
                preferredCameraType:(CameraType)cameraType
                         outputMode:(OutputMode)outputMode;
- (void)toggleContentsGravity;
- (void)resetFormat;
- (void)switchFormatWithDesiredFPS:(CGFloat)desiredFPS;
- (void)startRecording;
- (void)stopRecording;
- (void)updateOrientationWithPreviewView:(UIView *)previewView;

@end

やはりエラー・・・

swift
/*
Unexpected :  #identifier ('CMSampleBufferRef')

Expected   :
'NULLABLE', 'NONNULL', const, volatile, 'NONNULL_', 'NULLABLE_', typedef, extern, static, auto, register, 'BLOCK___', 'WEAK___', void, char, short, int, long, float, double, Class, id, SEL, BOOL, signed, unsigned, #type, 'USER_TYPE_NAME', struct, union, enum, 'NS_ENUM', ')', 'NS_OPTIONS'
*/

ちなみに試用期間1日のダウンロード版(Macアプリ)の方で試してみても、同様の結果でした。

###objc2swift

手っ取り早く変換結果を見れるweb版で試しました。

最初、TTMCaptureManager.m のコードを貼ってみたところ、コンバート結果が出ない。。

まさか、これもダメなのか・・・とあきらめかけたところ、

@interface MyClass

- (void)sayHello;

@end

@implementation MyClass

- (void)sayHello{
    NSLog(@"Hello Swift, Goodbye Obj-C!");
}

@end

デフォルトで入っているこのサンプルコードはちゃんと変換されている模様。

どうやら、ヘッダの内容 @interface と実装ファイルの内容 @implementation をセットで 渡さないといけないようです。

というわけでヘッダの内容をコピペしつつ、import とかの余計な部分を削除したところ、

ばっちりコンバートされました。生成されたコードをざっと見ても、private とかも判別されていて、なかなか良さげ。そのままビルド成功、というわけにはさすがにいきませんが、これだけやってくれればかなり捗りそうです。

##まとめ

3種類の Objective-C → Swift コンバータを試しました。

  • Swiftify: 無料プランでは10kB制限により1クラス全体を変換できず
  • iSwift: エラーでまったく変換されず
  • objc2swift: なかなか良さげ

というわけで、唯一まともに動いたのは objc2swift だけで、しかも完全無料でオープンソース。現状では ObjC → Swift コンバータは objc2swift 一択 という結果になってしまいました。

が、今回は1クラス試しただけだし、得意不得意とかもあるのかもしれません。今後もいろいろなソースコードで試してみたいと思います。

134
118
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
134
118

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?