はじめに
古くから存在するアプリでは、Objective-CとSwiftが共存していることがよくあります。はじめはObjective-Cで作られ、Swiftが発表された後はSwiftで作っている、というパターンですね。こういったアプリでは、Objective-Cで書かれたクラスをSwiftで継承する、という実装を行う場面が出てくると思います。そのときのメンバ変数の取り扱いで少し手間取ったので、備忘録として残します。
サンプルファイル
以下に、この記事で扱うファイルを記載します。
継承元のObjective-Cファイル
継承元のクラスが書かれたファイルは以下であるとします。
#import <UIKit/UIKit.h>
@protocol SampleDelegate
- (void) delegateMethod;
@end
@interface SampleParentViewController: UIViewController {
id<SampleDelegate> sampleDelegate;
}
- (instancetype)initWithDelegate:(id<SampleDelegate>)delegate;
@end
#import "SampleParentViewController.h"
@implementation SampleParentViewController
- (instancetype)initWithDelegate:(id<SampleDelegate>)delegate
{
self = [super init];
if (self) {
sampleDelegate = delegate;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
[sampleDelegate delegateMethod];
}
@end
継承先のSwiftファイル
以下のように、継承するクラスをSwiftで書いたとします。
import UIKit
class SampleChildViewController: SampleParentViewController {
let otherViewController: SampleDelegate = OtherViewController()
override func viewDidLoad() {
self.sampleDelegate = otherViewController
super.viewDidLoad()
}
}
しかし、このSwiftファイルをつくるとコンパイルエラーになります。以下で、このファイルの実装するための変更手順を示していきます。
変更手順
段階を追って、意図通りに動くための手順を示していきます。
プロパティを追加
まずこのsampleDelegateはメンバ変数として定義されているため、クラスの外から参照することはできません。参照できるようにするには、メンバ変数ではなくプロパティに変更する必要があります。そのために、まずはヘッダファイルにプロパティの宣言を追加します。
#import <UIKit/UIKit.h>
@protocol SampleDelegate
- (void) delegateMethod;
@end
@interface SampleParentViewController: UIViewController {
id<SampleDelegate> sampleDelegate;
}
@property id<SampleDelegate> sampleDelegate;
- (instancetype)initWithDelegate:(id<SampleDelegate>)delegate;
@end
一応、これだけでコンパイルエラーは解消します。しかし、実行してみるとotherViewControllerのdelegateMethodは実行されず、sampleDelegateは書き換えられていないことがわかります。これはヘッダファイルで新しくプロパティを宣言し変数を追加しましたが、もともとのsampleDelegateには何の変更も加わっていないためです。
Objective-Cのプロパティ
Objective-Cでは、ヘッダファイルでプロパティを宣言すると、メソッドファイルでは頭に_がついて扱われます。そのため現時点では、もともと存在していたsampleDelegateと新しく追加した_sampleDelegateが存在していることになっています。今回はsampleDelegateをプロパティに置き換えるのが目的なので、メソッドファイルに書かれているsampleDelegateを_sampleDelegateに書き換えていきます。
#import "SampleParentViewController.h"
@implementation SampleParentViewController
- (instancetype)initWithDelegate:(id<SampleDelegate>)delegate
{
self = [super init];
if (self) {
_sampleDelegate = delegate;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
[_sampleDelegate delegateMethod];
}
@end
これで、sampleDelegateが完全にプロパティに置き換わりました。したがって継承先のファイルからsampleDelegateが扱えるようになっています。一応、使わなくなったメンバ変数のsampleDelegateの宣言を消しておきましょう。
#import <UIKit/UIKit.h>
@protocol SampleDelegate
- (void) delegateMethod;
@end
@interface SampleParentViewController: UIViewController
@property id<SampleDelegate> sampleDelegate;
- (instancetype)initWithDelegate:(id<SampleDelegate>)delegate;
@end
まとめ
メンバ変数が定義されているObjective-CファイルをSwiftファイルで継承してその変数を扱うために、プロパティで宣言し直してメソッドファイルを書き換える手順を記載しました。Objective-Cはハマると解決に時間がかかる仕様が多いと思います。そんな人の助けになれると幸いです。